tags:

views:

125

answers:

4

Hello everyone,

I am confused about XSLT apply-template statement. For example, here in w3school.

http://www.w3schools.com/xsl/xsl%5Fapply%5Ftemplates.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

+1  A: 

xsl:apply-templates directs the XSLT engine to match the current source document subnodes against the stylesheet templates for further processing.

Ignacio Vazquez-Abrams
"match the current source document subnodes" -- in the w3school sample, what are the "current source document subnodes"? And what templates defined in the xslt file will be searched against for matching for "current source document subnodes"?
George2
Since only the root has been matched so far, it would be all cd nodes. And all the templates in the example would be candidates for matching.
Ignacio Vazquez-Abrams
+1  A: 

1) <xsl:apply-templates/> calls the traverses through all the subnodes (children) and calls the matching template if any.

2) After all the nodes are matched the lines following are output which in this case are

</body> 
</html>

3) In the example catalog is the root node.

Rashmi Pandit
1. For 1, can I understand it is implemented in a two layered loop (outer loop + inner loop)? The outer loop is foreach subnodes, and inner loop is for each template defined in current xslt file (i.e. for each subnodes, processing engine will try to find matched template defined in current xslt file)? 2. If more than one template is found matched, what will happen?
George2
Can you give an example where more than one template can match a node? As far as I know, it would be an xslt error and your xslt won't compile in that case.
Rashmi Pandit
+3  A: 
  1. <xsl:apply-templates /> will try to find a template which matches current node and its children.
  2. After all matched nodes are returned, XSL processor will output those closing tags (i.e. </body> and </html>)
  3. There is a root node, just before catalog, matched by "/"

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"&gt;

    <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>
Rubens Farias
"will try to find a template which matches current nodes" -- current node or current nodes? And which templates will be searched against for matching? All in the xslt file or?
George2
"closing tags" -- what is closing tag? Could you describe in some other words please?
George2
+2  A: 

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:

  1. <xsl:apply-templates> applies templates to the children of the context node.

  2. Matched nodes aren't "returned" in step 1; the XSLT processor finds a template for each and applies it.

  3. 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.

Robert Rossney