So far you have seen basic templates and how to call them. The only results so far have used literal result elements (such as the HTML markup used within the templates) to show a few examples of the xsl:value-ofelement. This element is part of XSLT and will help you write rich style sheets. The following sections will explore some of the more commonly used ele- ments and demonstrate how to use them.
Creating Nodes
You can create nodes in the transformed tree literally, as you have seen in the examples. The HTML tags used within the templates demonstrate this. When transformed, these nodes are automatically created within the result tree. Using the XSLT language, it is also possible to cre- ate nodes dynamically. This means node names and values do not need to be hard-coded within a template but can be created based on some criteria. I will now explain how to create different nodes and show examples of using the XSL elements for performing these operations.
Attribute Value Templates
Within many of the XSL elements that follow, some of the attribute values of the defining ele- ment are interpreted as attribute value templates, which allow the use of expressions. Curly braces surround expressions that are to be evaluated within the attribute value and look like {expression}. For example, to generate the local name of the current node in context along with the value of an attribute named numfrom the current node, the attribute value template would look like this:
{local-name(.)}{@num}
The attribute templates are not restricted to expressions only. You can also use literal values within these templates. Note that in order to use a literal curly brace, you must use double braces. The double braces will be replaced by a single brace. For instance, {{evaluates to a literal {, and }}evaluates to a literal }. So, when writing these templates using this:
{local-name(.)}unevaluated{@num}
it evaluates to the following when the element <site num="1" />is in context:
siteunevaluated1 Creating Elements
Sometimes you need to create elements in the result trees and literal elements just won’t do.
For instance, you cannot add elements that are named based on values from the context node using literals. This is where you can use the xsl:elementelement:
<xsl:element name={qname} namespace={uri-reference} use-attribute-sets=qnames />
All attribute values of this element within the curly braces ({}) are interpreted as attribute value templates for the values. The final result of the template, though, must be the type speci- fied. The content of this element is a template to define attributes and children of the element being created.
The name Attribute The nameattribute specifies the name of the element to be created. You can use it to mimic literal elements within the style sheet as well as to create dynamically named elements:
<!-- Using literal p elements -->
<p>
<xsl:value-of select="./name" />
<xsl:call-template name="siteurl" />
</p>
You can also use xsl:elementto produce the same <p></p>tags in the result tree:
<xsl:element name="p">
<xsl:value-of select="./name" />
<xsl:call-template name="siteurl" />
</xsl:element>
The element name could also be dynamically created rather than using a hard-coded name. When sharing templates that match multiple nodes of the same name, you might want the name of the current node in the result tree. It doesn’t make sense to write a bunch of con- ditional code, which I haven’t explained yet, and hard-code names based on the conditions.
Attribute templates come in handy in this case:
<xsl:element name="{local-name(.)}">
<xsl:value-of select="./name"/> : <xsl:value-of select="./url"/>
</xsl:element>
Assuming this is within a matching template and an element named siteis currently being processed, the portion of the resulting tree looks like the following (depending upon the values of the subnodes, of course):
<site>PHP : http://www.php.net/</site>
The only condition when using attribute value templates is that the final result must be a valid QName as defined in the XML specification.
The namespace Attribute The namespaceattribute defines the namespace for the element when created. The value of this attribute is also interpreted as an attribute value template. The result of the attribute value template should be a URI reference, though it is not an error if it is not legal. When the QName has a prefix, it will be associated with the namespace; otherwise, the namespace is considered to be a default namespace. When it results in an empty string, the created element will be considered to have a NULLnamespace. Using the same siteelement from the previous example as the context, the following code creates the resulting tree with namespaced elements:
<xsl:element name="ns:{local-name(.)}" namespace="http://www.example.com/ns">
<xsl:element name="ns:{local-name(.)}" namespace="http://www.example.com/ns" />
<xsl:element name="{local-name(.)}" namespace="http://www.example.com/ns" />
</xsl:element>
Here the first xsl:elementwill create an element with the QName ns:sitewith the ns prefix associated with the namespace http://www.example.com/ns. An empty child ns:site element is also created and bound to the same namespace. An additional siteelement is created, but this time without a prefix so the namespace will become the default namespace for the element in the results. Processing this snippet from the style sheet would result in the following piece of output:
<ns:site xmlns:ns="http://www.example.com/ns">
<ns:site></ns:site>
<site xmlns="http://www.example.com/ns"></site>
</ns:site>
The use-attribute-sets Attribute The use-attribute-setsattribute allows the use of a predefined set of attributes that will be created with the element. The value of this attribute is a whitespace- separated list of attribute set names. Before you try to understand what attribute sets are, you first need to understand how attributes are created.
Creating Attributes
You can create attributes in the same manner as elements. The xsl:attributeelement defines a new attribute:
<xsl:attribute name={qname} namespace={uri-reference} />
You define the attributes of this element in the same way as the respective attributes from the xsl:elementelement. The content of this attribute defines the value for the created attribute:
<xsl:element name="site">
<xsl:attribute name="{local-name(.)}att">
<xsl:value-of select="@num"/>
</xsl:attribute>
</xsl:element>
Based on this code, an element named sitewill be created with an attribute named by appending attto the local name of the context node. Its value will be set by the value of the numattribute of the current context node. Using an element node defined by <site num="1" />
as the context would result in the following:
<site siteatt="1"></site>
Named Attribute Sets
You can group sets of attributes within a named attribute set so that you do not need to add each individual attribute every time you need it:
<xsl:attribute-set name=qname use-attribute-sets=qnames />
The nameattribute specifies the name of the named attribute set being defined. The value is a literal QName and not an attribute value template like you saw with previous elements.
The value specified by the name is what is used to reference the attribute set from other ele- ments such as the value specified by the use-attribute-setsattribute from the xsl:element element. The use-attribute-setsattribute on the xsl:attributeset element can specify additional named attribute sets that this nameattribute set includes. The value consists of a list of nameattribute sets separated by whitespace. Attributes that are being defined within the attribute set, and not coming from other attribute sets from the use-attribute-setsattribute, are defined within the content of the xsl:attribute-setelement. For example:
<xsl:attribute-set name="attset1">
<xsl:attribute name="att1">1</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="attset2" use-attribute-sets="attset1">
<xsl:attribute name="att2">2</xsl:attribute>
</xsl:attribute-set>
<xsl:template match="site">
<xsl:element name="site" use-attribute-sets="attset2">
<xsl:attribute name="att3">3</xsl:attribute>
</xsl:element>
</xsl:template>
This code defines two attribute sets. The set attset1defines a single attribute named att1 having the value 1. The set attset2uses the named attribute set attset1as well as defines an attribute named att2having the value 2. When attset2is referenced from another element, such as the xsl:elementelement in the previous code, it would have the same effect as defin- ing the att1and att2 xsl:attributeelements within the content of the xsl:elementelement.
Assuming the previous xsl:elementis within a matched template, the result from the process- ing would be as follows:
<site att1="1" att2="2" att3="3"></site>
It is important to note that the same rules for the xsl:attributeelement, such as using expressions, pertain when used within attribute sets. Any expression would be evaluated just as if the xsl:attributeelements had been defined within the content of the xsl:elementelement.
■ Caution It is an error for an attribute to directly or indirectly reference itself.
Creating Text
You can easily create text using literal text as well as some other XSLT elements not yet intro- duced. Even so, you can also use the xsl:textelement to explicitly create text in the results because it offers a bit of control over how the text is handled:
<xsl:text disable-output-escaping = "yes" | "no" />
The content of this element is what is to be used as the content of the resulting text node.
It may be controlled to a degree using the disable-output-escapingattribute. This attribute may have the value yesor noand determines whether the text within the contents of the xsl:text element will be escaped in the resulting XML document. By default, the XSL processor will escape characters, so the default attribute value is no. For example:
<xsl:text disable-output-escaping="yes">
This & That
<xsl:text>
<xsl:text disable-output-escaping="no">
This & That
</xsl:text>
The difference between these two is significant. Processing the first will result in This & Thatas the content in the final resulting XML document, which in reality is malformed XML. The second block instructs the XSLT processor to escape the text content using the disable-output-escapingattribute with the value no, which results in the text This & That, which is legal and well-formed XML. The attribute, in this case, didn’t need to be specified since it uses no, which is the default value anyway. This is something to keep in mind, espe- cially when processing CDATA sections that have not been converted to text nodes because the disable-output-escapingattribute will not work with CDATA sections. (This is covered in more detail in the “Using Output” section.)
Creating Processing Instructions
You can create PIs just like all the other node types you have seen so far. You do this using the xsl:processing-instructionelement:
<xsl:processing-instruction name={ncname} />
The nameattribute, whose value is interpreted as an attribute value template, specifies the target of the PI being created. The content of the element defines the data for the PI:
<xsl:processing-instruction name="php">
print "Hello World";
</xsl:processing-instruction>
When this block is encountered within a template, it creates the following PI:
<?php print "Hello World"; ?>
■ Caution When the output method is html, processing instructions are terminated by >and not by ?>. This means you need to manually add ?as part of the content of the xsl:processing-instruction element.
Creating Comments
Comments are another type of node you can create dynamically; you do this by using the xsl:commentelement:
<xsl:comment />
As you may notice, this element has no attributes, and its content defines the text for the comment:
<xsl:comment>
Node named <xsl:value-of select="local-name()" /> was processed
</xsl:comment>
Using the siteelement from the XML data source as an example, a comment is dynami- cally generated when this element is processed within a template. Although the xsl:value-of element has not yet been introduced, you might already have an idea of what it does. The comment will include the literal text as well as the local name of the node in context when processed:
<!-- Node named site was processed -->
Copying Nodes
You can copy nodes directly to the result tree using the xsl:copyelement or the xsl:copy-of element. The differences between these two are the depth of the actual copy and the node to be copied.
xsl:copy This is the syntax for xsl:copy:
<xsl:copy use-attribute-sets=qnames />
The copy is only a shallow copy, so attributes and child nodes are not part of the copied node. Namespace nodes, however, are copied along with the node. When the node being
copied is an element type node, you can use the use-attribute-setsattribute to indicate the named attribute set to be created with the copied element. For example:
<xsl:template match="site">
<xsl:copy use-attribute-sets="attset2" />
<xsl:copy />
<xsl:copy>Some Text</xsl:copy>
</xsl:template>
When a siteelement is matched against this template, three copies of the element are cre- ated in the resulting tree. The first xsl:copycreates attributes based on the nameattribute set, attset2. The second xsl:copycopies only the element, which ends up being the open element tag with a closing element tag because no attributes or children are copied and no named attrib- ute set has been specified. The third xsl:copyelement creates a copy of the element and adds text content. It would also be valid for the content of the xsl:copyelement to create attributes and apply other templates. Applying this template to one of the siteelements produces the following:
<site att2="2" att1="1"/>
<site/>
<site>Some Text</site>
xsl:copy-of The xsl:copy-ofelement performs a deep copy of the node. Namespaces, attrib- utes, and children are all copied along with the node. Here’s the syntax:
<xsl:copy-of
select = expression />
The value of the selectattribute specifies the expression used to define the node set or result tree fragment to be copied into the result tree. An expression evaluating to any other type causes the results to be converted to a string and inserted into the result tree. This case would be similar to having called xsl:value-ofwith the expression. Later in the “Using Variables and Para- meters” section, you will be introduced to the concepts of variables and parameters in XSLT.
These add a data type called a result tree fragment, which is similar to the DOMDocumentFragment object. The xsl:copy-ofelement is efficient in handling these, as well as node sets, when they are to added to the final result tree. Rather than converting the nodes to strings, the nodes can be copied directly to the resulting tree. For example:
<xsl:template match="site">
<xsl:copy-of select="." />
</xsl:template>
The following is an example of a portion of the resulting tree using this template:
<site num="2">
<name>XML C Parser</name>
<url>http://www.xmlsoft.org/libxslt/index.php</url>
</site>
Text Generation
The xsl:value-ofelement is an element you have seen many times within the examples but has yet to be fully explained. You can use it to generate text nodes in the resulting tree:
<xsl:value-of select=string-expression disable-output-escaping = "yes" | "no" />
The difference between this element and the xsl:textelement is because of the select attribute on the xsl:value-ofelement. This element takes no child elements like many of the other ones and uses the results from the selectattribute to generate the text. The results from the selectattribute are automatically converted to a string if not so already, just as if the string function were called. In the event the expression results in an empty string, no text node is created. The disable-output-escapingattribute works the same way as the attribute on the xsl:textelement works. For example:
<xsl:template match="site">
<p><xsl:value-of select="./name"/> : <xsl:value-of select="./url"/></p>
</xsl:template>
A siteelement matching this template would have text nodes created from the xsl:value-ofelements based on the resulting string from the child nameand urlelements:
<p>PHP : http://www.php.net/</p>
Example Generating an HTML Document
Before continuing, I will demonstrate many of the concepts presented so far using a small exam- ple that transforms some XML data into an HTML page. The page will end up containing two links with a description of each link. I will use the following XML document for the input data:
<?xml version="1.0" encoding="iso-8859-1"?>
<sites>
<site>
<name>PHP</name>
<url>http://www.php.net/</url>
<description>PHP: Hypertext Preprocessor</description>
</site>
<site>
<name>XML C Parser</name>
<url>http://www.xmlsoft.org/</url>
<description>The XML C parser and toolkit of Gnome</description>
</site>
</sites>
This document is almost a duplicate of the previous one in this chapter. I have added a child element to each siteelement, providing a short description of the site. I will use the following style sheet to transform this data:
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html"/>