Both xsl:for-each
and xsl:template
are used to retrieve nodes from xml in an xsl stylesheet. But what is the fundamental difference between them? Please guide me. Thanks in advance.
问题:
回答1:
I think this has some what to do with understanding push vs. pull style processing than just comparing xsl:for-each
or xsl:template match="..."
. You often see programmers from another discipline using a lot of xsl:if
, xsl:choose
and for-loops when the problem could have been solved in a more elegant XSLTish way.
But to the question: In my opinion, if you consider using xsl:for-each
instead of processing the data with xsl:apply-templates
you need to rethink. There are cases where a for-loop is suitable in XSLT, but whenever a matching template would do the same, templates are the way to go. In my experience, you can usually do most xsl:for-each
with an xsl:apply-templates
instead.
Some benefits as I see it of using matching templates over a for-loop are:
- The stylesheets are easier to maintain and extend especially if source data changes.
- As @chiborg mentions, templates can be reused since they are not built into a specific template. Together with
xsl:next-match
in XSLT 2.0 you can chain templates together in powerful ways. - You don't have to mimic behavior already built in to all XSLT processors, that is; use
xsl:apply-templates
and let the processor work for you. - Also, I find it easier to understand and debug a push style stylesheet. If you divide your stylesheet info small templates which do one or a few things and write specific matching patterns it's easy to see which template is doing what and trace the source of the problem.
回答2:
I generally agree with the other answers, but I will say that in my experience, a stylesheet written with xsl:for-each
can be a lot easier to read, understand, and maintain than one that relies heavily xsl:apply-templates
... Especially xsl:apply-templates
with an implicit select (or a very generic select like select="node()"
).
Why? Because it's very easy to see what a for-each will do. With apply-templates, you in essence have to (a) know about all possible XML inputs (which will be easier if you have a schema, but then you still have to digest the schema; and many times you don't have a schema, especially for transient intermediate XML data sent on one stage of a pipeline; and even if you have a schema, your development framework (such as an ESB or CMS) may not give you a way to validate your XML at every point your pipelines. So if invalid data creeps in you will not be notified right away), so you can predict what kinds of nodes will be selected (e.g. children of the context node); and (b) look at every template in the stylesheet to see which template matches those nodes with highest priority (and last in document order). The order of processing may also skip all over the files, or over different files (imported or included). This can make it very difficult to "see" what's going on.
Whereas with a for-each, you know exactly which code will get instantiated: the code inside the for-each. And since for-each requires an explicit select expression, you're more likely to have a narrower field to guess from regarding what nodes can be matched.
Now I'm not denying that apply-templates is much more powerful and flexible than for-each. That's exactly the point: constructs that are more powerful and flexible, are also harder to constrain, understand, and debug (and prevent security holes in). It's the Rule of Least Power: "Powerful languages (or in this case, constructs) inhibit information reuse." (Also discussed here.)
When you use apply-templates, each template is more modular and therefore more reusable in itself, but the stylesheet is more complex and the interaction between templates is less predictable. When you use for-each, the flow of processing is easy to predict and see.
With <xsl:apply-templates />
, (or with <xsl:for-each select="node()"/>
), when structure of the input XML changes, the behavior of the stylesheet changes, without the developer's review. Whether this is good or bad depends on how much forethought you've put into your stylesheet, and how much good communication there is between the XML schema developer and the stylesheet developer (who may be the same person or may belong to different organizations).
So to me, it's a judgment call. If you have document-oriented XML, like HTML, where lots of the element types really can have many different types of children, in an arbitrary-depth hierarchy, and the processing of a given element type doesn't depend very often on its context, then apply-templates is absolutely essential. On the other hand if you have "data-oriented" XML, with a predictable structure, where you don't often have the same element type meaning the same thing in different contexts, for-each can be much more straightforward to read and debug (and therefore to write correctly and quickly).
回答3:
Both the 'for-each' and 'template' are used to retrieve the nodes from xml in the xsl. But what is the difference between them in basically
Here are some of the most important differences:
xsl:apply-templates
is much richer and deeper thanxsl:for-each
, even 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 template
s 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.stylusstudio.com/xsllist/200411/post60540.html
回答4:
It doesn't really matter, but you may want to think about it for the following thumb of rules that I found:
- If the code depends on the context
position (position()), put it in a
<xsl:for-each>
. - If the code depends on the context node (. or any location path), put it in a matching template.
- Otherwise, use a named template.
Reference and read more at: http://www.jenitennison.com/blog/node/9
回答5:
These are to complete different XSLT instructions.
More than push vs. pull style, this is more like iteration vs. recursion.
xsl:for-each
is an iterator instruction with all the benefits and constrains of iteration in a stateless declarative paradigm: a good processor should not polute the call stack.
xsl:apply-templates
is a general recursion instruction. General in the sense that it's more powerful than xsl:call-template
: you "throw" the selected nodes to the pattern matching mechanism, a truly "dynamic function invocation".
回答6:
for-each
can only be used inside one place in your template. Templates can be re-used with different apply-templates
calls. I mostly use templates instead of for-each because of the added flexibility.
回答7:
One use of for-each
I haven't seen mentioned: you can use it to switch the context node to another document. I've used it to transform data XML to a HTML input form. The template that matched a data field contained a for-each that selected a single node: the xs:element
in the XSD that described the data field to transform.
Using the description in the XSD one data field could be transformed to a radio button group, a drop down box, or a plain and simple text input. Without for-each
I couldn't walk through the two documents at the same time.
In general, I prefer matching templates. I find that it corresponds to the notion of a single transform applied at once better than for-each-ing this node, then the next, then the one after that, etc.. But that's a personal preference, of course.