Update same node multiple times with XSLT



I'm trying to use XSLT to update an XML document that I have. It needs to make multiple changes to the document to convert it to some other specifications.


What I want to do is update the same node more than once. Another way to look at it is I'd like to make multiple passes at the document, and each pass could update the same node.


All of my googling hints at using the 'mode' attribute of xsl:template, but all of the examples of the 'mode' attribute involve outputting the node twice - like in the case of using a heading in the table of contents and using it again as the title of a chapter. I don't want to output the node twice, I want to update it twice.


My sample XSLT:



<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version = '2.0'
xmlns:xsl='http://ift.tt/tCZ8VR'>

<!-- identity transform (copy over the document) -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>

<!-- wrap all BBB nodes in parenthesis -->
<xsl:template match="BBB" >
<xsl:copy>
(<xsl:apply-templates select="@*|node()" />)
</xsl:copy>
</xsl:template>

<!-- any BBB that has a CCC should get an attribute indicating so -->
<xsl:template match="BBB[CCC]">
<xsl:copy>
<xsl:attribute name="hasC">true</xsl:attribute>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>


</xsl:stylesheet>


My sample xml document:



<?xml version="1.0" encoding="UTF-8"?>
<source>

<AAA>
<BBB>Bee bee bee</BBB>
<BBB>Bee two bee two bee two</BBB>
</AAA>
<AAA>
<BBB/>
<CCC>
<DDD/>
</CCC>
<BBB>
<CCC/>
</BBB>
</AAA>

</source>


The current output:



<?xml version="1.0" encoding="UTF-8"?><source>

<AAA>
<BBB>
(Bee bee bee)
</BBB>
<BBB>
(Bee two bee two bee two)
</BBB>
</AAA>
<AAA>
<BBB>
()
</BBB>
<CCC>
<DDD/>
</CCC>
<BBB hasC="true">
<CCC/>
</BBB>
</AAA>

</source>


As you can see, the BBB node that has the 'CCC' only got updated once, with the second template - the first template didn't modify it. Ideally, I want the output to be



<BBB hasC="true">
(<CCC/>)
</BBB>


Is this possible? I know I could accomplish this by combining the two templates together, but I really want to keep them separate for readability and maintinence - the two templates come from different requirements, and keeping them separate is ideal.


I suppose I could have two XSLT files and chain them together by calling the XSLT processor twice, but I'm hoping I don't need to that.


No comments:

Post a Comment