Home > Enterprise >  How to copy attributes?
How to copy attributes?

Time:03-29

Input xml file:

<root>
    <x1 attr11="sd5">
        <x2 attr12="sd6" attr15="sd7">
            <a />
            <b>
                <x3 attr18="sd8">
                    <c>
                        <x4 attr19="sd9"/>
                        <d />
                        <e />
                    </c>
                </x3>
            </b>
        </x2>
    </x1>
</root>

The "updates.xml" file from which updates are taken - tag attributes:

<updates>
    <a attr1="adf" attr2="67" />
    <b attr3="g6h"/>    
    <c attr4="7jj" />   
    <d attr5="88" attr6="mn4" />    
    <e />
</updates>

If the input file contains a tag (without attributes) from the "updates.xml" file, then the attributes from the "updates.xml" file are copied into it. The file after XSLT1.0 transformation should look like this:

<root>
    <x1 attr11="sd5">
        <x2 attr12="sd6" attr15="sd7">
            <a attr1="adf" attr2="67" />
            <b attr3="g6h">
                <x3 attr18="sd8">
                    <c attr4="7jj">
                        <x4 attr19="sd9"/>
                        <d attr5="88" attr6="mn4" />
                        <e />
                    </c>
                </x3>
            </b>
        </x2>
    </x1>
</root>

Now this is the XSLT1.0 transformation file:

<?xml version="1.0" encoding="utf-8"?>

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

  <xsl:param name="updates" select="document('updates.xml')"/>
  <xsl:key name="replacement" match="//*" use="local-name()"/>

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

  <xsl:template match="*[not(node())]">
    <xsl:variable name="element" select="(.)"/>
    <xsl:variable name="replacement">
      <xsl:for-each select="$updates">
        <xsl:copy-of select="key('replacement', local-name($element))"/>
      </xsl:for-each>
    </xsl:variable>
    <xsl:choose>
      <xsl:when test="exslt:node-set($replacement)/*">
        <xsl:copy-of select="$replacement"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:copy-of select="(.)"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>

XML file after transformation:

<root>
    <x1 attr11="sd5">
        <x2 attr12="sd6" attr15="sd7">
            <a attr1="adf" attr2="67" />
            <b>
                <x3 attr18="sd8">
                    <c>
                        <x4 attr19="sd9" />
                        <d attr5="88" attr6="mn4" />
                        <e />
                    </c>
                </x3>
            </b>
        </x2>
    </x1>
</root>

Why aren't the attributes copied to the 'b' and 'c' tags?

CodePudding user response:

Process both the original attributes as well as those from the other document with apply-templates (i.e. the identity transformation) and keep recursive processing alive:

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

  <xsl:param name="updates" select="document('updates.xml')"/>
  <xsl:key name="replacement" match="*" use="local-name()"/>

  <!--Identity template-->
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>
  
  <xsl:template match="*">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:variable name="this" select="."/>
      <xsl:for-each select="$updates">
        <xsl:apply-templates select="key('replacement', local-name($this))/@*"/>
      </xsl:for-each>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>
 

</xsl:stylesheet>
  • Related