Home > Software engineering >  Copy with update to output xml tree?
Copy with update to output xml tree?

Time:04-15

Input file "in.xml":

<x1 attr1="1">
  <A default="dA" title="XXX">
    <x2 attr2="2">
      <B default="dB" description="YYY">
        <x3 attr3="3">
          <C default="dC" title="ZZZ"/>
        </x3>
      </B>
    </x2>
  </A>
</x1>

The "updates.xml" file from which updates are taken - tag attributes a, b, c:

<Macro>
  <Item key="Element">
    <A title="titleA" description="descriptionA" />
    <B title="titleB" description="descriptionB" />
    <C title="titleC" description="descriptionC" />
  </Item>
</Macro>

The input file is copied into the output tree unchanged, with the addition of attributes that are in the "updates.xml" file but are not in the input file. If the tag has the same attributes in the input file and the "updates.xml" file, then the data from the input file takes precedence. The file after XSLT1.0 transformation should look like this:

<x1 attr1="1">
  <A default="dA" title="XXX" description="descriptionA">
    <x2 attr2="2">
      <B default="dB" title="titleB" description="YYY">
        <x3 attr3="3">
          <C default="dC" title="ZZZ" description="descriptionC" />
        </x3>
      </B>
    </x2>
  </A>
</x1>

Now this is the XSLT1.0 transformation file:

<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:strip-space  elements="*"/>
 
  <xsl:output method="xml" indent="yes" />
  <xsl:variable name="update" select="document('update.xml')"/>
 
  <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="name" select="name()"/>
      <xsl:apply-templates select="$update//*[name(.) = $name]/@*"/>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>
 
</xsl:stylesheet>

Current XML file after transformation:

<x1 attr1="1">
  <A default="dA" title="titleA" description="descriptionA">
    <x2 attr2="2">
      <B default="dB" title="titleB" description="descriptionB">
        <x3 attr3="3">
          <C default="dC" title="titleC" description="descriptionC" />
        </x3>
      </B>
    </x2>
  </A>
</x1>

How to copy all attributes present in input file without changing?

CodePudding user response:

Change the order of

  <xsl:apply-templates select="@*"/>
  <xsl:variable name="name" select="name()"/>
  <xsl:apply-templates select="$update//*[name(.) = $name]/@*"/>

to

  <xsl:variable name="name" select="name()"/>
  <xsl:apply-templates select="$update//*[name(.) = $name]/@*"/>
  <xsl:apply-templates select="@*"/>

that way the attributes from the input document "win" as they are copied last.

  • Related