Usually the programming languages allow you to declare a variable for example:
Dim test as integer <-- Visual Basic
and subsequently allow to increase the value in a for each cycle.
for test=0 to 3
print test
next
Can I create a similar structure in XSLT 1.0?
With 'xsl:variable', I declare a variable, but if I want to increase in a for-each as you do?
The closest is XSLT 2.0 with
<xsl:for-each select="0 to 3">
<xsl:value-of select="."/>
</xsl:for-each>
which processes the sequence of integers 0, 1, 2, 3.
As you see, it does not use a variable and increments that, as variables are immutable, you simply bind a value to them once.
With XSLT 1.0 you can process nodes or you can write a recursive, named templates where each recursive call passes on an incremented parameter value. Whether you actually need that depends on your requirements, if you are new to the declarative programming of XSLT then it is best that you define your problem by showing a sample of the XML input and the corresponding output you want to create, explaining how the input is mapped to the output.
Related
I'm starting to learn XSLT/XPath, and I copied the following from a study guide, making some modifications:
<xsl:variable name="fname" select="'polist.xml'"/>
<xsl:variable name="thePath" select="'/collection/doc'"/>
...
<xsl:value-of select="count(doc($fname)/collection/doc)"/>
It reports the number of doc elements in the XML file. The doc() function accepts the file name variable 'fname'. But if I try to do the same with the 'thePath' variable in the count() function, using $thePath instead of the "/collection/doc" text, I get an error.
Suggestions on whether/how to use the 'thePath' variable in the count() function? Is it possible? Thanks!
Learning from examples leaves you very exposed to this kind of problem: it's easy to build a completely incorrect mental model of how the examples actually work. That's why I always advise people to start by reading a good book that explains the concepts first.
In your case you've made a common mistake, which is to assume that variables work like macros, that is, that they represent fragments of XPath text that can be substituted into an expression. That's not the case: variables represent values, the result of evaluating an expression, and you can only use a variable in places where a literal value (like a number or string) could appear.
(I suspect it's the use of the $ sign that leads to this false impression. $ is often used to represent variables in macro-like languages, for example shell scripts).
In XPath 1.0 there's no direct way of achieving what you are trying to do. In practice people either use vendor extensions for this, or they construct a pipeline in which phase 1 generates an XSLT stylesheet and phase 2 executes it (that's easier in XSLT than in most other languages, because XSLT is XML and can therefore be easily manipulated using XSLT).
In 3.0 you can evaluate XPath expressions supplied in the form of a string using the xsl:evaluate instruction. But very often, the requirement can be met better using functions. We don't know what the real underlying requirement is here so it's hard to know whether that's true in this case.
An example use of xsl:evaluate in XSLT 3 would be e.g.
<xsl:evaluate xpath="'count(' || $thePath || ')'" context-item="doc($fname)"/>
I want to validate an assumption that a set of 'or' statements as a predicate of a for-each operates analogous to the choose statement. Either things work as I expect or I just haven't hit the edge case that will cause an issue.
In a choose structure I know that it is evaluated in sequence and when the sequence finds a test that resolves to 'true' the processor drops out of the choose.
<xsl:choose>
<xsl:when test="number($A) and $A=1">
<!—do a thing -->
</xsl:when>
<xsl:when test="number($A) and $A=2">
<!—do a thing -->
</xsl:when>
<xsl:when test="number($A) and $A < 3">
<!—do a thing -->
</xsl:when>
</xsl:choose>
So if the first and third when is true (highly probable), the processor drops out of the choose when the first when resolves as true. This is great and expected. However, when this choose needs to be compressed into a for-each it seems a simple task, but a nagging thought in my mind is that I'm just getting lucky.
<xsl:for-each select="bunch of paths[(number($A) and $A=1) or (number($A) and $A=2) or (number($A) and $A < 3)]
In this example whether the first or third (or both) passes probably doesn't matter, but most of my work operates on financial dates so in that respect I want to be sure that if the first and third both pass that the predicate will evaluate the same as the choose statement.
So, I'm just seeking to ensure that my assumption that has been based on observation of predicate evaluation within the for-each is the same as the choose.
A significant difference between the two cases is that with the xsl:for-each example the evaluation context changes (both in the predicate, and in the body of the for-each instruction), while in the xsl:choose case, the context is the same throughout.
Another difference is that xsl:when always takes the effective boolean value of the test expression (so number 1 means true), whereas predicates have different semantics if the value is numeric.
<xsl:value-of select="$MyVar"/>
works but
<xsl:value-of select="MyDataPfath/$MyVar"/>
do not work.
What is wrong in my code?
From the look of it, what you are trying to achieve is 'dynamic evaluation'. XSLT does not support the dynamic evaluation of XPath by default, so you will need to make use of an extension function.
Depending on your XSLT processor, you might want to look at EXSLT extensions. In particular the dynamic module at http://www.exslt.org/dyn/index.html. This would allow to do something like this
<xsl:value-of select="dyn:evaluate('MyDataPfath/$MyVar')"/>
However, in your case, perhaps the $MyVar contains just a single element name. In which case you could change your command to the following, which would work without any extension functions
<xsl:value-of select="MyDataPfath/*[local-name() = $MyVar]"/>
Your code didn't fail, it did exactly what the specification says it should do. Which was different from what you were hoping/imagining that it might do.
Your hopes/imagination were based on a fundamental misunderstanding of the nature of variables in XPath. XPath variables are not macros. They don't work by textual substitution; they represent values. If the variable $E contains the string "X", then MyPath/$E means the same as MyPath/"X", which is illegal in XPath 1.0, and in XPath 2.0 returns as many instances of the string "X" as there are nodes in MyPath.
You probably intended MyPath/*[name()=$E]
it is not possible to get the value by using syntax 'MyDataPfath/$MyVar' in . it will not recognize the proper path.
suppose $MyVar has value 'Hi'. so it will be represented as 'MyDataPfath/"Hi"', this is not valid path, which you want to retrieve from the XML.
to remove this limitation, You can use name() or local-name() function, that can be used as follows:
or
I'm using Saxon-EE 9.3.0.4 for xsl transformations and found that when <xsl:result-document> is used inside <xsl:attribute> (as well as <xsl:namespace>, <xsl:processing-instruction>) instruction, processor
raises XTDE1480 error - Cannot switch to a final result destination while writing a temporary tree
<xsl:attribute name="a">
<xsl:result-document href="result.xml" > - error here
test
</xsl:result-document>
</xsl:attribute>
According to specification (Appendix D) permitted parents for <xsl:result-document> are:
any XSLT element whose content model is sequence constructor
any literal result element
Is this is bug in Saxon or limitations for <xsl:result-document> usage, which are not defined in specification?
Update:
I believe that this is not a good idea to use <xsl:result-document> inside <xsl:attribute>, but why error happens?
Thanks
In the spec, you can read :
The instructions in the initial template are evaluated in final output
state. An instruction is evaluated in the same output state as its
calling instruction, except that xsl:variable, xsl:param,
xsl:with-param, xsl:attribute, xsl:comment,
xsl:processing-instruction, xsl:namespace, xsl:value-of, xsl:function,
xsl:key, xsl:sort, and xsl:message always evaluate the instructions in
their contained sequence constructor in temporary output state.
The xsl:result-document write in a final tree result, and given the rule above, I understand that it is an error to try writting in a final tree result when inside the following elements
xsl:variable, xsl:param, xsl:with-param, xsl:attribute, xsl:comment, xsl:processing-instruction, xsl:namespace, xsl:value-of, xsl:function, xsl:key, xsl:sort, and xsl:message
Update in 2018: note that the XSLT 3.0 specification relaxes the restrictions. Instructions such as xsl:attribute and xsl:comment no longer set temporary output state. Recent Saxon versions (certainly 9.8) implement the revised rules.
I am new in XSLT so I'm little bit confused about the two tags,
<xsl:apply-templates name="nodes">
and
<xsl:call-template select="nodes">
So can you list out the difference between them?
<xsl:call-template> is a close equivalent to calling a function in a traditional programming language.
You can define functions in XSLT, like this simple one that outputs a string.
<xsl:template name="dosomething">
<xsl:text>A function that does something</xsl:text>
</xsl:template>
This function can be called via <xsl:call-template name="dosomething">.
<xsl:apply-templates> is a little different and in it is the real power of XSLT: It takes any number of XML nodes (whatever you define in the select attribute), processes each of them (not necessarily in any predefined order), somebody could say that apply-templates works like a loop, but this is not exactly the case, as the nodes may be processed in any order, even in parallel, and finds matching templates for them:
<!-- sample XML snippet -->
<xml>
<foo /><bar /><baz />
</xml>
<!-- sample XSLT snippet -->
<xsl:template match="xml">
<xsl:apply-templates select="*" /> <!-- three nodes selected here -->
</xsl:template>
<xsl:template match="foo"> <!-- will be called once -->
<xsl:text>foo element encountered</xsl:text>
</xsl:template>
<xsl:template match="*"> <!-- will be called twice -->
<xsl:text>other element countered</xsl:text>
</xsl:template>
This way you give up a little control to the XSLT processor - not you decide where the program flow goes, but the processor does by finding the most appropriate match for the node it's currently processing.
If multiple templates can match a node, the one with the more specific match expression wins. If more than one matching template with the same specificity exist, the one declared last wins.
You can concentrate more on developing templates and need less time to do "plumbing". Your programs will become more powerful and modularized, less deeply nested and faster (as XSLT processors are optimized for template matching).
A concept to understand with XSLT is that of the "current node". With <xsl:apply-templates> the current node moves on with every iteration, whereas <xsl:call-template> does not change the current node. I.e. the . within a called template refers to the same node as the . in the calling template. This is not the case with apply-templates.
This is the basic difference. There are some other aspects of templates that affect their behavior: Their mode and priority, the fact that templates can have both a name and a match. It also has an impact whether the template has been imported (<xsl:import>) or not. These are advanced uses and you can deal with them when you get there.
To add to the good answer by #Tomalak:
Here are some unmentioned and important differences:
xsl:apply-templates is much richer and deeper than xsl:call-templates and even from xsl:for-each, simply because we don't know what code will be applied on the nodes of
the selection -- in the general case this code will be different for
different nodes of the node-list.
The code that will be applied
can be written way after the xsl:apply templates was written and by
people that do not know the original author.
The FXSL library's implementation of higher-order functions (HOF) in XSLT wouldn't be possible if XSLT didn't have the <xsl:apply-templates> instruction.
Summary: Templates and the <xsl:apply-templates> instruction is how XSLT implements and deals with polymorphism.
Reference: See this whole thread: http://www.biglist.com/lists/lists.mulberrytech.com/xsl-list/archives/200411/msg00546.html
xsl:apply-templates is usually (but not necessarily) used to process all or a subset of children of the current node with all applicable templates. This supports the recursiveness of XSLT application which is matching the (possible) recursiveness of the processed XML.
xsl:call-template on the other hand is much more like a normal function call. You execute exactly one (named) template, usually with one or more parameters.
So I use xsl:apply-templates if I want to intercept the processing of an interesting node and (usually) inject something into the output stream. A typical (simplified) example would be
<xsl:template match="foo">
<bar>
<xsl:apply-templates/>
</bar>
</xsl:template>
whereas with xsl:call-template I typically solve problems like adding the text of some subnodes together, transforming select nodesets into text or other nodesets and the like - anything you would write a specialized, reusable function for.
Edit:
As an additional remark to your specific question text:
<xsl:call-template name="nodes"/>
This calls a template which is named 'nodes':
<xsl:template name="nodes">...</xsl:template>
This is a different semantic than:
<xsl:apply-templates select="nodes"/>
...which applies all templates to all children of your current XML node whose name is 'nodes'.
The functionality is indeed similar (apart from the calling semantics, where call-template requires a name attribute and a corresponding names template).
However, the parser will not execute the same way.
From MSDN:
Unlike <xsl:apply-templates>, <xsl:call-template> does not change the current node or the current node-list.