Reputation: 60
After searching for the node with the same name in other structure and replace his value, how can I duplicate the parent node of the matched one?
Can I set a key for each child's parent in the template?
From this,
<Message>
<XMLNSC>
<MaXML>
<Rule>
<A>RuleA</A>
<D>RuleD</D>
</Rule>
<Body>
<A>valA</A>
<B>valB</B>
<C>
<D>valD</D>
</C>
</Body>
</MaXML>
</XMLNSC>
To this,
<Message>
<XMLNSC>
<MaXML>
<Rule>
<A>RuleA</A>
<D>RuleD</D>
</Rule>
<Body>
<A>RuleA</A>
<A>RuleA</A>
<B>valB</B>
<C>
<D>RuleD</D>
<D>RuleD</D>
</C>
<C>
<D>RuleD</D>
<D>RuleD</D>
</C>
</Body>
<Body>
<A>RuleA</A>
<A>RuleA</A>
<B>valB</B>
<C>
<D>RuleD</D>
<D>RuleD</D>
</C>
<C>
<D>RuleD</D>
<D>RuleD</D>
</C>
</Body>
</MaXML>
</XMLNSC>
My XSLT, https://xsltfiddle.liberty-development.net/pPqsHTK/5
Upvotes: 0
Views: 78
Reputation: 167716
If you write a template for those descendants of MaXML
which have a child element with a key match you can simply use the identity template twice on those descendant elements, I had the exclude the Rule
elements explicitly then:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<xsl:template match="@* | node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:key name="ref" match="MaXML/Rule/*" use="concat(generate-id(ancestor::MaXML), '|', name())"/>
<xsl:template match="MaXML//*[not(self::Rule)][*[key('ref', concat(generate-id(ancestor::MaXML), '|', name()))]]">
<xsl:call-template name="identity"/>
<xsl:call-template name="identity"/>
</xsl:template>
<xsl:template match="Body//*[key('ref', concat(generate-id(ancestor::MaXML), '|', name()))]">
<xsl:copy>
<xsl:value-of select="key('ref', concat(generate-id(ancestor::MaXML), '|', name()))"/>
</xsl:copy>
<!-- duplicate matched node -->
<xsl:element name="{name()}">
<xsl:value-of select="key('ref', concat(generate-id(ancestor::MaXML), '|', name()))"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/pPqsHTK/6
With XSLT 3 it a bit easier:
<xsl:template match="MaXML//*[not(self::Rule)][*[key('ref', node-name(), ancestor::MaXML)]]">
<xsl:next-match/>
<xsl:next-match/>
</xsl:template>
https://xsltfiddle.liberty-development.net/pPqsHTK/8
Upvotes: 1