Search code examples
xsltxslt-2.0string-comparison

How to compare one element in an array with all the other elements in another array? And repeating it for n elements in the first array? Using XSLT


In the below XML I need to compare the OrderShipmentItemss LineItemNbr value (Example: 000010) with all the OrderItems/ScheduleLineItems's LineItemNbr (000010, 000020, 000030, 000040) in the first iteration.

Repeat this comparison for all the OrderShipmentItem LineItemNbr's (000010,000020). According to given xml it should be 2 times.

If they are equal map the DelivereQty value to the Quantity attribute of order element and customerNbr to the customercontact attribute of order element.

<Orders>
  <OrderEvent>
    <SAPOrderLineNbrs>
      <LineItemNbr>000010</LineItemNbr>
      <LineItemNbr>000020</LineItemNbr>
    </SAPOrderLineNbrs>
  </OrderEvent>
  <OrderHeader>
    <OrderItems>
      <LineItemNbr>000010</LineItemNbr>
      <ScheduleLineItems>
        <LineItemNbr>000010</LineItemNbr>
        <CustomerNbr>22222222</CustomerNbr>
      </ScheduleLineItems>
    </OrderItems>
    <OrderItems>
      <LineItemNbr>000020</LineItemNbr>
      <ScheduleLineItems>
        <LineItemNbr>000020</LineItemNbr>
        <CustomerNbr>11111111</CustomerNbr>
      </ScheduleLineItems>
    </OrderItems>
    <OrderItems>
      <LineItemNbr>000030</LineItemNbr>
      <ScheduleLineItems>
        <LineItemNbr>000030</LineItemNbr>
        <CustomerNbr>33333333</CustomerNbr>
      </ScheduleLineItems>
    </OrderItems>
    <OrderItems>
      <LineItemNbr>000040</LineItemNbr>
      <ScheduleLineItems>
        <LineItemNbr>000040</LineItemNbr>
        <CustomerNbr />
      </ScheduleLineItems>
    </OrderItems>
    <OrderShipment>
      <OrderShipmentItems>
        <LineItemNbr>000010</LineItemNbr>
        <OrderShipmentScheduleItems>
          <DeliveredQty>1.000</DeliveredQty>
        </OrderShipmentScheduleItems>
      </OrderShipmentItems>
      <OrderShipmentItems>
        <DeliveredQty>2.000</DeliveredQty>
        <LineItemNbr>000020</LineItemNbr>
        <OrderShipmentScheduleItems>
          <DeliveredQty>2.000</DeliveredQty>
        </OrderShipmentScheduleItems>
      </OrderShipmentItems>
    </OrderShipment>
  </OrderHeader>
</Orders>

My Output should contain same number of orders as LineItemNbr (In the above it is 2) and we need to check OrderShipmentItems's LineItemNbr value (Example: 000010) with all the OrderItems/ScheduleLineItems's LineItemNbr (000010, 000020, 000030, 000040) for every lineItemNbr.

If they are equal then we need to map DeliveredQty value as Quantity and CustomerNbr as CustomerContact.

Output should be:

 <Orders> 
    <Order Quantity="1.000" CustomerContact="222222222"/>
    <Order Quantity="2.000" CustomerContact="111111111"/>
  <Orders>

Please help me

What I have tried is the below xslt but it is comparing only first list element value.

    <xsl:for-each select="/*/OrderHeader/OrderShipment/OrderShipmentItems">
<order>
      <xsl:for-each select="/*/OrderHeader/OrderItems/ScheduleLineItems">
        <xsl:if test="/*/OrderHeader/OrderShipment/OrderShipmentItems/LineItemNbr = /*/OrderHeader/OrderItems/ScheduleLineItems/LineItemNbr">
          <xsl:attribute name="Quantity">
            <xsl:value-of select="/*/OrderHeader/OrderShipment/OrderShipmentItems/OrderShipmentScheduleItems/DeliveredQty" />
          </xsl:attribute>
          <xsl:attribute name="CustomerContact">
            <xsl:value-of select="/*/OrderHeader/OrderItems/ScheduleLineItems/CustomerNbr" />
          </xsl:attribute>
        </xsl:if>
      </xsl:for-each>
</order>
    </xsl:for-each>

Solution

  • Your question would be a lot clearer if you showed the expected output. See if this simplified example can help:

    XSLT 1.0/2.0

    <xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    
    <xsl:key name="shipment" match="OrderShipmentItems" use="LineItemNbr" />
    
    <xsl:template match="/Orders">
        <result>
            <xsl:for-each select="OrderHeader/OrderItems/ScheduleLineItems">
                <item>
                    <xsl:copy-of select="LineItemNbr | CustomerNbr"/>
                    <xsl:copy-of select="key('shipment', LineItemNbr)/OrderShipmentScheduleItems/DeliveredQty"/>
                </item> 
            </xsl:for-each>     
        </result>   
    </xsl:template>
    
    </xsl:stylesheet>
    

    Applied to your input XML example, this will produce:

    Result

    <?xml version="1.0" encoding="UTF-8"?>
    <result>
      <item>
        <LineItemNbr>000010</LineItemNbr>
        <CustomerNbr>22222222</CustomerNbr>
        <DeliveredQty>1.000</DeliveredQty>
      </item>
      <item>
        <LineItemNbr>000020</LineItemNbr>
        <CustomerNbr>11111111</CustomerNbr>
        <DeliveredQty>2.000</DeliveredQty>
      </item>
      <item>
        <LineItemNbr>000030</LineItemNbr>
        <CustomerNbr>33333333</CustomerNbr>
      </item>
      <item>
        <LineItemNbr>000040</LineItemNbr>
        <CustomerNbr/>
      </item>
    </result>
    

    -- added --

    Applying the same principle in the opposite direction is rather trivial:

    XSLT 1.0/2.0

    <xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    
    <xsl:key name="order-item" match="OrderItems" use="LineItemNbr" />
    
    <xsl:template match="/Orders">
        <Orders>
            <xsl:for-each select="OrderHeader/OrderShipment/OrderShipmentItems">
                <Order Quantity="{OrderShipmentScheduleItems/DeliveredQty}" CustomerContact="{key('order-item', LineItemNbr)/ScheduleLineItems/CustomerNbr}"/>
            </xsl:for-each>     
        </Orders>   
    </xsl:template>
    
    </xsl:stylesheet>
    

    Result

    <?xml version="1.0" encoding="UTF-8"?>
    <Orders>
      <Order Quantity="1.000" CustomerContact="22222222"/>
      <Order Quantity="2.000" CustomerContact="11111111"/>
    </Orders>