XSL Walkthrough

This section discusses the process flow through the XSL when the PeopleSoft SCM purchase order message is transformed.

XSL is composed of templates. An XSLT template is an instruction of what to do when a particular XML node or condition is encountered. During a transform, the XSL processing engine starts at the root element of the XML message and then attempts to find matching templates in the XSL. When a matching template is found, the instructions in that template are used in the building of the output XML document.

The processing of a transform is actually a two pass process. In the first pass, the XSL is executed against the input XML, and an output XML document is generated. In the second pass, the psft_function calls are resolved and the codeset values are placed into the document.

This section discusses the first pass of transform processing, during which the XSL code runs against the input XML and the system generates an output XML document. The steps listed below mimic the actions taken by the transformation engine in processing the input XML.

  1. The first element in the input message is PURCHASEORDERMESSAGE. The transformation engine finds the following matching template in the XSL:

      <xsl:template match="PURCHASEORDERMSG">
        <PO_MSG>
          <xsl:apply-templates select="FieldTypes"/>
          <xsl:apply-templates select="MsgData"/>
        </PO_MSG>
      </xsl:template>

    Here we see the root element of the output document being created. This template instructs the transformation engine to:

    • Output the start tag for PO_MSG.

      It is important to note that template processing is a recursive process. In the sequence above, the transformation engine outputs the start tag, then applies templates to all FieldType nodes. This is essentially a callout to the template that handles those nodes (and potentially any children). The output of this call is then placed into the output document. Then the transformation engine selects all the MsgData nodes, and applies templates to them. Again, the output from the processing of those nodes is then place into the output document. Finally, the closing PO_MSG tag is written into the output, and the first pass is finished. Of course, documenting a recursive process is not always straightforward. In this example bear in mind that while it is presented as a numbered sequence of steps, the actual process is not sequential.

    • Select the FieldTypes nodes under the current node in the input document, and process them.

    • Select the MsgData nodes under the current node in the input document, and process them.

    • Output the end tag for PO_MSG.

  2. The transform engine selects the FieldTypes node, and finds the following template:

      <xsl:template match="FieldTypes">
      <FieldTypes>
        <PO_HEADER class="R">
          <PO_NUMBER type="CHAR"/>
          <PO_DATE type="DATE"/>
        </PO_HEADER>
        <PO_ITEM class="R">
          <SKU type="CHAR"/>
          <CUSTNAME type="CHAR"/>
          <SHIPPER type="CHAR"/>
          <DESTADD type="CHAR"/>
          <DESTCITY type="CHAR"/>
          <DESTSTATE type="CHAR"/>
        </PO_ITEM>
        <PSCAMA class="R">
          <LANGUAGE_CD type="CHAR"/>
          <AUDIT_ACTN type="CHAR"/>
          <BASE_LANGUAGE_CD type="CHAR"/>
          <MSG_SEQ_FLG type="CHAR"/>
          <PROCESS_INSTANCE type="NUMBER"/>
          <PUBLISH_RULE_ID type="CHAR"/>
          <MSGNODENAME type="CHAR"/>
        </PSCAMA>
      </FieldTypes>
      </xsl:template>

    The interesting thing about this template is that it is basically an instruction to insert static text into the output document. Of course, this makes sense, as the FieldTypes section is dependant upon the message structure, and not the actual data contained within any particular message instance. Also note that there is no further node selection in this template, so after the XML is emitted this particular path through the XML ends.

  3. Now that the FieldTypes nodes have been processed, the transform engine processes the MsgData node using the following matching template:

      <xsl:template match="MsgData">
        <MsgData>
          <xsl:apply-templates select="Transaction"/>
        </MsgData>
      </xsl:template>

    The template is quite simple. The transformation engine is to put a starting MsgData node in the output document, and then process the Transaction nodes in the input document. Note that the node context has changed: the current node in the input document being processed is the MsgData node. The call to select then implies that all child Transaction nodes under the MsgData are to be selected.

  4. The Transaction nodes under MsgData are matched by the following template:

      <xsl:template match="Transaction">
        <Transaction>
          <xsl:apply-templates select="PURCHASEORDER"/>
          <PSCAMA class="R">
            <LANGUAGE_CD>ENG</LANGUAGE_CD>
            <AUDIT_ACTN/>
            <BASE_LANGUAGE_CD>ENG</BASE_LANGUAGE_CD>
            <MSG_SEQ_FLG/>
            <PROCESS_INSTANCE>0</PROCESS_INSTANCE>
            <PUBLISH_RULE_ID/>
            <MSGNODENAME/>
          </PSCAMA>
        </Transaction>
      </xsl:template>

    A Transaction start tag is written to the output document, and then the PURCHASEORDER nodes are to be handled. Once these nodes have been processed, the PSCAMA information will be written out, along with the closing Transaction tag.

  5. The call to handle the PURCHASEORDER node invokes:

      <xsl:template match="PURCHASEORDER">
        <PO_HEADER class="R">
          <PO_NUMBER IsChanged="Y">
             <xsl:value-of select="PURCHASEORDERNUM"/>
          </PO_NUMBER>
          <PO_DATE IsChanged="Y">
             <xsl:value-of select="PURCHASEORDERDATE"/>
          </PO_DATE>
          <xsl:apply-templates select="PURCHASEDITEMS"/>
        </PO_HEADER>
      </xsl:template>

    The PO_HEADER start tag is emitted as well as the child PO_NUMBER and PO_DATE elements. The call out to xs:value-of means that node values from the input message are copied to the output message. In this case, the node PO_NUMBER in the output message is given the value from PURCHASEORDERNUM in the input message. PO_DATE is given the value from PURCHASEORDERDATE. Once these two elements have been written out, the transformation engine is then told to process the PURCHASEDITEMS nodes in the input document.

  6. Each PURCHASEDITEMS node in the input message causes the following template to be executed:

      <xsl:template match="PURCHASEDITEMS">
        <PO_ITEM class="R">
          <SKU IsChanged="Y"><xsl:value-of select="ITEM"/></SKU>
          <CUSTNAME IsChanged="Y">
             <xsl:value-of select="../SHIPPINGDETAILS/NAME"/>
          </CUSTNAME>
          <SHIPPER IsChanged="Y">
             <psft_function name="codeset" codesetname="SCM_CODESET">
                <parm name="CARRIER_ID">
                  <xsl:value-of select="../SHIPPINGDETAILS/CARRIER_ID"/>
                </parm>
                <value name="SHIPPER" select="."/>
             </psft_function>
           </SHIPPER>
          <DESTADD IsChanged="Y">
             <xsl:value-of select="../SHIPPINGDETAILS/ADDRESS"/>
          </DESTADD>
          <DESTCITY IsChanged="Y">
             <xsl:value-of select="../SHIPPINGDETAILS/CITY"/>
          </DESTCITY>
          <DESTSTATE IsChanged="Y">
             <xsl:value-of select="../SHIPPINGDETAILS/STATE"/>
           </DESTSTATE>
        </PO_ITEM>
      </xsl:template>

    This is where the bulk of the building of the output message is performed. For each PURCHASEDITEMS node in the input document, this template will be run once. The template is responsible for building out the PO_ITEM element and children in the output message. As in the template for PURCHASEORDER, this template uses the values from the input message and copies them across to the output message. For example, the SKU element in the output is given the value from the ITEM node in the input. Also note that the SHIPPER node contains a reference to psft-function and the SCM_CODESET. At this stage in the transformation, this text is static except for the value-of call to “../SHIPPINGDETAILS/CARRIER_ID”, which will be resolved to “USPS”. The actual codeset lookup will not be done at this point; this will occur in the second pass.

  7. After the PURCHASEDITEMS template completes, the transformation jumps back to step 5, and outputs the closing PO_HEADER template.

  8. Once the PURCHASEORDER template in step 5 completes, the transformation jumps back to step 4, and the Transaction template is completed. At this point the PSCAMA section in the template is written to the output message.

  9. After the Transaction template in step 4 completes, the transformation jumps back to step 3, and the MsgData template. At this point the closing MsgData tag is written to the output message.

  10. After the MsgData template in step 3 completes, the transformation jumps back to step 1. At this point the closing PO_MSG tag is written out, and the first part of the transformation process ends.

This section discusses the second pass of transform processing, during which the psft_function calls are resolved and the codeset values are placed into the document.

Assuming that no errors were encountered in the processing in the first pass a complete XML document will be available, containing the formatted PeopleSoft CRM purchase order message. However, this XML will still contain the reference:

      <SHIPPER IsChanged="Y">
         <psft_function name="codeset" codesetname="SCM_CODESET">
            <parm name="CARRIER_ID">USPS</parm>
            <value name="SHIPPER" select="."/>
         </psft_function>
      </SHIPPER>

The second pass walks through the message and resolves all calls to psft_function. In this instance the codeset lookup will be run, and the psft_function node will be replaced with the result. The XML in the output message will then look like:

      <SHIPPER IsChanged="Y">
         United States Postal Service
      </SHIPPER>

After the second pass completes, the transform is complete.