I am confused about XSLT apply-template statement. For example, here in w3school.
http://www.w3schools.com/xsl/xsl_apply_templates.asp
For the statements,
<xsl:template match="/">
<html>
<body>
<h2>My CD Collection</h2>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
my confusions are,
(1) what is the function of <xsl:apply-templates/>
? It does not contain any specific template to call. I think it will match (return) all directly child of current element (non-direct child of current node will not be returned, current node is root node), not sure whether I am correct?
(2) after all matched nodes are returned in (1), what are the next step XSLT processor will do?
(3) in this specifc sample, the root node is catalog or another higher level of root? and why?
thanks in advance, George
Some things that will make understanding the answers you get easier:
First and foremost, nodes and elements are not the same thing. Elements are nodes, but nodes aren't necessarily elements. You often find people using the terms interchangeably. There are actually four kinds of nodes in XML: elements, text nodes, processing instructions, and comments. (Attributes aren't really nodes, which I'll get to in a second.)
In XSLT, the root of an XML document isn't its top-level element; the root is an abstraction that doesn't really exist. The top-level element is a child of the root. For instance, here's a well-formed XML document whose root has five child nodes, including the top-level element:
<?xml-stylesheet href="mystyle.css" type="text/css"?>
<!-- this is a perfectly legitimate XML document -->
<top_level_element/>
Five? It looks like there are only three. I think I'll let you figure out what the other two are yourself. Hint: there could actually be seven nodes in that example.
The XPath expression /
finds the document root, not the top-level element. In the above case, to find the top-level element, you'd use /top_level_element
, or /*
. (It's always safe to use /*
to find the top-level element, since the document root must have a single element child.)
So armed with that knowledge, let's look at what apply-templates
does. It basically performs a two-step process: First, it builds a set of nodes. Then, and for each one, it finds a matching template (from among the templates in the XSLT file) and applies the template to it. As you observed in one of your comments, it's conceptually very similar to a loop.
The select
attribute is used in the first step. It provides an XPath expression that's used to build the node set that it's going to apply templates to. If no select
attribute is provided, the list it builds is all children of the context node. (The "context node" is the node that the current template is being applied to.)
The match
attribute on the template
elements is used in the second step. The stylesheet processor finds all templates whose match
attribute matches the node it's trying to apply templates to. If it finds more than one, it selects the most specific one it can, e.g. given these templates:
<xsl:template match="*"/>
<xsl:template match="foo"/>
<xsl:template match="foo[bar]"/>
a foo
element with a bar
child element will be matched by the third, a foo
element with no bar
will be matched by the second, and a baz
element will be matched by the first. (The actual method that XSLT uses is defined here; in practice, I've been using XSLT for nearly a decade and I've never once needed to know specifically how it works, though it's interesting.)
If it doesn't find a match, it will use the built-in default template for the type of node - basically, you can assume that any XSLT transform implicitly contains these templates:
<xsl:template match="*">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="text()">
<xsl:copy/>
</xsl:template>
<xsl:template match="processing-instruction() | comment() | @*"/>
Armed with all this knowledge, you can now understand the identity transform:
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*"/>
</xsl:copy>
</xsl:template>
That matches any node or attribute (note that attributes aren't nodes, which is why @*
is needed), copies it, and then applies templates to all of its child nodes and attributes. (Only the document root and elements will have child nodes, and only elements will have attributes.) Since it's the only template in the transform, and it matches all nodes and attributes, it applies itself to all of the child nodes and attributes. Thus, it copies everything in the source tree to the output tree.
If you add this template to the identify transform:
<xsl:template match="foo"/>
you now have a transform that copies every node in the source tree except foo
elements - that second template matches foo
elements (the first one does too, but since the second one's match
attribute is more specific, it's the one XSLT chooses) and does nothing with them.
Given all that, the answers to your specific questions:
<xsl:apply-templates>
applies templates to the children of the context node.
Matched nodes aren't "returned" in step 1; the XSLT processor finds a template for each and applies it.
In this example, the context node is the document root, an abstract node that the top-level element and any comments or processing instructions outside it are the children of.
<xsl:apply-templates />
will try to find a template which matches current node and its children.</body>
and </html>
)"/"
EDIT: An example to clarify 1.
; consider your provided sample:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
Here we're at "root" node, just before "catalog" element.<br />
Let's enumerate this child nodes:
<ul>
<xsl:for-each select="*">
<li><xsl:value-of select="name()" /></li>
</xsl:for-each>
</ul>
<!-- Now, process "catalog" and ALL his child nodes -->
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="cd">
<p>
<!-- Find a template ONLY for title element -->
<xsl:apply-templates select="title"/>
<xsl:apply-templates select="artist"/>
</p>
</xsl:template>
</xsl:stylesheet>
xsl:apply-templates directs the XSLT engine to match the current source document subnodes against the stylesheet templates for further processing.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With