I am trying to process an xml file which has several different state groups like
<root>
<childgroup>16</childgroup>
<setstate>init</setstate>
<child1>...</child1>
<child2>...</child2>
<setstate>process<setstate>
<child2>...</child2>
<child3>...</child3>
.....
<childgroup>17</childgroup>
...
What I need is actually get something like
<childgroup no="16">
<state statename="init">
<child1>...</child1>
<child2>...</child2>
</state>
<state statename="process">
<child2>...</child2>
<child3>...</child3>
</state>
</childgroup>
<childgroup no="17">
...
I've done simple part which is going and adding "chgrpno" attribute and stateid attribute to all childs (it makes copy-of of all elements but childgroup and state, adding the attribute to those two.
<xsl:template match="/">
<xsl:apply-templates mode="numb"/>
</xsl:template>
This works and in the result all childs have attribute so I could regroup them in the next pass and states have numbers so I could later make same thing. But trying to follow the example of M.Kay with "temporary documents" when I try to do
<xsl:variable name="nmb">
<xsl:apply-templates mode="numb"/>
</xsl:variable>
<xsl:template match="/">
<xsl:copy-of select="$nmb"/>
</xsl:template>
then it just returns the original to me, and all changes which I made in the first pass are gone. So what am I doing wrong here?
I use XSLT 1.0, not XSLT 2.0 explicitly.
(edit: surely I named the variable, forgot to copy it here).
The key thing in multi-pass processing with XSLT 1.0 is that the variable that contains the result of the first pass doesn't actually contain an XML document (tree).
This variable contais an RTF (Result-Tree-Fragment). RTFs are defined only in XSLT 1.0. THe only operation that can be done with an RTF is
<xsl:copy-of>
or<xsl:value-of>
or passing it as parameter -- anything that treats the RTF just as a string.By definition, any attempt to the innards of an RTF with an XPath expression having location tests in it -- must fail.
The workaround from this is to use an extension function, usually named xxx:node-set() (but Xalan uses the name "nodeset" no dash), where the
"xxx:"
prefix is bound to a specific, implementation-defined XSLT processor. As Martin Honnen recommends, for the purpose of achieving some degree of portability, one should try to use the EXSLT common:nodeset() extension, whenever this is implemented by the particular XSLT processor.Here is an example of two-pass processing with XSLT 1.0:
When applied on this XML document:
this transformation in the first pass produces a filtered tree in which only the
num
elements with odd value are present. Then the second pass renames everynum
element tox
. The final result is:Another (single-pass) possible approach (not saying the simpler one) is:
When applied on the following XML:
Produces:
You should name your variable, then you can copy it e.g.
With XSLT 1.0, if you don't want to copy the variable content with copy-of and instead want to process it with apply-templates then you need an extension function like exsl:node-set e.g.
Here is an example how to approach the grouping with XSLT 1.0 in one step; the stylesheet
transforms the input sample
into