Search code examples
xslt

Replace existing element with another from an external XML


I would like to replace an element from an external XML file. Currently I have an XSLT which adds elements, but not replacing them.

Input.xml:

<all>
   <item>
      <sku>3850950</sku>
      <name>Macbook Pro</name>
      <qty>3</qty>
      <img>original.jpg</img>
   </item>
   <item>
      <sku>3859955</sku>
      <name>iPhone 12</name>
      <qty>9</qty>
      <img>original-apple.jpg</img>
   </item>
</all> 

XSLT:

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

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

<xsl:key name="group" match="additem" use="sku" />

<xsl:template match="item">
    <xsl:copy>
        <xsl:copy-of select="*"/>
        <xsl:apply-templates select="key('group', sku, document('./extra-info.xml'))"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="additem">
     <xsl:for-each select="img">
        <img>
        <xsl:value-of select="."/>
        </img>
     </xsl:for-each>   
</xsl:template>

</xsl:stylesheet>

Extra-info.xml:

<all>
   <additem>
      <sku>3850950</sku>
      <img>aaaaaaa</img>
      <img>bbbbbbb</img>
   </additem>
   <additem>
      <sku>3859955</sku>
   </additem>
</all>

I would like to match img elements from extra-info.xml, the common key is sku. Replace <img> in the input.xml if same exists in extra-info.xml and add all of them.

Example output:

<all>
   <item>
      <sku>3850950</sku>
      <name>Macbook Pro</name>
      <qty>3</qty>
      <img>aaaaaaa</img>
      <img>bbbbbbb</img>
   </item>
   <item>
      <sku>3859955</sku>
      <name>iPhone 12</name>
      <qty>9</qty>
      <img>original-apple.jpg</img>
   </item>
</all> 

Solution

  • AFAICT, you want to do:

    XSLT 2.0

    <xsl:stylesheet version="2.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="additem" match="additem" use="sku" />
    
    <!-- identity transform -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="item">
        <xsl:variable name="additem" select="key('additem', sku, document('extra-info.xml'))"/>
        <xsl:copy>
            <xsl:copy-of select="* except img"/>
            <xsl:choose>
                <xsl:when test="$additem/img">
                    <xsl:copy-of select="$additem/img"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:copy-of select="img"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:copy>
    </xsl:template>
    
    </xsl:stylesheet>