Reputation: 4356
Is there any way in XSL to update a global variable?
I want to check what elements i already transformed and act accordingly. That would require me to somehow add the names of the elements to some sort of list and update it each time a new element is transformed.
But since xsl:variable
isn't "variable" in the sense one would expect, i have no way of adding anything to it once it has been defined.
I have multiple included data files, so using xsl functions that only know the current set of nodes will not help.
== Edit ==
This is what my transformation looks like now. But it will include files that are repeatedly referenced in different sub-files every time.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<!-- include the contents of referenced files -->
<xsl:template match="reference">
<xsl:apply-templates select="document(@url)/data/node()" />
</xsl:template>
</xsl:transform>
And the data files would look something like this:
<data>
<reference url="another_data_file.xml"/>
... other stuff ...
</data>
Upvotes: 2
Views: 6897
Reputation: 6667
XSLT is a functional language, and does not allow variables to be updated. If you need to aggregate results over several steps, the usual approach is to use a recursive template. Example:
<xsl:template name="transform-elements">
<xsl:param name="elements-to-process" select="/.."/>
<xsl:param name="processed-elements" select="/.."/>
<xsl:if test="$elements-to-process">
<xsl:variable name="element" select="$elements-to-process[1]"/>
<!-- ... Do stuff with $element ...-->
<!-- Recursively invoke template for remaining elements -->
<xsl:call-template name="transform-elements">
<xsl:with-param name="elements-to-process"
select="$elements-to-process[position() != 1]"/>
<xsl:with-param name="processed-elements"
select="$processed-elements|$element"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
Upvotes: 8
Reputation: 32094
I am not sure about the size of the documents you are trying to parse, but as a solution for relatively small XML documents you can output the result to a variable and having applied the extension function node-set (from exslt, or msxsl, etc.) apply transformation to the contents of the variable, excluding duplicate nodes as if you would process a single XML document.
Upvotes: 0
Reputation: 176159
If your input data is spread over several documents it might be a good idea to split the transformation process into several steps.
Add a pre-processing transformation which pulls the relevant sections from the input documents into a single intermediate document. This document can then be transformed with a simple XSLT and you might not run into the problems which you are currently facing.
Upvotes: 1
Reputation: 17909
Sadly, there isn't a direct way, XSL Variables are Assign Once only, but that can be assigned conditionally.
However, variables defined in a block are only accessible to that block and its children, perhaps inverting your logic and doing it iteratively would work instead ?
That way, you can't process stuff that's been transformed already, as it's already been completed.
Have a look into the usages of xsl:Key and xsl:for-each, this will let you order the nodes you transform.
To quote from w3schools, using this XML:
<persons>
<person name="Tarzan" id="050676"/>
<person name="Donald" id="070754"/>
<person name="Dolly" id="231256"/>
</persons>
And this XSL:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="preg" match="person" use="@id"/>
<xsl:template match="/">
<html>
<body>
<xsl:for-each select="key('preg','050676')">
<p>
Id: <xsl:value-of select="@id"/><br />
Name: <xsl:value-of select="@name"/>
</p>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Will find the person with the ID of '050676'. Perhaps using this method with more defined key would give you the structure you need?
Upvotes: 1