0

Relatively new to XSLT.

Here's a sample XML:

<Shipments>
                <Shipment>
                 <ErpOrder>415580479</ErpOrder>
                    <Containers>
                        <ShippingContainer>
                            <TreeUnit>12211620</TreeUnit>
                            <WeightUm>L</WeightUm>
                        </ShippingContainer>
                    </Containers>
                </Shipment>
                <Shipment>
                    <ErpOrder>415580479</ErpOrder>
                </Shipment>
                 <Shipment>
                    <ErpOrder>5124516</ErpOrder>
                </Shipment>
</Shipments>

I want to copy the <Containers> node and all child tag within that node to any <Shipment> tag that matches the <ErpOrder> value and is missing the <Containers> node.

Output:

<Shipments>
            <Shipment>
             <ErpOrder>415580479</ErpOrder>
                <Containers>
                    <ShippingContainer>
                        <TreeUnit>12211620</TreeUnit>
                        <WeightUm>L</WeightUm>
                    </ShippingContainer>
                </Containers>
            </Shipment>
            <Shipment>
                <ErpOrder>415580479</ErpOrder>
                 <Containers>
                    <ShippingContainer>
                        <TreeUnit>12211620</TreeUnit>
                        <WeightUm>L</WeightUm>
                    </ShippingContainer>
                </Containers>
            </Shipment>
             <Shipment>
                <ErpOrder>5124516</ErpOrder>
            </Shipment>
</Shipments>

What I have so far, but I think is completely off [EDITED]:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="no" indent="yes" method="xml"/>

 <xsl:key name = "erpordermatch" match = "Shipment" use = "@ErpOrder"/>

 <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
  </xsl:template>

<xsl:template match="Shipment[not(Containers)]">
     <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
      <xsl:for-each select="key('erpordermatch', @ErpOrder)">
            <xsl:if test="@ErpOrder = ErpOrder">
                <xsl:copy-of select="Containers"/>
            </xsl:if>
        </xsl:for-each>
 </xsl:copy>                
            
    </xsl:template>
</xsl:stylesheet>

michael.hor257k
  • 113,275
  • 6
  • 33
  • 51
  • Yes, it it completely off. It looks you just scrambled some random code together. – michael.hor257k Jul 23 '20 at 14:58
  • Can you help point me in the right direction? I've tried using xsl: template match with a copy -of, but I'm not sure how to define the criteria where ErpOrder matches between the two parent Shipment tags. – Shuaipeng Zhang Jul 23 '20 at 15:00
  • I suggest you use a [key](https://www.w3.org/TR/1999/REC-xslt-19991116/#key) to link to a `Shipment` by its `ErpOrder`. Then define a template matching `Shipment[not(Containers)]` and have it copy its content AND the `Containers` from the key. – michael.hor257k Jul 23 '20 at 15:04
  • Okay, I did some research and edited my XSL stylesheet per your suggestions. I'm still not able to get this to function properly...Thanks for your help, I just picked up XSL a couple days ago, trying to learn all this on my own. – Shuaipeng Zhang Jul 23 '20 at 15:44
  • I have rolled your question back to what it was when I answered it. Otherwise it would not be useful to anyone else reading it. – michael.hor257k Jul 23 '20 at 18:04

1 Answers1

0

See if this works for you:

XSLT 1.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:strip-space elements="*"/>

<xsl:key name="ship-by-erp" match="Shipment" use="ErpOrder" />

<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="Shipment[not(Containers)]">
    <xsl:copy>
        <xsl:apply-templates/> 
        <xsl:copy-of select="key('ship-by-erp', ErpOrder)/Containers"/>
    </xsl:copy>
</xsl:template>
  
</xsl:stylesheet>

Note that this results in the first Shipment being duplicated in the output (as shown also in your expected output). Are you sure you want this?

michael.hor257k
  • 113,275
  • 6
  • 33
  • 51
  • It worked! Thank you so much! However, when I add in the following parent tags, it doesn't seem to work. I've edited my sample XML to reflect this. Is this due to the fact that Shipments is no longer the root tag? – Shuaipeng Zhang Jul 23 '20 at 17:44
  • See if this helps: https://stackoverflow.com/a/34762628/3016153 – michael.hor257k Jul 23 '20 at 17:48