Search code examples
xsltxslt-1.0xslt-2.0

XSLT copy child node value to parent based on condition in parent and child


if Orderitem->name is 'Desktop' then copy the price from the value in listofspareparts where name is 'spare2' in spareparts1.

Input:

<listoforders>
    <Orderitem>
        <name>Desktop</name>
        <place>NZ</place>
        <price>120</price>
        <listofspareparts>
            <spareparts1>
                <name>spare1</name>
                <value>140</value>
            </spareparts1>
            <spareparts1>
                <name>spare2</name>
                <value>130</value>
            </spareparts1>            
        </listofspareparts>
    </orderitem>
</listoforders>

Output should be:

<listoforders>
    <Orderitem>
        <name>Desktop</name>
        <place>NZ</place>
        <price>130</price>
        <listofspareparts>
            <spareparts1>
                <name>spare1</name>
                <value>140</value>
            </spareparts1>
            <spareparts1>
                <name>spare2</name>
                <value>130</value>
            </spareparts1>                
        </listofspareparts>
    </orderitem>
</listoforders>

XSLT-1.0:

<xsl:stylesheet version="1.0" xmlns:xsl="w3.org/1999/XSL/Transform"> 
    <xsl:output omit-xml-declaration="yes" indent="yes"/>    
    <xsl:strip-space elements=""/>

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

        </xsl:copy>
    </xsl:template>

    <xsl:template match="price[../Orderitem[name='Desktop']"> 
        <xsl:copy-of select="value[../../listofspareparts/spareparts1[name='spare‌​2']]" />
    </xsl:template>

</xsl:stylesheet>

Please let me know what I am missing here.


Solution

  • First of all, your XML is not well-formed because there is an inconsistency <Orderitem> vs. </orderitem>. So I chose to name this element <Orderitem>.

    Your XPaths were pretty close and just needed a little fine-tuning. Just look at the differences. You need to always take into account the current node from where things develop relative to - which is called an axis.

    An axis defines a node-set relative to the current node.

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
        <xsl:output omit-xml-declaration="yes" indent="yes"/>    
        <xsl:strip-space elements="*"/>
    
      <xsl:template match="node()">
        <xsl:copy>
          <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="price[../name='Desktop']"> 
        <price>
          <xsl:value-of select="../listofspareparts/spareparts1[name='spare2']/value" />
        </price>
      </xsl:template>
    
    </xsl:stylesheet>
    

    Output is as desired.