Yesterday you learned all about using templates, that they are key to Extensible Stylesheet Language Transformations (XSLT), and that they can either be explicitly called or matched by the processor. When templates are being matched, multiple templates may match the current node. You have learned how to control which template is actually matched when this situation occurs, enabling you to control the output that is actually generated.
In today’s lesson, you will learn more details about inserting text and elements into the resulting output. You will learn how to do the following:
• Insert text with special characters
• Insert elements and attributes into the XML result
• Insert elements and attributes with a generated name
• Copy elements from the source XML into the result
As you learned in previous lessons, inserting text is easy. In a template, you specify the text you want, and it is then inserted each time the template is processed. When you want to insert the value from an element or attribute in the source XML document into the result, you can use the xsl:value-of
element to specify which value you want to insert.
You may be wondering why this section is devoted entirely to inserting text if the procedure is so simple. Well, I included this discussion because the text inserted and the values in elements and attributes have been plain in the previous samples. I specifically avoided special characters that might cause problems in those samples. Because you will most certainly encounter situations in which you need to work with characters such as é, ë, ê, and so on, a closer look is in order.
NEW TERM
Unless you specify otherwise, a stylesheet will generate XML. In XML, and thus in XSLT, some characters need to be treated differently. They are called special characters
. Generally, special characters are a problem when a document is processed—either because of the encoding used or because these characters have a special function within the document (for example, tag delimiters).
NEW TERM
To use special characters in a value (in text), you need to use output escaping. Characters are said to be output escaped when they are replaced by a series of characters that represent them. You use them if you want to insert those characters without their performing the function they have within the document, or when those characters are not supported by the encoding used and hence need to be represented in some other way.
Output escaping is common in HTML documents because these documents are based on ASCII encoding, which supports only 256 characters. Many characters used in different languages are not among those 256 characters, so to represent them, you need to use some kind of alternative encoding. Because XML can be based on many encoding schemes, including Unicode, XML by default requires only minimal output escaping. In Unicode, most common international characters can be inserted as is, so you don’t need to replace characters such as é, ë, and ê with other characters to represent them. If your policy is to always output escape these kinds of characters, you are certainly allowed to do so.
NEW TERM
In XML, output escaping works on the basis of entities. An entity is a name that represents a character or series of characters. It can be used as a replacement for a special character or as a shortcut to insert a value (for example, a copyright notice).
By default, XML defines only five entities, which replace characters within XML that have a special function. Table 5.1 shows the characters for which entities have been defined in XML.
NEW TERM
Of the entities in Table 5.1, only the first two always must be used. The &
entity always denotes the start of an entity that is being inserted, including the one replacing it. The <
entity always denotes the start of an XML tag, so it can never be used in regular text. You must use the other three entities only when the processor may interpret a character’s presence as performing the function it has in XML rather than being part of the text. If, at that point, you want to insert that character in the text, you need to insert the entity. When the actual character’s presence cannot be misinterpreted, you can insert that character as is, as shown in Listing 5.1.
Note
You can download the sample listings in this lesson from the publisher’s Web site.
Listing 5.1 contains quite a mix of escaped characters. Where possible, the characters are inserted as is. For the values of the elements on lines 3–4, using entities instead of the actual characters is mandatory. Not doing so would result in an error. For the quote character on line 6, you can use either the quote character within an element value or use the corresponding entity. Because the element’s attribute on line 6 uses the quote character to delimit the value, the quote entity is needed to insert the actual character in the value. For the apostrophe character, this use is similar, as shown on lines 7–8. The > character also doesn’t need to be output escaped, except when it is within an attribute value. Otherwise, it could be mistaken for the element tag’s ending. The characters on lines 11–13 don’t need to be escaped, but you can choose to do so.
If you look at the code for Listing 5.1 in an XML-enabled viewer, such as Internet Explorer 5.0 or higher, you can see that the output-escaped characters actually appear as the characters themselves, as shown in Figure 5.1.
HTML Entities
If you’re familiar with HTML, you may have noticed that entities such as
(non-breaking space) are no longer defined. Actually, inserting such an entity by itself results in an error. For
you should use  
instead. The five built-in entities in XML will be properly processed by all parsers on all platforms. You can extend entities either by using numerical codes or by creating your own with a DTD.
You can find a complete list of the entities defined in HTML 4.0 at <http://www.w3.org/TR/REC-html40/sgml/entities.html
. For each entity listed, the equivalent number code also is given. These number codes, which correspond to the number codes in Unicode, can be used in XML, as can all other Unicode number codes.
Another option is to create a Document Type Definition (DTD) that defines these entities and use that DTD when you’re creating documents and stylesheets in which you want to use these entities.
Note
Defining entities with DTDs is beyond the scope of this book. Using DTDs is discussed further on Day 15, “Working with Namespaces.”
The bottom line from the preceding discussion is that XML can contain special characters, but some characters have to be output escaped because of their function in XML. The question that now arises is “How does XSLT deal with these characters?” To answer this question, look at Listing 5.2.
Listing 5.2 contains several templates that could be used with Listing 5.1. In the templates, some characters are output escaped, but others aren’t just to show you that you can mix up the characters when it doesn’t matter whether you use output escaping. In the template starting on line 13, one of the quote characters is output escaped; the other is not. Also, the >
that starts the template’s value is not output escaped. It can be used this way because it is in a position where the parser does not expect a >
character to perform a function (ending a tag). The <
character ending the value needs to be output escaped, however, if you don’t want the parser to mistake it for the start of a tag.
Listing 5.3 shows the result of applying Listing 5.2 to Listing 5.1.
OUTPUT
In Listing 5.3, most output-escaped characters are replaced by their actual characters. The reason for this conversion has already been hinted at in Figure 5.1. When the parser loads the XML, the characters it can handle without their being output escaped are immediately converted to the characters themselves. In effect, after the XML is loaded, you cannot tell whether the characters were output escaped. This is why in XSLT you cannot determine whether a character in the source XML was output escaped.
Note
If you apply Listing 5.2 to Listing 5.1 from the command prompt or console, the output looks a little different because the command prompt doesn’t have the means to display some of the characters. If you save the result to a file and view that file in a text editor that supports these characters, the characters are displayed as they should be.
When the output is created, the processor outputs all the characters conforming to the output encoding used (in this case, UTF-8), regardless of the output escaping used in the source XML or stylesheet. If the processor determines that a character does need to be output escaped, it outputs the character by itself, also regardless of the way the character appeared in the input. Refer to line 10 of Listing 5.1 and the output generated from that line with the stylesheet, which appears on line 24 of Listing 5.3. As you can see, the processor automatically converts the >
character to its entity.
As long as your XML source and stylesheets are output escaped properly, you don’t need to worry about what the resulting output will look like from an output-escaping point of view. When you’re creating XML output, the processor ensures that the output is encoded and output escaped as it should be. When you create other forms of output, you may have to be more careful, however.
Note
On Day 7, “Controlling the Output,” different output types will be discussed further.
I have been saying that the samples in this book produce XML output. Strictly speaking, this is true because all the output is preceded by an XML prolog, and all characters conform to XML encoding and output escaping. You may have noticed that none of the results contain tags; they contain only text. The output created therefore is not well-formed XML because well-formed XML documents need to have at least a root element.
Values in the document must exist inside that root element; otherwise, the document is not valid. So, to create valid XML documents, you need to be able to insert elements.
Like inserting text, inserting elements is straightforward. You can insert elements anywhere within a template, as long as you use well formed XML (if it isn’t, the stylesheet itself will not be well formed XML). If you want to insert elements with a namespace, that namespace needs to be declared within the stylesheet.
Note
On Day 15, “Working with Namespaces,” inserting elements with a name-space will be discussed thoroughly.
Inserting elements in the output is required if you want the output to be XML or HTML. If you restructure your source document or if you format the source document for display on the Web, this is the case. When you’re transforming elements to HTML, for instance, you may want to insert hyperlinks, text in boldface, and so on.
The best way to show how easily you can insert elements is by example. The first thing you need is an XML document to be transformed. The document used in Listing 5.4 comes from yesterday’s lesson.
Now you need a stylesheet to transform Listing 5.4 and add some elements. Listing 5.5 shows such a stylesheet.
ANALYSIS
The stylesheet in Listing 5.5 creates an HTML table containing all the information on the cars stored in Listing 5.4. For each car
element, a row is created in the table. The cars
template starting online 9 creates the start tag of the table
element and then uses the xsl:apply-templates element to invoke other templates
for each child element of the cars
element. When that has been done, the end tag of the table
element is inserted onine 12. The car
template starting online 15 is invoked several times, for each car
element in Listing 5.4. This template inserts a table row starting tag online 16, and the closing tag online 18. In between, it invokes the processor for all its attributes. For each attribute, a table cell is created by the template starting online 21, which also inserts the value of the attribute. When you apply Listing 5.5 to Listing 5.4, you get the result shown in Listing 5.6.
OUTPUT
If you open Listing 5.6 as an HTML file in a browser, you get a neat table with cars.
Technically, Listing 5.6 is XML. However, because the entire document conforms to the rules of HTML, you can save it as an HTML file and view it in a Web browser.
ANALYSIS
The stylesheet in Listing 5.5 could also have created non-HTML tags. In that case, Listing 5.6 would look different, but it would have been well-formed XML as well. Nothing restricts you to using only HTML tags. I chose to generate HTML tags to give you a practical example that might occur in the real world. I created the HTML tags in such a way that the result is well-formed XML as well. Therefore, you can load the result into a viewer or parser without generating an error. Some HTML tags are not well-formed XML, such as <br>
and <input>
. If you want to insert such tags, you need to make them well formed—for instance, <br><br>
or <input />
. If you don’t, the
stylesheet itself is not well-formed XML, so an error occurs when you try to use it. When these tags are sent to the output as well-formed XML, they may not always appear correctly in a Web browser.
Note
You’ll learn how to create correct HTML output on Day 7, “Controlling the Output.”
Creating a Different XML Structure
Listing 5.4 contains car
elements, with the values stored in attributes. Yesterday you saw a listing with the same information, but stored in child elements. You created a stylesheet to generate the same output for both structures. Another option is to restructure one of the documents so that it uses the same structure as the other. The stylesheet in Listing 5.7 does exactly that.
ANALYSIS
Listing 5.7 isn’t very different from Listing 5.5. The cars
template on line 9 inserts a cars
element instead of a table
element, and the car
template on line 15 inserts a car
element instead of a tr
element. The major difference between Listings 5.7 and 5.5 is the way the car
element’s attributes are handled. In Listing 5.5, all attributes are handled by the same template, which inserts a td
element and the value of the attribute being processed. In Listing 5.7, each attribute is handled by a different template, to see to it that the newly created elements have the same name as the attribute in the source XML. When you apply Listing 5.7 to Listing 5.4, you get the results shown in Listing 5.8.
OUTPUT
In Listing 5.8, the result contains all attributes from Listing 5.4 as elements. Although Listing 5.8 isn’t as neatly formatted as Listing 4.14 in yesterday’s lesson, they are syntactically and semantically identical. When the documents are loaded into a parser, the resulting XML document tree is the same for all intents and purposes.
Inserting Elements with a Generated Name
Earlier you learned how to insert elements literally into a stylesheet. This approach makes it easy to insert elements. You also can use another method to insert elements. This method uses xsl:element
to insert elements. Using this XSLT element, you could write
xsl:element name=”model”>Focus</xsl:element>
instead of
<model>Focus</model>
Using this method, as shown in Listing 5.9, you could also achieve the result in Listing 5.6.
Listings 5.5 and 5.9 are nearly identical. In Listing 5.5, the elements are literally inserted; in this listing, the xsl:element
element is used on lines 10, 16, and 22 to insert the elements. The result is identical. Writing the elements into the stylesheet literally is a shortcut for the method used in Listing 5.9
You might be wondering why you would use xsl:element
instead of inserting the elements literally. In the preceding situation, using xsl:element
is indeed unnecessary. The code is easier to create and easier to read when you just insert the elements literally. The situation becomes different when you want to create elements in which the element names can be determined only at runtime. Literal elements have to be determined at design time rather than runtime, so inserting elements literally is not a possibility. You might be able to create templates with very complex match expressions to have more diversity in the elements you create, but the more complex the source XML processed becomes, the harder it becomes to deal with all the possibilities.
To get around the drawback of not being able to create elements dynamically at runtime, you can use xsl:element
because the value of the name
attribute of xsl:element
can be determined at runtime using XPath expressions. This means that you can create elements that have a name given as a value in the source XML. Listing 5.10 shows how this technique works.
Applying Listing 5.10 to Listing 5.4 yields the result in Listing 5.11.
OUTPUT
ANALYSIS
Listing 5.11 shows a list of car model years. You create the elements with the year value by using the xsl:element
tag, as shown on line 16 in Listing 5.10. Line 17 inserts the corresponding year. The result is that each element’s name corresponds to the value of each car’s model
attribute in Listing 5.4. Instead of using a literal value for the xsl:element
tag’s name
attribute, you use an expression. You can see that it is an expression because of the curly braces surrounding the expression @model
. Instead of creating elements like <{@model}>
, the curly braces and expression are replaced with the value of the expression by the processor.
The expression on line 16 in Listing 5.10 is simple. You can make it more complex, getting a value from an entirely different part of the source XML. Also, you can mix expressions and literal text in the value of the name
attribute, as shown in Listing 5.12.
ANALYSIS
You can use the template in Listing 5.12 instead of the car
template starting on line 15 in Listing 5.10. The value of the name
attribute on line 2 in this listing contains two expressions surrounded by curly braces, with some literal text in between. If you apply the complete stylesheet of Listing 5.12 to Listing 5.4, the result is similar to Listing 5.13
OUTPUT
ANALYSIS
In Listing 5.13, the text and expressions comprising the value of the name
attribute on line 2 of Listing 5.12 create elements with names that consist of the values of the manufacturer
and model
attributes, with a hyphen (-
) in between. As long as the resulting element name is valid in XML, any combination of expressions and literal values is fine.
In Listing 5.7, each attribute had to be handled by a different template to restructure the document. If you could use the attribute’s name to create an element, that approach would not have been necessary. The XPath function name ()
comes into play here. This function gives the name of the context node. Listing 5.14 shows it in action.
When Listing 5.14 is applied to Listing 5.4, the result is the same as Listing 5.8. This stylesheet, however, requires a lot less code than the one in Listing 5.7. In Listing 5.14, all the attributes are matched by the template that starts on line 21. Using the name ()
function, this template creates a new element with the name of the context node on line 22. In each case, this name is the name of the attribute. The value of the attribute becomes the value of the newly created element. The templates in lines 5, 9, and 15 all perform functions discussed earlier.
Using the method from Listing 5.14, you can actually create a stylesheet that works on every XML document that has attributes and convert that document so that it uses only elements. If you apply that same stylesheet to an XML document that has no attributes, the output is the same as the source document. The code to convert attributes is remarkably simple; it’s shown in Listing 5.15.
ANALYSIS
The template that starts on line 5 in Listing 5.15 will match any element in the document because it uses a wildcard. When it is invoked, it creates an element with the same name as the element for which the template is invoked, the context node. Then xsl:apply-templates
invokes the processor for each attribute of that element. The template that starts on line 12 will match all these attributes because the attribute wildcard expression matches any attribute. This template creates an element with the name of the attribute being processed and gives it the value of that same attribute. After all the attributes are processed, control reverts to the template on line 5, which then invokes the processor for all child elements. These elements are either matched by the template itself or by the template starting on line 18, which just writes the value to the output.
As you can see, Listing 5.15 does not contain a template that matches the root element of the source document. Because of the built-in template rule, such a template isn’t necessary.
Inserting attributes isn’t much different from inserting elements. If you insert elements literally, you can add attributes literally as well. Listing 5.16 shows how to do so.
LISTING 5.16 Partial Stylesheet Inserting Literal Attributes
ANALYSIS
The templates in Listing 5.16 are replacements for the cars
and car
templates on lines 9 and 15 in Listing 5.5. On line 2 of Listing 5.16, two attributes are added to the table
element that line 1’s template inserts. On line 8, the tr
element now has a bgcolor
attribute. The result is that each time these templates are invoked, the attributes are inserted along with the elements, as you can see in the result in Listing 5.17.
OUTPUT
Figure 5.2 shows what Listing 5.17 looks like when you save it as an HTML file and view it in Internet Explorer 5.
FIGURE 5.2 Screenshot of Listing 5.17 viewed in Internet Explorer 5.
Earlier you learned that you can insert elements with a name generated with an expression. You can do the same with attributes by using xsl:attribute
. This element’s name
attribute gives the created attribute its name. Just as with xsl:element
, this can be literal text, an expression, or a mix of literal text and expressions. Listing 5.18 shows an example with literal text; this example is equivalent to Listing 5.16.
LISTING 5.18 Partial Stylesheet Inserting Literal Attributes
In Listing 5.18, the attributes that were inserted literally in Listing 5.16 have been replaced by xsl:attribute
elements on lines 3, 4, and 11. The value of the name
attribute of the xsl:attribute
element is the name used literally in Listing 5.16. The value of the created attribute is given in between the tags of the xsl:attribute
element. The result of Listing 5.18 applied to Listing 5.4 would be identical to Listing 5.17 because Listings 5.16 and 5.18 are the same as far as the processor is concerned.
Earlier you looked at some samples that converted Listing 5.4 into an XML document with only elements, as shown in Listing 5.8. With the xsl:attribute
element, you also can perform this process in reverse, converting Listing 5.8 into Listing 5.4. Listing 5.19 shows a stylesheet that does this.
Note
You should realize by now that there is nearly always more than one way to get the same result. Throughout this book, the samples are used to explain a specific function, but they may not show the most efficient way to perform a task.
The template that actually converts attributes to elements starts on line 20. It matches any element, but the cars
and car
elements are overridden by the templates on lines 9 and 14, respectively. The match expression for the template on line 20 could also have been model|manufacturer|year
, but then any other child elements of the car
element would not be converted, as well as any child elements with different names elsewhere in the document tree. The template creates a new attribute each time it is invoked, with the name and value of the context element.
As you can see from Listing 5.19, the xsl:attribute
element doesn’t necessarily have to be a child element of some element being created. It can exist inside a matched or called template. The attribute is then added to the element that is being created from another template—the car
element in Listing 5.19. This capability is useful when you need to create multiple related attributes. You can create a named template that inserts the attributes you need, as shown in Listing 5.20.
ANALYSIS
In Listing 5.20, the two named templates defined on lines 27 and 32 add attributes with properties for HTML table
elements and tr
(row) elements, hence their names tableprop
and rowprop
. The former is called from line 11 in the cars template, which inserts a table
element and then adds its attributes using the named template. The rowprop
template is called from line 18 in the car element, which adds a table row for each car. If you apply Listing 5.20 to Listing 5.4, the result is similar to Listing 5.17.
In Listing 5.20, it doesn’t make much difference if the attributes are inserted using named templates because no other templates call the named templates. So, creating those templates is actually overkill. If multiple templates create elements with identical attributes, using this method would be effective for keeping the attributes in a central place so that they can be edited there if they need to change for all the elements.
NEW TERM
If you want to insert multiple literal attributes along with an element, using a named (or matched) template is not the only solution. Within a stylesheet, you can define a set of attributes that can be inserted with an element. This set of attributes is appropriately named an attribute-set and can be defined using the xsl:attribute-set
element. You can then insert it by using the use-attribute-set
attribute with xsl:element
, as shown in Listing 5.21.
ANALYSIS
When you apply Listing 5.21 to Listing 5.4, the result is like Listing 5.17. As you can see on lines 13–20, two attribute-sets are defined, similar to the named templates in Listing 5.20. Apart from the fact that they define an attribute-set, not a template, the code is similar. How the attributes are inserted differs more, however. On line 2, the tableprop
attribute-set is added using the use-attribute-sets
attribute. The same goes for the rowprop
attribute-set, which is used on line 8 as part of the tr
element’s definition.
Attribute-sets are flexible. You can employ several methods to use multiple attribute-sets. The easiest way to use them is to specify multiple attribute-sets as a value of the use-attribute-sets
attribute, separated by whitespace. Listing 5.22 shows a sample.
ANALYSIS
In Listing 5.22, the tableprop
attribute-set from Listing 5.21 is replaced by two attribute-sets, border
and width
, defined on lines 6 and 10. On line 2, the value of use-attribute-sets
now contains both these attribute-sets separated by a space. If you apply this stylesheet to Listing 5.4, you again end up with the results shown in Listing 5.17.
The use-attribute-sets
attribute is not limited to use with xsl:element
. You can, in fact, create an attribute-set with this attribute, in the process creating an attribute-set that consists of all the attribute-sets listed. This is yet another way to replace the tableprop
attribute-set in Listing 5.21, as shown in Listing 5.23.
ANALYSIS
In Listing 5.23, a tableprop
attribute-set is defined; it uses use-attribute-sets
to “import” the border
attribute-set. An attribute also is added, so the result is basically the same as the tableprop
attribute-set in Listing 5.21. It is not surprising that the result of Listing 5.23 is the same as the result from Listing 5.21; this result is shown in Listing 5.17.
NEW TERM
Because you can nest attribute-sets as shown, you can create an elaborate structure of attribute-sets, referring to one another. This capability is useful in situations in which you are creating HTML or XSLFO output with elaborate formatting. You need to be careful, however, that you don’t have a circular reference, which occurs when element A refers to element B, which refers back to element A, thus creating a never-ending loop. Circular references can also occur with more elements.
In some cases, copying elements from the source document into the result without altering them might be useful. In some of the sample listings earlier in this lesson, I did that by re-creating the element or elements in question. A better way to do that is to use other elements, as described in the following sections.
NEW TERM
The xsl:copy
element copies the context node from the source to the result. This is called shallow copy, so if you want to copy attributes or child elements, you need to explicitly code for this type of copying. Shallow copy means that only the context node is copied. Any attributes or child nodes the node may have are not copied along with the node.
ANALYSIS
In Listing 5.24, the xsl:copy
element is used in two different ways. The first one has an opening tag on line 10 and a closing tag on line 12. This method effectively creates opening and closing tags for the cars
element because it is the context node. The element’s value is determined by the result from the xsl:apply-templates element on line 11. The xsl:copy
element on line 16 makes a copy of each car
element for which the template is invoked. Be aware that this method creates only an empty car
element, without any of the attributes. The big difference between the two different xsl:copy
elements in Listing 5.24 is that the value of the element created on line 10 is added specifically. If that isn’t done, which is the case on line 16, then the element is empty. You can clearly see this result in Listing 5.25.
OUTPUT
The xsl:copy
element supports more or less the same functions that xsl:element
and xsl:attribute
elements offer. You can add child elements and attributes just as you would with the latter two, and you also can use the use-attribute-sets
attribute to add attributes. Because I thoroughly discussed these features with xsl:element
, I will not discuss them any further. Listing 5.26 shows a sample combining xsl:copy
with uses-attribute-sets
. Listing 5.27 shows the result from applying Listing 5.26 to Listing 5.4.
ANALYSIS
In Listing 5.26, an attribute-set is defined on line 7. The xsl:copy
element on line 2 uses this attribute-set. In addition, line 3 adds another attribute named model
.
OUTPUT
ANALYSIS
The order in which the attributes appear in Listing 5.27 is deliberate. Any attribute-sets are processed first, in the order in which they are added, and then other attribute definitions are inserted. If an attribute is defined more than once, the last one added is the one sent to the output.
NEW TERM
The xsl:copy
element is useful, but it operates only on the context node and copies only the context node, without any of the attributes or child elements. Although you can get around both deficiencies by creating several templates, another element can copy based on an XPath expression and performs deep copy, which is the opposite of shallow copy. In this type of copy, the selected node or node-set and all attributes and descendant elements are copied. In effect, the entire tree fragment under the node or under each node in the selected node-set is copied to the output.
You use the xsl:copy-of
element to perform a deep copy. Unlike the xsl:copy
element, this element is always empty and has a mandatory select
attribute. The select
attribute’s value must be a valid XPath expression selecting a node or node-set. Listing 5.28 shows a simple usage of xsl:copy-of
.
ANALYSIS
Line 10 in Listing 5.28 selects the context node and copies it to the output, including all its attributes and descendant elements. Because the context node is the cars
element, which is effectively the root element, the entire document is copied to the output. So, if you apply Listing 5.28 to Listing 5.4, the result is the same as Listing 5.4. Because xsl:copy-of
is used in the template matching the cars
element, only a fragment of the document is copied to the output if the cars
element is not the root element of the source document.
If the select expression yields a node-set, for each node in the node-set, the entire tree fragment is copied. This goes for any node-set, even node-sets composed of nodes from different sections in the tree. As such, the node-set should be used with care because you may end up copying many elements you aren’t supposed to. Listing 5.29 shows a replacement template for the template on line 9 of Listing 5.28. The template in Listing 5.29 copies a node-set of two cars.
The result from applying Listing 5.28 with the changes from Listing 5.29 to Listing 5.4 is shown in Listing 5.30.
OUTPUT
ANALYSIS
As you can see in Listing 5.30, Listing 5.29 copies only the first and third car
elements from Listing 5.4. It does, however, copy them with all their attributes.
Using both the xsl:copy
and xsl:copy-of
elements, you can copy large parts of documents very selectively. The xsl:copy
element requires more work than the xsl:copy-of
element, but it gives you more control over the output.
Comments and processing instructions perform a special function in an XML document. Comments are mostly meant for a human reader, telling him or her what is going on in a document. In HTML, comments may also serve to let older browsers ignore a piece of code that they will not understand, such as JavaScript code. Processing instructions are the opposite of comments. They are not meant for the reader; instead, they are instructions for the program reading the XML document. For instance, in XML, a processing instruction is used to attach a stylesheet to an XML document, so if it is viewed by an XML/XSLT-enabled viewer, the viewer will apply the stylesheet automatically. CSS documents are attached to HTML documents the same way.
Because comments are not actually part of the XML structure, you can insert them almost anywhere in a document. They can appear at the start or end of a document, beyond the root element of the document, and anywhere a text value is also possible. This does mean that you can’t insert a comment within a start or end tag.
You can insert a comment by using the xsl:comment
element. This element has no attributes, and the element value is output as the comment. Now consider this example:
<xsl:comment>This is a comment</xsl:comment>
In XML or HTML output, this code results in the following being inserted into the output at the location the comment was inserted:
<!--This is a comment-->
The <!--
character sequence denotes the start of a comment; the -->
sequence, the end, just like start and end tags of an XML element. Because of this, it is not legal to have --
in the comment itself; using these characters would result in an error.
Comments are very useful when you’re debugging a stylesheet. For instance, inserting a comment at the start of each template shows you exactly which templates are matched for a source document. Because the comments don’t interfere with the XML, you can use the reulting XML in other applications just as before. Listing 5.31 shows Listing 5.24 with debugging comments.
ANALYSIS
Lines 6, 11, and 18 of Listing 5.31 insert a comment when the templates on lines 5, 10, and 17 are invoked. This way, you get a complete record of which templates are matched and in what sequence. The result is shown in Listing 5.32.
ANALYSIS
On line 1 of Listing 5.32, you can see that the root template is matched first and only once. Then the cars
template is matched, followed by a match of the car
template for each car element in Listing 5.4. The comments show all this clearly, but you can still use this document as if it is the result in Listing 5.25.
A comment doesn’t have to contain literal text. You can use XSLT elements such as xsl:value-of
to create the value. This allows you to see which element is being operated on or to provide other useful information.
OUTPUT
ANALYSIS
A processing instruction is used to give a program reading a document additional information on how to process the document. These instructions can be very specific and program/vendor-related instructions or common instructions, such as attaching a stylesheet to an XML or HTML file. Because processing instructions often have bearing on the entire document, they should be inserted at the start of a document. Processing instructions are not widely used in XML, but in HTML, they are more common. It is therefore good to know how to insert them.
Inserting a processing instruction is just as easy as inserting an element, except that you insert a processing instruction with the xsl:processing-instruction
element. Like xsl:element
, this element has a mandatory name
attribute used to identify the processing instruction. The element value is used as the value of the processing instruction. Listing 5.33 shows a sample using a processing instruction.
ANALYSIS
On line 6 of Listing 5.33, a processing instruction is inserted to attach Listing 5.5 to it as a stylesheet. The name given to the processing instruction is therefore xml-stylesheet
. The value links to the file containing Listing 5.5 and specifies that that file is XML. This is just like the processing instruction used on Day 2, “Transforming Your First XML,” to attach a stylesheet to an XML source. Line 7 copies the entire document in Listing 5.4 to the output, so the result is as shown in Listing 5.34.
OUTPUT
ANALYSIS
Listing 5.34 displays the same document as Listing 5.4. The difference is in the first line, which contains a processing instruction attaching Listing 5.5 to it. If you viewed Listing 5.34 in an XML/XSLT enabled browser, it would appear as Listing 5.6 displayed in a browser.
Today you learned all about inserting text, elements, and attributes. Although most methods are fairly easy, you can choose from many methods. If you need to insert literal elements and attributes, the easiest way is to write them in the stylesheet as they should appear. When they need to be generated from data in the source document, you use xsl:element
and xsl:attribute
.
You can quickly add sets of elements and attributes using named (or matched) templates. If you need to insert sets of attributes, you have the option of using the use-attribute-sets
attribute to specify sets of predefined attributes that need to be inserted. Attribute-sets can be created from other attribute-sets, so you can create quick and easy inserts that actually insert a complex set of attributes. If two attributes inserted for an element are the same, the one defined last prevails.
Tomorrow you will learn more details about taking action based on elements or attributes in the source document. This way, you can insert elements and text even more selectively.
Q I have seen several methods to insert elements and attributes. Which is best?
A There is not really a best way to insert elements and attributes. The XSLT specification does not include any implementation details for the processors, so different processors use different implementations with different performance characteristics. Go with what works for you.
Q Why doesn’t xsl:copy-of
support attribute-sets?
A Suppose you copy a large tree fragment. In this case, attributes are added to all elements in the tree fragment. The likelihood that you would want this result is very small. When you need this result, you can create a named template to add the attributes.
Q Does xsl:copy-of
have to operate on the context node?
A Certainly not. The select
attribute can contain an expression that selects any node or node-set. It does not have to be the context node or relative to the context node.
This workshop tests whether you understand all the concepts you learned today. It is very helpful to know and understand the answers before starting tomorrow’s lesson. You can find the answers to the quiz questions and exercises in Appendix A.
1. True or False: For an XSLT processor, there is a difference between inserting characters as is and using output escaping.
2. True or False: You can use xsl:attribute
only to create attributes for an element created with xsl:element
.
3. What is the purpose of the XPath function name ()
?
4. What is the difference between shallow copy and deep copy?
5. Is there a difference between <xsl:element name=”{name ()}” />
and <xsl:copy />?
1. Create a stylesheet for Listing 5.4 to create the output from Listing 5.8, but use xsl:copy
and xsl:element
where possible.
5
3.145.51.153