The Transformation Process


I've described the essential process performed by XSLT, transformed a source tree to a result tree under the control of a stylesheet, and looked at the structure of these trees. Now it's time to look at how the transformation process actually works, which means taking a look inside the stylesheet.

Invoking a Transformation

The actual interface for firing off a transformation is outside the scope of the XSLT specification, and it's done differently by different products. There are also different styles of interface: possibilities include an API that can be invoked by applications, a GUI interface within a development environment, a command line interface, and the use of an <?xml-stylesheet?> processing instruction within a source document, which is described in Chapter 3 (see page 93). There's a common API for Java processors that was initially called TrAX, then became part of JAXP, and in JDK 1.4 has become part of the standard Java class library. For browsers, Microsoft and Netscape each has its own API, but there is at least one project (Sarissa, see http://sarissa. sourceforge .net/) that provides a common API that can be used on either browser.

What the XSLT 2.0 specification does do is to describe in abstract terms what information can be passed across this interface when the transformation is started. This includes the following:

  • The stylesheet itself: Many products provide separate API calls to compile a stylesheet and then to run it, which saves time if the same stylesheet is being used to transform many source documents.

  • A source document: This can be identified by any node in the document, which acts as the initial context node for the transformation. This will usually be the document node at the root of the tree, but it doesn't have to be. In fact, you don't have to supply an initial context node at all; you can instead supply the name of a template that will be the first template to be executed. The stylesheet can then fetch any data it needs from stylesheet parameters or from calls on the document() function.

  • An initial named template: This acts as the entry point to the stylesheet and can be specified instead of supplying an initial context node, but it is also possible to supply both. If an initial named template is identified, the transformation starts with that template; otherwise , it starts by searching for a template rule that matches the initial context node, as described in the next section.

  • An initial mode: Modes are described later in this chapter, on page 70. Normally, the transformation starts in the default (unnamed) mode, but you can choose to start in a different mode if you prefer. When the template rules in a stylesheet use a named mode, it becomes easier to combine two stylesheets into a single multiphase transformation, as described on page 82, and this feature ensures that you can still use the rules for each processing phase independently.

  • Parameters: A stylesheet can define global parameters using <xsl:param> elements, as discussed on page 392. Interfaces for invoking a transformation will generally provide some kind of mechanism for setting values for these parameters. (A notable exception is that when you invoke a transformation using the <?xml-stylesheet?> processing instruction in a source document, there is no way of setting parameters.)

  • A base URI for output documents: Many stylesheets will produce a single result document, and this URI effectively defines where this result document will be written. If the stylesheet produces multiple result documents, then each one is created using an <xsl:result-document> instruction with an href attribute, and the href attribute, if it is a relative URI, is interpreted as a location relative to this base URI.

Template Rules

As we saw in Chapter 1, most stylesheets will contain a number of template rules. Each template rule is expressed in the stylesheet as an <xsl:template> element with a match attribute. The value of the match attribute is a pattern. The pattern determines which nodes in the source tree the template rule matches.

For example, the pattern «/ » matches the root node, the pattern «title » matches a <title> element, and the pattern «chapter/title » matches a <title> element whose parent is a <chapter> element.

When you invoke an XSLT processor to apply a particular stylesheet to a particular source document, the first thing it does is to read and parse these documents and create internal tree representations of them in memory. Once this preparation is complete, the transformation process can start.

The first step in the transformation process is usually to find a template rule that matches the document node of the source tree. If there are several possible candidates, there is a conflict resolution policy to choose the best fit (see page 71 for details). If there is no template rule that matches the document node, a built-in template is used. The XSLT processor then evaluates the contents of this template rule.

XSLT 2.0 also allows you to start the transformation by supplying an initial node other than the document node. As discussed in the previous section , you can even start the transformation without supplying an initial node at all, by providing the name of the first template to be evaluated.

The content of an <xsl:template> element in the stylesheet is a sequence of elements and text nodes. Comments and processing instructions in the stylesheet are ignored, as are whitespace text nodes, unless they belong to an <xsl:text> element or to one with an appropriate xml:space attribute. This sequence of elements and text nodes is called a sequence constructor, because the result of evaluating it is itself a sequence.

Elements in the sequence constructor can be classified as either instructions or data, depending on their namespace. Text nodes are always classified as data. When the sequence constructor is evaluated, the instructions are evaluated, and the result of each instruction is added to the result sequence. The data nodes are copied to the result tree. Elements that are classified as data are officially termed literal result elements.

Contents of a Sequence Constructor

Consider the following template rule.

  <xsl:template match="/">   <xsl:message>Started!</xsl:message>   <xsl:comment>Generated from XSLT</xsl:comment>   <html>   ...   </html>   The end   </xsl:template>  

The body of this template rule consists of two instructions ( <xsl:message> and <xsl:comment> ), a literal result element (the <html> element), and some text ( «The end »). When this template is evaluated, the instructions are executed according to the rules for each individual instruction, and literal result elements and text nodes are copied (as element nodes and text nodes, respectively) to the result sequence.

It's simplest to think of this as a sequential process, where evaluating a sequence constructor causes evaluation of each of its components in the order they appear. Actually, because XSLT is largely side-effect-free, they could be executed in a different order, or in parallel. The important thing is that after evaluating this sequence constructor, the result sequence will contain a comment node (produced by the <xsl:comment> instruction), an <html> element node (produced by the <html> literal result element), and the text node «The end » . The order of these items in the result sequence corresponds to the order of the instructions in the stylesheet, although in principle the XSLT processor is free to execute the instructions in any order it likes.

<xsl:message> is an exception to the rule that XSLT is side-effect-free. Evaluating an <xsl:message> instruction doesn't cause anything to be added to the result sequence; it merely causes the side effect of writing a message to some external device (perhaps standard output, or a log file). If there are several <xsl:message> instructions in a sequence constructor, then the order in which the messages appear is not guaranteed .

If I hadn't included the «... » within the <html> element, this would be the end of the matter. But when a literal result element such as <html> is evaluated, its content is treated as a sequence constructor in its own right, and this is evaluated in the same way. It can again contain a mixture of instructions, literal result elements, and text. As we'll see in the next section, the result sequence produced by this sequence constructor is used to create the nodes that are attributes and children of the new <html> element.

Sequence Constructors

Sequence constructors play such an important role in the XSLT 2.0 processing model that it's worth studying them in some detail.

As we have seen, the content of an <xsl:template> element, after any parameter definitions contained in <xsl:param> elements, is a sequence constructor. (In XSLT 1.0, a sequence of instructions is officially called a template, though in practice everyone uses this term to mean "a template rule." In the previous edition of this book, I referred to the concept as a template body .) The new name sequence constructor reflects a change in the way the processing model is described, and a change in its capability: a sequence of instructions can now be used to produce any sequence of items, not only a sequence of sibling nodes in a tree.

Many other XSLT elements are also defined to have a sequence constructor as their content. For example, the contents of an <xsl:variable> or <xsl:if> element follow exactly the same rules as the content of an <xsl:template> (ignoring <xsl:param> elements), and these too are sequence constructors. It follows that one sequence constructor may be contained within another. For example, consider the following template rule.

  <xsl:template match="para">   <xsl:if test="position()=1">   <hr/>- o - 0 - o -<hr/> </xsl:if>   <xsl:apply-templates/>   <xsl:if test="position()=last()">   <hr/>- o - 0 - o -<hr/>   </xsl:if>   </xsl:template>  

Viewed as a tree, using the notation introduced in Chapter 2, this has the structure shown in Figure 2-7. There are three sequence constructors, indicated by the dotted lines. Within the sequence constructors on this tree, there are three kinds of nodes: text nodes, XSLT instructions (such as <xsl:if> ), and literal result elements (such as <hr> ), which are elements to be written to the result tree.

click to expand
Figure 2-7

A sequence constructor is the nearest equivalent in XSLT to a block or compound statement in a block-structured programming language such as C or Java; and like blocks in C or Java, it defines the scope of any local variables declared within the block.

A sequence constructor is a sequence of sibling nodes in the stylesheet. Comment and processing instruction nodes are allowed, but the XSLT processor ignores them. The nodes of interest are text nodes and element nodes.

When a sequence constructor is evaluated, the result is, in general, a sequence of items. Many instructions such as <xsl:element>, <xsl:copy-of >, and <xsl:number> can create new nodes; a couple of the new instructions introduced in XSLT 2.0 such as <xsl:sequence> and <xsl:perform- sort > can also return references to existing nodes in a source document. It is also possible for the sequence to contain atomic values: these can be produced using the <xsl:sequence> and <xsl:copy-of> instructions.

Most likely, the sequence returned by a sequence constructor will be used to build the content of an element node in the result tree. In the example shown in Figure 2-7:

  • The sequence constructors contained in the <xsl:if> elements always (if they are evaluated at all) produce a sequence of three nodes: two empty <hr> elements and a text node.

  • The sequence constructor contained in the <xsl:template> instruction returns a sequence that is the concatenation of the nodes returned by the first <xsl:if> instruction, then the nodes returned by the <xsl:apply-templates> instruction, and finally the nodes returned by the second <xsl:if> instruction. The result of the template is this sequence of nodes.

Suppose that the template rule in our example is invoked using a construct such as the following.

  <div>   <xsl:apply-templates select="para"/>   </div>  

The <xsl:apply-templates> instruction results in the sequence of nodes produced by evaluating the selected template rule. In fact, this instruction can select several <para> elements, and the template rule is invoked once for each one. The resulting nodes are all concatenated into a single sequence. Because the <xsl:apply-templates> instruction is the only instruction in the sequence constructor contained by the <div> element, the final sequence delivered to the <div> element contains the results of expanding the template rule for each of the selected <para> elements in the source document.

The <div> element is a literal result element, which when evaluated constructs a new element node. The name of this node will be <div> , and the content will be formed from the sequence produced by evaluating the sequence constructor contained within the literal result element in the stylesheet. In our example, this sequence contains elements and text nodes, and these are copied to form the content of the new <div> element.

This is by far the most common scenario: instructions are evaluated to produce a sequence of nodes, and the nodes are copied to form the contents of a result tree. However, in XSLT 2.0 it is also possible to process the sequence in other ways. In particular:

  • A generated sequence can be captured in a variable. For example, the following variable will have a value that is a sequence of element nodes. These elements are not attached to a tree; they have no parent, and they are not siblings of each other:

      <xsl:variable name="months" as="element()*">   <month>January</month>   <month>February</month>   <month>March</month>   </xsl:variable>  

    You can then refer to the third element in this sequence as «$months[3] » . But don't try doing «$months/month » ; the $months variable holds a sequence of <month> elements, and the path expression «$months/month » (which is short for «$months/child::month » ) tries to find children of these elements that are named <month> . It won't find any.

This kind of variable is constructed when the «as » attribute is present to define the required type of the items in the sequence. If the «as » attribute were omitted, the <month> elements would be added to a temporary tree, and the variable $months would refer to the document node of this tree. For more information, see the section Temporary Trees on page 79.

  • A generated sequence can also be returned by a function. Rather than defining the sequence of month elements in a variable, it could equally well be defined in a function.

      <xsl:function name="m:months" as="element()*">   <month>January</month>   <month>February</month>   <month>March</month>   </xsl:function>  

    You could then refer to the third month as «m:months() [3] » . Note that user -defined functions must always be in a namespace, to avoid conflicts with system-defined functions.

  • There is an important difference between using a variable and a function to capture the sequence: the variable will return the same elements every time, whereas the function will create new elements every time you call it. For example, this means that the expression «$months[3] is $months[3] » will be true , while «m:months() [3] is m:months() [3] » will be false. (The «is » operator in XPath 2.0 tests whether the values of the two operands are references to the same node.) In practice, you would want to use a function only if you were supplying parameters, because the data that came back depended on the parameters in some way.

Text nodes appearing within a template body are copied to the result sequence when the sequence constructor is evaluated. However, text nodes in a sequence constructor that consist entirely of whitespace will be ignored, unless the xml:space attribute is used on an enclosing element to define them as significant.

Text nodes containing whitespace only are also significant if they appear as the content of an <xsl:text> element, but in that case they are not part of a sequence constructor.

For more information on the treatment of whitespace see Chapter 3, page 136.

Nested Sequence Constructors

Suppose the template rule actually looks like this.

  <xsl:template match="/">   <xsl:message>Started!</xsl:message>   <xsl:comment>Generated from XSLT</xsl:comment>   <html>   <head>   <title>My first generated HTML page</title>   </head>   <body>   <xsl:apply-templates/>   </body>   </html>   The end   </xsl:template>  

Here the <html> element contains two child elements, <head> and <body> . These are both literal result elements, so they are evaluated by copying them from the stylesheet to the result sequence.

Evaluating the <head> element in turn causes the sequence constructor within the <head> element to be evaluated. This sequence constructor contains a single literal result element, the <title> element, which in turn contains a sequence constructor containing a single text node, whose value is the string «My first generated HTML page » .

What happens here (as far as the formal definition of the processing model is concerned ) is a bottom-up process of tree construction. The sequence constructor containing the text node is evaluated to produce a result sequence containing a copy of the text node. The <head> element is then evaluated to produce a new <head> element node, which has this text node as its only child.

When the <body> element is evaluated, things get more interesting because it contains an XSLT instruction, namely <xsl:apply-templates/> . This particular instruction has critical importance: when written as here, without any attributes, it means "select all the children of the current node in the source tree, and for each one, find the matching template rule in the stylesheet, and evaluate it."

What actually happens at this point depends both on what is found in the source document, and on what other template rules are present in the stylesheet. Typically, because we are currently processing the root node of the source document tree, it will have just one child node, namely the document element (the outermost element of the source XML document). Suppose this is a <doc> element. Then the XSLT processor will search the stylesheet looking for a template rule that matches the <doc> element.

The simplest situation is where it finds just one rule that matches this element, for example one declared as:

  <xsl:template match="doc">  

If it finds more than one matching template rule, it has to use its conflict resolution policy to choose the best fit. The other possibility is that there is no matching template rule: in this case it invokes the built-in template rule for element nodes, which simply executes <xsl:apply-templates/>: in other words, it selects the children of this element, and tries to find template rules that match these children. There's also a built-in template rule for text nodes, which copies the text node to the output. If the element has no children, <xsl:apply-templates/> does nothing.

Whatever happens, however, the result of evaluating the <xsl:apply-templates> instruction is a sequence, usually a sequence of nodes. These nodes are added to the result of the sequence constructor contained by the <body> instruction, and are used to form the children (and potentially also the attributes) of the new <body> element. The new <head> and <body> elements now form a sequence that's used to make the children of the <html> element; and because this template rule was the first one to be activated, the transformation is now complete and the tree with this <html> element at the top becomes the final result tree of the transformation. (The <html> element is automatically wrapped in a document node, to complete the process.)

Hopefully, you never actually need to analyze what's going on to this level of detail. The name template was chosen because you can think of the whole process as producing a simple fill-in-the-blanks copy of the elements in the stylesheet as elements in the result tree. In the case of literal result elements and literal text, they are copied across unchanged; in the case of XSLT instructions, some processing is performed to fetch data from a source document for insertion at this point in the result tree.

Push Processing

The simplest way to process a source tree is thus to write a template rule for each kind of node that can be encountered , and for that template rule to produce any output required, as well as to call <xsl:apply-templates> to process the children of that node.

Push Processing
start example

This example demonstrates the push processing technique: a rule-based stylesheet in which there is one template rule to process each different kind of node.

end example
 

Input

The source document, books.xml, is a simple book catalog.

  <?xml version="1.0"?>   <books>   <book category="reference">   <author>Nigel Rees</author>   <title>Sayings of the Century</title>   <price>8.95</price>   </book>   <book category="fiction">   <author>Evelyn Waugh</author>   <title>Sword of Honour</title>   <price>12.99</price>   </book>   <book category="fiction">   <author>Herman Melville</author>   <title>Moby Dick</title>   <price>8.99</price>   </book>   <book category="fiction">   <author>J. R. R. Tolkien</author>   <title>The Lord of the Rings</title>   <price>22.99</price>   </book>   </books>  

Stylesheet

Say you want display this data in the form of a sequentially numbered booklist. The following stylesheet, books.xsl , will do the trick.

  <xsl:stylesheet   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"   version="2.0"   >   <xsl:template match="books">   <html><body>   <h1>A list of books</h1>   <table width="640">   <xsl:apply-templates/>   </table>   </body></html>   </xsl:template>   <xsl:template match="book">   <tr>   <td><xsl:number/></td>   <xsl:apply-templates/>   </tr>   </xsl:template>   <xsl:template match="author  title  price">   <td><xsl:value-of select="."/></td>   </xsl:template>   </xsl:stylesheet>  

What's happening here? There's no template rule for the document node, so the built-in template gets invoked. This processes all the children of the document node.

There's only one child of the document node, the <books> element. So the template rule for the <books> element is evaluated. This creates some standard HTML elements on the result tree, and eventually calls <xsl : apply-templates / > to cause its own children to be processed . These children are all <book> elements, so they are all processed by the template rule whose match pattern is «match = "book" » . This template rule outputs an HTML <tr> element, and within it a <td> element, which it fills by executing the <xsl:number/> instruction whose effect is to get the sequence number of the current node (the <book> element) within its parent element. It then calls <xsl : apply-templates/> once again to process the children of the <book> element in the source tree.

The children of the <book> element in the source document are all <author> , <title> , or <price> elements; so as it happens they all match the template rule whose match pattern is «match="author title price" » (you can read « » as "or"). This template rule outputs an HTML <td> element that it fills by executing an instruction < xsl:value-of select="."/> This instruction evaluates an XPath expression, and writes its result (a string) as text to the result tree. The expression is «. » , which returns the string value of the current node, that is the textual content of the current <author> , <price> , or <title> element.

This template makes no further call on <xsl : apply-templates> , so its own children are not processed, and control returns all the way up.

Output

  <html>   <body>   <h1>A list of books</h1>   <table width="640">   <tr>   <td>1</td>   <td>Nigel Rees</td>   <td>Sayings of the Century</td>   <td>8.95</td>   </tr>   <tr>   <td>2</td>   <td>Evelyn Waugh</td>   <td>Sword of Honour</td>   <td>12.99</td>   </tr>   etc..   </table>   </body>   </html>  

This style of processing is called push processing. It is driven by the <xsl:apply-templates> instruction, as if the processor is pushing the nodes out of the door, saying "is anyone interested in dealing with this one?"

In this description I occasionally talk of instructions writing to the result tree. This is how the process was described in XSLT 1.0, and it accounts for the name push. It's a convenient way to think about what's going on. Technically, as we have seen, instructions don't write to the result tree; they are evaluated to produce a sequence (usually a sequence of nodes, but occasionally atomic values) and this sequence is then used by the calling instruction, often to construct the children of a new element. The importance of this model is that in XSLT 2.0, there are some situations in which the result of a sequence constructor is not used directly to build part of a result tree, but can be used in some other way, for example as the result of an XPath function call.

In such situations it is possible for an XPath expression to encounter nodes such as attributes and text nodes that have no parent, because they have not yet been attached to a result tree.

Controlling Which Nodes to Process

Simple push processing works very well when the data in the output is to have the same structure and sequence as the data in the input, and all we want to do is add or remove a few tags or perform other simple editing of values as we go along.

In the previous example, it wouldn't work so well if the properties of each book were less predictable, for example if some of the books had no price, or if the title and author could appear in either order. In this case the HTML table that we generated wouldn't be nicely arranged in columns any more, because generating a new cell for each property we encounter is not necessarily the right thing to do.

In such circumstances, there are two choices:

  • Be more precise about which nodes to process, rather than just saying process all children of the current node.

  • Be more precise about how to process them, rather than just saying choose the best-fit template rule.

Let's try the first option.

Controlling the Sequence of Processing
start example

We can gain greater control over which nodes are to be processed by changing the <book> template in books.xsl , as follows.

  <xsl:template match="book">   <tr>   <td><xsl:number/></td>   <xsl:apply-templates select="author, title, price"/>   </tr>   </xsl:template>  

Instead of selecting all child elements and finding the appropriate template rule for each one, this now explicitly selects first the <author> child element, then the <title> child element, and then the <price> child element.

This will still work, and it's more robust than our previous attempt, but it will still produce a ragged table if there are any <book> elements without an <author> (say), or with more than one.

The comma operator used in the expression «select="author , title , price" » is new in XPath 2.0. It simply concatenates several sequences (which might be single items, but could also be empty, or contain multiple items) into a single sequence, in the order specified.

end example
 

As we want a regular structure in the output and because we know a lot about the structure of the source document, we'd probably be better off in this situation defining all the processing in the <book> template rather than relying on template rules to match each of its child elements.

Selecting Nodes Explicitly
start example

We can gain greater control over how nodes are to be processed by writing the <book> template rule in the following manner.

  <xsl:template match="book">   <tr>   <td><xsl:number/></td>   <td><xsl:value-of select="author"/></td>   <td><xsl:value-of select="title"/></td>   <td><xsl:value-of select="price"/></td>   </tr>   </xsl:template>  

Some people call this pull processing, because instead of the template pushing nodes out of the door to be picked up by another template, it is pulling the nodes in and handling them itself.

end example
 

The pattern-matching (or push) style of processing is the most characteristic feature of XSLT, and it works very well in applications where it makes sense to describe the handling of each type of node in the source document independently. However, there are many other techniques available, all of which are equally valuable . From within a template rule that is processing one particular node, the main alternatives if you want access to information in other nodes are as follows:

  • Call <xsl:apply-templates> to process those nodes using their appropriate template rules.

  • Call <xsl:apply-templates> in a particular mode (see later) to process those nodes using the template rules for the relevant mode.

  • Call <xsl:value-of> to extract the required information from the nodes directly.

  • Call <xsl:for-each> to perform explicit processing of each of the nodes in turn.

  • Call <xsl:call-template> to invoke a specific template by name, rather than relying on pattern matching to decide which template to invoke.

Further discussion of the different approaches to writing a stylesheet is included in Chapter 9, "Stylesheet Design Patterns."

Modes

Sometimes you want to process the same node in the source tree more than once, in different ways. The classic example is to produce a table of contents. When generating the table of contents, you want to handle all the section headings in one way, and when producing the body of the document, you want to handle them in a different way.

One way around this problem is to use push processing on one of these passes through the data, and pull processing on all the other occasions. However, this could be very constraining. Instead, you can define different modes of processing, one for each pass through the data. You can name the mode of processing when you call <xsl:apply-templates> , and the only template rules that will be considered are those that specify the same mode. For example, if you specify:

  <xsl:apply-templates select="heading-1" mode="table-of-contents"/>  

Then the selected template rule might be one defined as:

  <xsl:template match="heading-1" mode="table-of-contents">   ...   </xsl:template>  

Further details of how to use modes are in Chapter 5, page 194 and an example of how to use them to generate a table of contents is in Chapter 10, page 661.

Built-In Template Rules

What happens when <xsl:apply-templates> is invoked to process a node, and there is no template rule in the stylesheet that matches that node?

A built-in template rule is invoked.

There is a built-in template rule for each kind of node. The built-in rules work as follows.

Node Kind

Built-In Template Rule

Document

Call <xsl:apply-templates> to process the children of the document node, in the same mode as the calling mode

Element

Call <xsl:apply-templates> to process the children of this element, in the same mode as the calling mode

Attribute

Copy the attribute value to the result tree, as text-not as an attribute node

Text

Copy the text to the result tree

Comment

Do nothing

Processing instruction

Do nothing

Namespace

Do nothing

The built-in template rules will only be invoked if there is no rule that matches the node anywhere in the stylesheet.

There is no way to override the built-in template for namespace nodes, because there is no pattern that will match a namespace node. If you call <xsl:apply-templates> to process namespace nodes, nothing happens. If you want to process all the namespace nodes for an element, use:

  <xsl:for-each select="namespace::*">  

Conflict Resolution Policy

Conversely, what happens when there is more than one template rule whose pattern matches a particular node? As I mentioned earlier, the conflict resolution policy comes into play.

This works as follows:

  • First the import precedence of each rule is considered. As Chapter 3 will show, one stylesheet may import another, using the <xsl:import> declaration, and this part of the policy basically says that when stylesheet A imports stylesheet B, the rules in A take precedence over the rules in B.

  • Then the priority of each rule is examined. The priority is a numeric value, and the higher the number, the higher the priority. You can either specify the priority explicitly in the priority attribute of the <xsl:template> element, or leave the system to allocate a default priority. In this case, the system allocates a priority that is designed to reflect whether the pattern is very general or very specific: for example the pattern «subsection/title » (which matches any <title> element whose parent is a <subsection> element) gets higher priority than the pattern «* » , which matches any element. System-allocated priorities are always in the range -0.5 to +0.5: user-allocated priorities will normally be 1 or more, but there are no restrictions. For more details see the description of the <xsl:template> element in Chapter 5, page 450.

  • Finally, if there is more than one rule with the same import precedence and priority, the XSLT processor has a choice: it can either report an error, or choose whichever rule appears last in the stylesheet (some processors do both: they give you a warning, and then carry on processing). Different processors will behave differently in this situation, which gives you a slight portability problem to watch out for: it is best to ensure this ambiguity never happens, which you can achieve by setting explicit priorities on your template rules.




XSLT 2.0 Programmer's Reference
NetBeansв„ў IDE Field Guide: Developing Desktop, Web, Enterprise, and Mobile Applications (2nd Edition)
ISBN: 764569090
EAN: 2147483647
Year: 2003
Pages: 324

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net