I have a xsl:template that is inserting an additional node into my original XML.
I would then like to use the following Template to reference that new node to assist in the continuation of the parsing of the source file.
My current method (second template) does not 'see' the newly inserted node from the first template. How would I approach this?
Many Thanks.
The below examples are extremely simplified to express what I am trying to achieve.
Starting XML:
<master>
<node>
<node1>hi</node1>
<node2>bye</node2>
</node>
</master>
First Template:
<xsl:template match="master/node">
<node>
<xsl:apply-templates/>
<node3>greetings</node3>
</node>
</xsl:template>
Result XML 1:
<master>
<node>
<node1>hi</node1>
<node2>bye</node2>
<node3>greetings<node3>
</node>
</master>
Second Template:
<xsl:template match="master/node[node3='greetings']">
<node>
<newnode><xsl:value-of select="./node3"/>
</node>
</xsl:template>
Expected Result:
<master>
<node>
<newnode>greetings</newnode>
</node>
</master>
XSL:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="no" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<!-- first template -->
<xsl:template match="master/node">
<node>
<xsl:apply-templates/>
<node3>greetings</node3>
</node>
</xsl:template>
<!-- second template -->
<xsl:template match="master/node[node3='greetings']">
<node>
<newnode><xsl:value-of select="./node3"/></newnode>
</node>
</xsl:template>
In XSLT 2.0, you just capture the output of the first template in a variable, and the value of the variable is a new XML document which can be processed just like a source document.
In XSLT 1.0, when you capture the output of a template in a variable, it is not a first-class document, but rather a "result tree fragment" which can only be processed in very limited ways. The exslt:node-set() extension converts it from a "result tree fragment" to a first-class document which can then be processed normally.
I hope that helps to summarise the very detailed information you have been given by others (though I do feel that these days, we should assume people are using XSLT 2.0 unless they tell us otherwise).
In XSLT 1.0 without extensions, only nodes in input documents can be matched by templates. To apply templates to an intermediate result, you can use the
nodeset
extension (widely implemented by XSLT 1.0 implementations) which allows templates to be applied to result-tree fragments. Or you can move to XSLT 2.0.See Dimitre Novatchev's answer to a related question for more details on the nodeset extension.
Michael Sperberg-McQueen has given a precise explanation how to process RTFs (Result Tree Fragments) in XSLT 1.0.
Here is an example of a complete solution, using the EXSLT
node-set()
extension function:When this transformation is applied to the provided XML document:
the wanted, correct result is produced:
Do note that it is best to organize multi-pass processing in such a way, that all templates operating in Pass-N are in a separate and different mode than all templates operating in any other pass number. This is to avoid errors when the same template accidentally is selected for execution both in Pass-N and in Pass-M.
Using modes the above solution becomes: