I have a quite flat XML file for which I want to change some attributes, depending on an input list of some kind. The tricky part which I'm not able to solve is that I also want to change the attribute not only on one node but also on a sibling node that references the found node.
I have the following XML file:
<?xml version="1.0" encoding="utf-8"?>
<Root>
<SubItem id="id21" cls="classA" name="FirstSub" master="#id30"/>
<SubItem id="id22" cls="classA" name="SecondSub" master="#id31"/>
<SubItem id="id23" cls="classA" name="ThirdSub" master="#id32"/>
<SubItem id="id24" cls="classA" name="FourthSub" master="#id33"/>
<SubItem id="id25" cls="classA" name="FifthSub" master="#id34"/>
<Item id="id30" cls="classA" name="First"/>
<Item id="id31" cls="classA" name="Second"/>
<Item id="id32" cls="classA" name="Third"/>
<Item id="id33" cls="classA" name="Fourth"/>
<Item id="id34" cls="classA" name="Fifth" />
</Root>
And the following additional input file listing the name
values of elements where I want to change the cls
attribute value:
<input>
<ToClassB>
<Name>Second</Name>
<Name>Third</Name>
</ToClassB>
</input>
And the following XSLT, which works fine for elements with name
values matching those in the additional input list:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:plm="http://www.plmxml.org/Schemas/PLMXMLSchema" exclude-result-prefixes="xs"
version="2.0">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="no"/>
<xsl:variable name="inputs" select="document('file:/C:/Temp//demoInput.xml')"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/Root/Item/@name[. = $inputs/input/ToClassB/Name/text()]">
<xsl:variable name="elemName" select="../@id"/>
<xsl:copy>
<xsl:copy-of select="../@name"/>
</xsl:copy>
<xsl:attribute name="cls">
<xsl:value-of select="'classB'" />
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
My expected result:
<?xml version="1.0" encoding="UTF-8"?>
<Root>
<SubItem id="id21" cls="classA" name="FirstSub" master="#id30"/>
<SubItem id="id22" cls="ClassB" name="SecondSub" master="#id31"/>
<SubItem id="id23" cls="ClassB" name="ThirdSub" master="#id32"/>
<SubItem id="id24" cls="classA" name="FourthSub" master="#id33"/>
<SubItem id="id25" cls="classA" name="FifthSub" master="#id34"/>
<Item id="id30" cls="classA" name="First"/>
<Item id="id31" cls="ClassB" name="Second"/>
<Item id="id32" cls="ClassB" name="Third"/>
<Item id="id33" cls="classA" name="Fourth"/>
<Item id="id34" cls="classA" name="Fifth"/>
</Root>
Item tags with name
values of "Second"
or "Third"
are matched, and their cls
attribute values are changed to ClassB
, as well as the cls
attribute values for related SubItem
elements (master attribute referencing id attribute on Item
elements).
Is this possible at all with XSLT or do I need to use some programming?
<SubItem>
being associated with an<Item>
in the same document, viaSubItem/@master
andItem/@id
? Also, do you need to preserve the element order? – John Bollinger<Root>
does not directly apply templates to the<SubItem>
children, but instead relies on the template(s) for<Item>
to apply templates to the associated<SubItem>
s. You'll then have enough context to correctly direct how theircls
attributes should be transformed. – John Bollinger