First xml file "in.xml" to be updated:
<root attr="root">
<xItem key="1" th="1">
<m1 />
<b attr3="j" attr4="x">
<m4 />
<m3 attr4="11" />
<Chartr>
<tag1 title="tag1"/>
<Widget title="default1"/>
<tag2 title="tag2"/>
</Chartr>
<Chartu>
<tag3 title="tag3">
<tag4 title="tag4"/>
</tag3>
<Widget title="default2">
<default title="default3"/>
</Widget>
<tag5 title="tag5">
<tag4 title="tag5"/>
</tag5>
</Chartu>
<Itemz key="2" th="2">
<d>
<m6 />
<Chartn>
<Widget title="default4"/>
</Chartn>
</d>
<m5 attr5="gd"/>
</Itemz>
</b>
<Itemq key="3" th="3">
<Itemt key="4" th="4">
<Charto>
<Widget title="default5">
<default title="default6"/>
</Widget>
</Charto>
<m6 />
</Itemt>
<m7 />
</Itemq>
<Chartd />
<m2 />
</xItem>
</root>
The second xml file "updates.xml" from which data is taken to update the first file:
<updates attr="updates">
<xItem key="1">
<b>
<Chartr>
<Widget title="update1" title1="update11">
<update title="update2"/>
</Widget>
</Chartr>
<Chartu>
<Widget title="update3">
<update title="update4" title4="update44"/>
</Widget>
</Chartu>
<Itemz key="2">
<d>
<m6 />
<Chartn/>
</d>
</Itemz>
</b>
<Itemq key="3">
<Itemt key="4">
<Charto>
<Widget title="update5" x="23">
<update1 title="update6" x="23"/>
<update2 title="update7"/>
</Widget>
</Charto>
</Itemt>
</Itemq>
<Chartd/>
</xItem>
</updates>
The update.xml file differs from the input file in that it contains only those tags that are ancestors of the Widget tag and lacks some attributes. After the XSLT1.0 transformation, the input tree is transferred to the output tree with the replacement of the Widget tags from the "updates.xml" file. If there is a Widget tag in the input file, but not in the "updates.xml" file, then the widget tag from the input file is transferred to the output tree. Now the 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"/>
<xsl:key name="replacement" match="*[Widget]" use="local-name()"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[not(node())]|*[Widget]">
<xsl:variable name="this" select="."/>
<xsl:variable name="replacement">
<xsl:for-each select="$updates">
<xsl:copy-of select="key('replacement', local-name($this))"/>
</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:param name="updates" select="document('updates.xml')"/>
</xsl:stylesheet>
After transforming the file:
<root attr="root">
<xItem key="1" th="1">
<m1 />
<b attr3="j" attr4="x">
<m4 />
<m3 attr4="11" />
<Chartr>
<Widget title="update1" title1="update11">
<update title="update2" />
</Widget>
</Chartr>
<Chartu>
<Widget title="update3">
<update title="update4" title4="update44" />
</Widget>
</Chartu>
<Itemz key="2" th="2">
<d>
<m6 />
<Chartn>
<Widget title="default4" />
</Chartn>
</d>
<m5 attr5="gd" />
</Itemz>
</b>
<Itemq key="3" th="3">
<Itemt key="4" th="4">
<Charto>
<Widget title="update5" x="23">
<update1 title="update6" x="23" />
<update2 title="update7" />
</Widget>
</Charto>
<m6 />
</Itemt>
<m7 />
</Itemq>
<Chartd />
<m2 />
</xItem>
</root>
How to ensure that the output file also contains the Widget tag's siblings and their attributes and descendant tags, i.e. tag1, tag2, tag3, tag4, tag5 so that after XSLT1.0 transformation the output file looks like this:
<root attr="root">
<xItem key="1" th="1">
<m1 />
<b attr3="j" attr4="x">
<m4 />
<m3 attr4="11" />
<Chartr>
<tag1 title="tag1"/>
<Widget title="update1" title1="update11">
<update title="update2" />
</Widget>
<tag2 title="tag2"/>
</Chartr>
<Chartu>
<tag3 title="tag3">
<tag4 title="tag4" />
</tag3>
<Widget title="update3">
<update title="update4" title4="update44" />
</Widget>
<tag5 title="tag5">
<tag4 title="tag5"/>
</tag5>
</Chartu>
<Itemz key="2" th="2">
<d>
<m6 />
<Chartn>
<Widget title="default4" />
</Chartn>
</d>
<m5 attr5="gd" />
</Itemz>
</b>
<Itemq key="3" th="3">
<Itemt key="4" th="4">
<Charto>
<Widget title="update5" x="23">
<update1 title="update6" x="23" />
<update2 title="update7" />
</Widget>
</Charto>
<m6 />
</Itemt>
<m7 />
</Itemq>
<Chartd />
<m2 />
</xItem>
</root>
CodePudding user response:
By changing the context to the actual Widget and using it's parent-name as key, like this:
<?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"/>
<xsl:key name="replacement" match="Widget" use="local-name(parent::*)"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Widget">
<xsl:variable name="parentName" select="local-name(parent::*)"/>
<xsl:variable name="replacement">
<xsl:for-each select="$updates">
<xsl:copy-of select="key('replacement', $parentName)"/>
</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:param name="updates" select="document('updates.xml')"/>
</xsl:stylesheet>