In what order are the templates in the XSLT document executed and do they match the original XML or the buffered result?

This is what always puzzled me in XSLT:

  • In what order are the patterns executed and
  • When they are executed, do they (a) match the original XML source or (b) the current XSLT output to this point?

Example:

<person> <firstName>Deane</firstName> <lastName>Barker</lastName> </person> 

Here is an XSLT snippet:

 <!-- Template #1 --> <xsl:template match="/"> <xsl:value-of select="firstName"/> <xsl:value-of select="lastName"/> </xsl:template> <!-- Template #2 --> <xsl:template match="/person/firstName"> First Name: <xsl:value-of select="firstName"/> </xsl:template> 

Two questions:

  • I assume that pattern No. 1 will be executed first. I don’t know why I suppose this - is it only because he appears first in the document?
  • Is template # 2 running? It corresponds to the node in the source XML, but by the time we get this template (provided that it runs the second), the "firstName" node will not be in the output tree.

So, are the “subsequent” templates mandatory for what happened in the “early” templates, or do they work with the original document, not paying attention to what was brought to them? (All these words are in quotation marks, because it is difficult for me to discuss issues based on time, when I really understand little how the order of templates is determined in the first place ...)

In the above example, we have a template that matches the root of the node ("/"), which - when it is executed - has substantially removed all nodes from the output. In this case, it will prevent the execution of all other patterns, since after the completion of this first pattern there will be nothing suitable?

At this point, I was worried that later templates did not execute because the nodes they were working on did not appear in the output file, but what about the opposite? Can a “earlier” template create a node that a “later” template can do something with?

In the same XML as above, consider this XSL:

 <!-- Template #1 --> <xsl:template match="/"> <fullName> <xsl:value-of select="firstName"/> <xsl:value-of select="lastName"/> </fullName> </xsl:template> <!-- Template #2 --> <xsl:template match="//fullName"> Full Name: <xsl:value-of select="."/> </xsl:template> 

Template # 1 creates a new node called "fullName". Pattern number 2 matches the same node. Will Template # 2 run because the "fullName" node exists in the output by the time we bypass Template # 2?

I understand that I am deeply unaware of the XSLT Zen. To date, my style sheets consist of a template corresponding to the root of the node, and then they are completely procedural. I'm tired of this. I would rather get XSLT right, so my question is.

+61
xslt
Oct 07 '09 at 13:30
source share
4 answers

I like your question. You are very clear about what you have not yet understood. You just need to connect something. My recommendation is that you read “How XSLT Works,” in the chapter I wrote to accurately address the questions you ask. I would love to hear if this ties things together for you.

Less formally, I will take up the answer to each of your questions.

  • In what order are the patterns executed and
  • When they are executed, do they (a) match the original XML source or (b) the current XSLT output for that point?

At any given XSLT processing point, in a sense, there are two contexts that you identify as (a) and (b): where you are in the source tree and where you are in the result tree. Where you are in the source tree is called the current node. It can change and move throughout the source tree, as you select arbitrary sets of nodes for processing using XPath. However, conceptually, you never “jump” through the result tree in the same way. The XSLT processor builds it in an orderly manner; first, it creates the root node of the result tree; then adds children, creating the result in the order of the document (first in depth). [Your message motivates me to pick up my visualization software for XSLT experiments again ...]

The order of the template rules in the style sheet never matters. You cannot tell just by looking at the stylesheet in what order the template rules will be created, how many times the rule will be created, or even whether it will be created at all. ( match="/" is an exception, you can always know that it will be running.)

I assume that pattern # 1 will execute first. I don’t know why I suppose that this is only because it first appears in the document?

Nope. It could be called the first, even if you put it last in the document. The order of the template rules never matters (with the exception of the error condition, when you have more than one template rule with the same priority as the same node, even then it is not necessary for the developer, and you should never rely on this behavior). It is called first because the first thing that always happens when starting the XSLT processor is the virtual call <xsl:apply-templates select="/"/> . One virtual call creates an entire result tree. Nothing happens outside of it. You can customize or "customize" the behavior of this command by specifying template rules.

Is template # 2 running? It matches the node in the source XML, but by the time we get to this template (if it is the second one), the "firstName" node will not be in the output tree.

Template # 2 (or any other template rules) will never be run unless you have a call to <xsl:apply-templates/> somewhere in the match="/" rule. If you do not have them, then no template rules other than match="/" will be triggered. Think of it this way: in order for a template rule to be activated, it cannot just match the node value in the input. It should match the node you select for processing (using <xsl:apply-templates/> ). Conversely, it will continue to match node as many times as you want to process it.

Will [ match="/" template] pre-empt all other templates from execution, since there is nothing after the first template is completed?

This rule crowds out the rest, never including <xsl:apply-templates/> . There are many more nodes that can be processed in the source tree. They are always there, ripe for a choice; process each one as many times as you like. But the only way to handle them using template rules is to call <xsl:apply-templates/> .

At this point, I was worried with subsequent patterns that didn’t execute because the on nodes it uses did not appear on the output, but what about the opposite? Can you create a node "earlier", which template "later" can do something with?

Not that the earlier pattern creates a new node for processing; that the “earlier” template in turn processes more nodes from the source tree using the same instruction ( <xsl:apply-templates ). You can think of it as calling the same “function” recursively, with different parameters each time (nodes are processed according to the context and the select attribute).

In the end, you get a tree-like stack of recursive calls to the same "function" ( <xsl:apply-templates> ). And this tree structure is isomorphic to your actual result. Not everyone understands this or thought of it that way; because we don’t have effective visualization tools ... yet.

Template # 1 creates a new node called the "full name". Template No. 2 corresponds to the same node. Will template # 2 execute because the "fullName" node exists at the output by the time we get around template # 2?

Nope. The only way to make the processing chain is to explicitly configure it this way. Create a variable, for example $tempTree , that contains the new <fullName> element, and then process it like this <xsl:apply-templates select="$tempTree"> . To do this, in XSLT 1.0 you need to wrap the variable reference with an extension function (for example, exsl:node-set() ), but in XSLT 2.0 it will work the same way.

Whether you are processing nodes from the original source tree or to the temporary tree that you are creating, in any case you need to explicitly specify which nodes you want to process.

What we haven't looked at is how XSLT gets all its implicit behavior. You must also understand the built-in template rules. I constantly write stylesheets that do not even contain an explicit rule for the root of the node ( match="/" ). Instead, I rely on a built-in rule for root nodes (apply patterns to child elements), which is the same as a built-in rule for element nodes. That way, I can ignore large parts of the input, let the XSLT processor automatically cross it, and only when it encounters node, I wonder if I will do something special. Or I could write one rule that copies everything recursively (called an identity transformation), overriding it only where necessary, to make additional changes to the input. After you read “How XSLT Works,” your next appointment is to look at “identity transformation.”

I understand that I am deeply uninformed about the XSLT Zen. To date, my style sheets consisted of a template corresponding to the root of the node, then they are completely procedural from there. I'm tired of this. I would rather actually understand XSLT correctly, hence my question.

I greet you. Now it's time to take the “red pill": read "How XSLT Works"

+79
09 Oct '09 at 9:13
source share

Templates always match the source XML. Thus, the order does not matter if only two or more patterns do not match the same node (s). In this case, somewhat counter-intuitively, the rule with the last matching pattern is run.

+5
Oct 07 '09 at 14:06
source share

In the first example, Template # 1 starts because when you start processing the input xml, it starts from the root, and this is the only template in your stylesheet that matches the root element. Even if he was 2nd in the stylesheet, he would still complete 1st.

In this example, template 2 will not start because you have already processed the root element using template 1 and there are no more elements to process after the root. If you want to process other elements with additional templates, you must change them to.

 <xsl:template match="/"> <xsl:apply-templates/> </xsl:template> 

Then it allows you to define a template for each element you are interested in and process the xml in a more logical way, rather than doing it procedurally.

Also note that in this example nothing will be output, as in the current context (in the root) there is no firstName element, but only a person element, so it should be:

 <xsl:template match="/"> <xsl:value-of select="person/firstName"/> <xsl:value-of select="person/lastName"/> </xsl:template> 

It will be easier for me to think that you are navigating through xml, starting at the root and looking for a template matching this element, then following these instructions to generate the output. XSLT converts the input document to an output file, so the output dose is empty at the start of the conversion. The output is not used as part of the conversion, it is just the output from it.

In your second example, template # 2 will not run because the template runs against xml input, not output.

+2
Oct 07 '09 at 14:15
source share

Evan's answer is mostly good.

However, one thing that seems to be missing is the ability to “invoke” pieces of code without any correspondence. This, at least, according to some people, will significantly improve the structuring.

I made a small example, trying to show what I mean.

 <xsl:template match="/" name="dotable"> <!-- Surely the common html part could be placed somewhere else --> <!-- the head and the opening body --> <html> <head><title>Salary table details</title></head> <body> <!-- Comments are better than nothing --> <!-- but that part should really have been somewhere else ... --> <!-- Now do what we really want here ... this really is making the table! --> <h1>Salary Table</h1> <table border = "3" width="80%"> <xsl:for-each select="//entry"> <tr> <td><xsl:value-of select="name" /></td> <td><xsl:value-of select="firstname" /></td> <td><xsl:value-of select="age" /></td> <td><xsl:value-of select="salary" /></td> </tr> </xsl:for-each> </table> <!-- Now close out the html --> </body> </html> <!-- this should also really be somewhere else --> <!-- This approach works, but leads to horribly monolithic code --> <!-- Further - it leads to templates including code which is strictly --> <!-- not relevant to them. I've not found a way round this yet --> </xsl:template> 

However, after playing a little, and first using a hint that, if there are two suitable templates, the latter will be selected in the code and then restructuring my code (not everything is shown here), I achieved this, it seems to work, and hopefully generates the right one code, and also displays the necessary data -

 <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- <?xml version="1.0"?>--> <xsl:template name="dohtml"> <html> <xsl:call-template name="dohead" /> <xsl:call-template name="dobody" /> </html> </xsl:template> <xsl:template name="dohead"> <head> <title>Salary details</title> </head> </xsl:template> <xsl:template name="dobody"> <body> <xsl:call-template name="dotable" /> </body> </xsl:template> <xsl:template match="/entries" name="dotable"> <h1>Salary Table</h1> <table border = "3" width="80%"> <xsl:for-each select="//entry"> <tr> <td><xsl:value-of select="name" /></td> <td><xsl:value-of select="firstname" /></td> <td><xsl:value-of select="age" /></td> <td><xsl:value-of select="salary" /></td> </tr> </xsl:for-each> </table> </xsl:template> <xsl:template match="/" name="main"> <xsl:call-template name="dohtml" /> </xsl:template> 

[Scroll the code from top to bottom if you cannot see it]

How it works, the main template always matches - matches with /

It has pieces of code patterns - which are invoked.

Now this means that it is not possible to map another template to /, but you can explicitly map to the named node, which in this case is the highest level node in xml entries.

A slight modification to the code resulted in the example above.

0
Mar 09 '13 at 12:19
source share



All Articles