Chapter 6. Building New XML Documents with XSLT

CONTENTS
  •  6.1 Creating Elements with LREs
  •  6.2 The <xsl:element> Instruction Element
  •  6.3 Creating Attributes with the <xsl:attribute> Instruction Element
  •  6.4 The <xsl:attribute-set> Top-Level Element
  •  6.5 The <xsl:text> Instruction Element
  •  6.6 Adding Attributes to LREs
  •  6.7 Comments and Processing-Instructions
  •  6.8 Namespace Aliases
  • Creating new XML elements

  • <xsl:element>

  • <xsl:attribute>

  • Literal result elements (LREs)

  • Attribute value templates (AVTs)

  • <xsl:processing-instruction>

  • <xsl:comment>

  • <xsl:namespace-alias>

One of the most convenient features of XSLT stylesheets is the ability to generate new content in the process of transformation. This generated content can be derived through a series of XPath expressions in combination with LREs, text that you add, or with other elements in XSLT yet to be introduced.

There are many ways to work with the existing structure and content of an XML document. However, there are only a few specific XSLT elements that deal directly with the creation of new elements and content. In this chapter, we will look at how content can be created using LREs, as well as the following XSLT elements: <xsl:element>, which is used to generate new XML elements; <xsl:attribute>, which is used to generate new XML attributes; <xsl:attribute-set>, which is used to create a group of attributes; and <xsl:text>, which is used to generate text. We will also discuss attribute value templates (AVTs), which provide the capability to use expressions in attributes. At the end of this chapter, we will also discuss two elements that are used to generate processing-instructions and comments. Finally, the last section will discuss the use of the <xsl:namespace-alias> element, which is useful when generating namespaced elements using LREs.

There are two specific ways to add new elements: either using LREs or using the <xsl:element> element. While both methods generate new elements, there are some specific nuances that may make one method preferable over the other, depending on the circumstances. Specifically, dealing with namespaces and attributes may be easier using <xsl:element> rather than LREs. Both methods are presented in the following sections.

6.1 Creating Elements with LREs

Elements that are not part of the input source document can be created using a literal result element, also known as an LRE. LREs are XML elements that are not part of the XSL specification or extension set of elements. They are "literal" elements that are passed through to the output, with the same element-type name and any attributes that are added by the stylesheet. LREs are added by the author of the stylesheet and placed according to the desired output. They are considered templates and can contain instruction elements, but cannot contain top-level elements. An LRE can also be used as the document element of the stylesheet, if the attribute defining it as a stylesheet is used.

An LRE generates an element of the same name in the output tree whenever the template rule that contains it is invoked. A common use of this is to transform XML to HTML, where the LRE is the HTML element specified for output.

For example, if your source XML refers to paragraphs with a <para> element, you might want to change them to the HTML <p> element by typing the <p> directly in the template, as in Example 6-1.

Example 6-1 Simple transformation of element-type names using LREs.
<xsl:template match="para">       <p>             <xsl:apply-templates />       </p> </xsl:template> 

In this template, <p> is an LRE. The template matches any element called <para> and outputs a <p> element in its place. The <xsl:apply-templates> instruction can be considered as an instruction to send any children of <para> on through to the next template rule, or output if there are no more template rules.

6.2 The <xsl:element> Instruction Element

The <xsl:element> instruction element provides a more structured approach to adding new XML elements directly to the output result tree. The following element model definition shows the correct structure of the <xsl:element> instruction element:

<!-- Category: instruction --> <xsl:element   name = { qname }   namespace = { uri-reference }   use-attribute-sets = qnames>   <!-- Content: template --> </xsl:element> 

The <xsl:element> instruction element has three attributes, one of which is mandatory: the name attribute. The name attribute contains the element-type name of the new element in the result tree. This attribute is required because an element without an element-type name is not valid XML, and using the <xsl:element> implies that the output will be either XML or HTML.

Note

Using <xsl:element> when the output type is text will cause the new element's tags to be ignored (not even sent to the output). LREs will also be ignored. The output type is specified with the <xsl:output> element's method attribute, discussed in Chapter 10.

The optional namespace attribute permits the declaration of a URI, if the new element requires a namespace to be shown in the result. In addition, <xsl:element> contains the optional use-attribute-sets attribute, which allows the new element to reference a pre-determined set of attributes (see Section 6.4).

In our Markup City in Example 6-2, the <xsl:element> element could enable the city planners to begin drawing neighborhood grids.

The template rule shown adds houses to each block using the <xsl:element> with an element-type name (specified in the name attribute) of house. This may seem a little over-complicated, since the same effect can easily be accomplished using LREs as follows:

<xsl:template match="block">       <block>           <house>1</house>           <house>2</house>           <house>3</house>           <house>4</house>           <house>5</house>    </block> </xsl:template> 

However, the advantage of using <xsl:element> instead of an LRE is that the name of the new element can be calculated using expressions, which are not allowed in the start or end tags of an LRE. The name attribute of <xsl:element> is interpreted by the XSLT processor as an AVT (see Section 6.6.1 for more information about AVTs). Using AVTs allows the content of the name attribute to be an XPath expression, as long as the value is surrounded by curly braces {}. For example, instead of naming our houses just house, we could compute the value of the element-type name using an expression:

<xsl:element name="{concat(translate(ancestor::thoroughfare/@name, ' ', '-'), '-', 'house')}"> 

The result of this expression would return a different element-type name depending on which <thoroughfare> the <block> is in. The value of the name attribute of each <thoroughfare> is put through a translate() to convert the spaces to dashes. Then, the value is concatenated with a dash and the word "house." The two new element-type names are <Whitesburg-Drive-house> and <Bankhead-house>.

Expressions are not allowed in an LRE name because the special characters in an expression are not valid XML and are not allowed in an element-type name. For example, if we wanted to just repeat the element <block> without typing "<block>," it would seem to make sense to use <name()> to extract the name of the element, but this would cause an error. This format is not a valid LRE because parentheses () are not allowed in element-type names, and the XSLT processor would attempt to interpret <name()> as a literal XML element. You could, however, use the name() function as follows:

<xsl:element name="{name()}"> 
Example 6-2 Using <xsl:element> to add houses to each block.
INPUT: <?xml version="1.0"?> <parkway>             <thoroughfare>Governor Drive</thoroughfare>             <thoroughfare name="Whitesburg Drive">                   <sidestreet name="Bob Wallace Avenue">                          <block>1st Street</block>                          <block>2nd Street</block>                          <block>3rd Street</block>                   </sidestreet>                   <sidestreet>Woodridge Street</sidestreet>             </thoroughfare>             <thoroughfare name="Bankhead">                   <sidestreet name="Tollgate Road">                          <block>First Street</block>                          <block>Second Street</block>                          <block>Third Street</block>                   </sidestreet>                   <sidestreet>Oak Drive</sidestreet>             </thoroughfare> </parkway> TEMPLATE RULE: <xsl:template match="block">       <block>             <xsl:element name="house">1</xsl:element>             <xsl:element name="house">2</xsl:element>             <xsl:element name="house">3</xsl:element>             xsl:element name="house">4</xsl:element>             <xsl:element name="house">5</xsl:element>       </block>       </xsl:template> OUTPUT: <block> <house>1</house> <house>2</house> <house>3</house> <house>4</house> <house>5</house> </block>       <!-- other blocks removed for brevity --> 

Once new elements are created, using either <xsl:element> or LREs, you can add attributes as necessary using the <xsl:attribute> element. Note that <xsl:attribute> can also be used to add attributes to elements generated or copied from the input with other XSLT elements; its use is not restricted to just new elements.

6.3 Creating Attributes with the <xsl:attribute> Instruction Element

One of the most useful instruction elements is the <xsl:attribute> element, which, as its name indicates, creates attributes. It has two attributes, as shown in the following element model definition: the name attribute, which establishes the new attribute's name, and the namespace attribute, which can give a namespace URI for the attribute, if necessary.

<!-- Category: instruction --> <xsl:attribute   name = { qname }   namespace = { uri-reference }>   <!-- Content: template --> </xsl:attribute> 

Using <xsl:attribute> is a good example of how XSLT stylesheets, as well-formed XML data instances themselves, benefit from and can be interpreted by means of XML syntax rules for the logical syntax of their structure. Based on the placement of the <xsl:attribute> element, the attributes created will be inserted into the element whether an LRE or otherwise in which the <xsl:attribute> instruction element is nested, as Example 6-3 illustrates. Assume that we want to add an address attribute to the houses in our previous example.

Example 6-3 Adding attributes with <xsl:attribute>.
TEMPLATE RULE: <xsl:template match="block">     <block>     <xsl:element name="house">           <xsl:attribute name="address">1</xsl:attribute>     </xsl:element>     <xsl:element name="house">           <xsl:attribute name="address">2</xsl:attribute>     </xsl:element>     <xsl:element name="house">           <xsl:attribute name="address">3</xsl:attribute>     </xsl:element>     <xsl:element name="house">           <xsl:attribute name="address">4</xsl:attribute>     </xsl:element>     <xsl:element name="house">           <xsl:attribute name="address">5</xsl:attribute>     </xsl:element>     </block> </xsl:template> OUTPUT: <block>     <house address="1"/>     <house address="2"/>     <house address="3"/>     <house address="4"/>     <house address="5"/> </block> 

The result of this stylesheet adds the address attribute to each new house. Note that the XSLT processor automatically converts empty elements to the proper format.

Again, this example can be accomplished using a few LREs, but the usage demonstrated in the previous section with AVTs also applies to <xsl:attribute>. The name attribute value can be an expression when used as an AVT by adding curly braces {}. As an added bonus, the content of the attribute value to be generated can now be calculated using any of the XSLT elements that are valid within a template. This is because the content of the <xsl:attribute> element is defined as a template.

A more complex usage, as shown in Example 6-4, might involve generating an address using the position() function to find out which <block> the houses are on. See Section 5.2.6.1 for an explanation of how context affects the value of the position().

Example 6-4 Creating house numbers with <xsl:attribute> using concat(), and position().
TEMPLATE: <xsl:template match="block"> <block> <xsl:element name="house"> <xsl:attribute name="address"><xsl:value-of select="concat(position(), '01')"/></xsl:attribute> </xsl:element> <xsl:element name="house"> <xsl:attribute name="address"><xsl:value-of select="concat(position(), '02')"/></xsl:attribute> </xsl:element> <xsl:element name="house"> <xsl:attribute name="address"><xsl:value-of select="concat(position(), '03')"/></xsl:attribute> </xsl:element> <xsl:element name="house"> <xsl:attribute name="address"><xsl:value-of select="concat(position(), '04')"/></xsl:attribute> </xsl:element> <xsl:element name="house"> <xsl:attribute name="address"><xsl:value-of select="concat(position(), '05')"/></xsl:attribute> </xsl:element> </block> </xsl:template> OUTPUT: <?xml version="1.0" encoding="utf-8"?> <block> <house address="101"/> <house address="102"/> <house address="103"/> <house address="104"/> <house address="105"/> </block> <block> <house address="201"/> <house address="202"/> <house address="203"/> <house address="204"/> <house address="205"/> </block> <block> <house address="301"/> <house address="302"/> <house address="303"/> <house address="304"/> <house address="305"/> </block> <block> <house address="401"/> <house address="402"/> <house address="403"/> <house address="404"/> <house address="405"/> </block> <block> <house address="501"/> <house address="502"/> <house address="503"/> <house address="504"/> <house address="505"/> </block> <block> <house address="601"/> <house address="602"/> <house address="603"/> <house address="604"/> <house address="605"/> </block> 

The resulting XML file contains the new <house>s with their appropriate number, based on the number of the <block> they are on. The position() function gets the number of the current <block>, and the concat() function combines it with the number of the house for each <house>.

Some of the city planners have approved the addition of several homes and addresses to Woodridge Street, and we want to make Woodridge Street the value of a name attribute for <sidestreet>, so that <sidestreet> can also contain several <house> elements, as shown in Example 6-5.

Example 6-5 Creating attributes with <xsl:attribute>.
TEMPLATE RULE: <xsl:template match="//sidestreet[contains(., 'Woodridge')]"> <sidestreet> <xsl:attribute name="name"><xsl:value-of select="text()"/></xsl:attribute>       <house><xsl:attribute name="address">1100</ xsl:attribute>       </house>       <house><xsl:attribute name="address">1101</ xsl:attribute>       </house>       <house><xsl:attribute name="address">1102</ xsl:attribute>       </house> </sidestreet> </xsl:template> OUTPUT: <sidestreet name="Woodridge Street"> <house address="1100"/> <house address="1101"/> <house address="1102"/> </sidestreet> 

Here we are using LREs to create the houses, and adding the attribute directly to each LRE with the <xsl:attribute> element. We could then add other contents to the <house> elements as needed. Notice that we did not use <xsl:apply-templates>, and so the original text data or PCDATA that listed Woodridge Street as the only content of <sidestreet> was not output again as content of the new <sidestreet>.

The nesting of <xsl:attribute> in the <house> LREs serves to situate the resulting address attribute inside, or as part of, the <house> in the output result tree. Remember from Chapter 1 that the parent of an attribute is the element that contains it, but at the same time, the attribute is not and cannot be considered a child of the element itself. Accordingly, then, nesting the <xsl:attribute> element within the element makes the attribute part of the new element.

Note

The <xsl:attribute> element must always appear first inside an LRE or <xsl:element>, prior to any additional LREs or instruction elements; otherwise, the attribute being defined is ignored in the output.

6.3.1 Using <xsl:attribute> with Namespaces

The <xsl:attribute> instruction provides a way to declare a namespace for the attribute being created, using the optional namespace attribute to declare it. The value of the namespace attribute can be an expression, in the form of an AVT, but it should resolve to a URI.

There is no special provision (no attribute) for declaring a prefix for the namespace that is being declared, but it can be added in the name attribute, using the form name="prefix:element-name" as the declaration. However, the XSLT processor decides whether to use a prefix defined in this manner. If the prefix defined for an attribute happens to be xmlns, the XSLT processor will not generate the namespace in the result tree. The xmlns is a reserved prefix and should not be used in an <xsl:attribute> name attribute. In Example 6-6, we add a namespace when declaring an attribute by simply adding the namespace attribute to the <xsl:attribute> element; but in this case, we do not add a prefix.

The resulting <font> element has the XSLT processor specific prefix (generated by James Clark's XT) automatically inserted as shown in bold. The namespace URI, http://www.our_company.com, is clear, as is the defined attribute name, "our_company_color," but the prefix is still up in the air. In fact, the temptation to make the attribute declaration stipulate the prefix'namespace="xmlns:WRONG='http://www.our_company.com'"' may seem logical, but is not correct. Example 6-7 shows the proper way to declare a prefix for a namespaced attribute.

Example 6-6 Creating a series of HTML font attributes with <xsl:attribute> inside LREs.
TEMPLATE RULE: <xsl:template match="/"> <font>       <xsl:attribute name="fontface">courier</xsl:attribute>       <xsl:attribute name="size">4</xsl:attribute>       <xsl:attribute name="our_company_color"       namespace="http://www.our_company.com">quadraseptic- chartreuse-       taupe</xsl:attribute> </font> </xsl:template> OUTPUT: <font fontface="courier" size="4" ns0:our_company_color="quadraseptic-chartreuse-taupe" xmlns:ns0="http://www.our_company.com"/> 
Example 6-7 Adding a prefix to a namespace with <xsl:attribute>.
<font> <xsl:attribute name="fontface">courier</xsl:attribute> <xsl:attribute name="size">4</xsl:attribute> <xsl:attribute name="myprefix:our_company_color" namespace="http://www.our_company.com">quadraseptic-chartreuse- taupe</xsl:attribute> </font> 

So, the author of the XSLT stylesheet creating a namespaced attribute with <xsl:attribute> is at the mercy of the chosen processor as to what prefix will result, even if it is defined correctly. Happily, XT does pick up on the prefix value defined in the name attribute, resulting in:

<font fontface="courier" size="4" myprefix:our_company_color="quadraseptic-chartreuse-taupe" xmlns:myprefix="http://www.our_company.com"/> 

Regardless of the range of uses for <xsl:attribute>, the variety of possible namespace prefixes, or the values or names for the created attributes being specified, this element provides indispensable functionality for a range of contexts. Most applicably, for industrial-strength applications of XSLT stylesheets, the <xsl:attribute-set> element offers additional versatility.

6.4 The <xsl:attribute-set> Top-Level Element

The <xsl:attribute-set> top-level element provides the ability to set up a group of <xsl:attribute> elements that generate attributes that can be inserted collectively into an element in the result tree.

The <xsl:attribute-set> element has two attributes: the name attribute, which is used to name and call the attribute set created, and the use-attribute-set attribute. The allowed content of the <xsl:attribute-set> element is zero or more <xsl:attribute> elements, as shown in the following element model definition:

<!-- Category: top-level-element --> <xsl:attribute-set   name = qname   use-attribute-sets = qnames>   <!-- Content: xsl:attribute* --> </xsl:attribute-set> 

Having a content of zero or more elements means that the <xsl:attribute-set> element can be an empty element, but it has the ability to call other <xsl:attribute-set> elements and include their content as its own. Note that an empty <xsl:attribute-set> element with no use-attribute-sets attribute is perfectly valid, but not very useful. A sample DTD element and attribute declaration detailing the structure of <xsl:attribute-set> is shown below.

<!ELEMENT xsl:attribute-set (xsl:attribute)*> <!ATTLIST xsl:attribute-set     name %qname; #REQUIRED     use-attribute-sets %qnames; #IMPLIED > 

6.4.1 The name Attribute

The value of the name attribute for <xsl:attribute-set> is a QName that is used to name the group of attributes. The value of the name attribute is the same as the value used for use-attribute-sets when the attribute set is being called.

ATTRIBUTE:  name NMTOKEN #REQUIRED VALUE = QName 

6.4.2 The use-attribute-sets Attribute

The attribute use-attribute-sets is used to access the content of an <xsl:attribute-set> and send the resulting attributes and their values to the result tree. This attribute is also found on two other XSLT elements, <xsl:element> and <xsl:copy>, and can be used by LRE elements if prefixed with the xsl namespace prefix (xsl:use-attribute-sets):

ATTRIBUTE:  use-attribute-sets NMTOKENS #IMPLIED VALUE = QNames 

When used on an <xsl:attribute-set> element, the use-attribute-sets attribute serves to sort of nest attribute sets. Any attribute set called by another <xsl:attribute-set> is placed before the ones that the calling set defines, if any. For example, if an <xsl:attribute-set> named "calling-set"called an <xsl:attribute-set> named "boilerplate-set," the attributes in the "boilerplate-set" would appear before the attributes in "calling-set," as shown below.

<xsl:attribute-set name="calling-set" use-attribute-sets="boilerplate- set" >        <xsl:attribute name="att1">Attribute1</xsl:attribute> </xsl:attribute-set> <xsl:attribute-set name="boilerplate-set">        <xsl:attribute name="att2">Attribute2</xsl:attribute> </xsl:attribute-set> 

The result of combining these two attribute sets (to the processor) is a single <xsl:attribute-set>, with the <xsl:attribute> elements placed in the calling set as if they were in the same set, but the called attributes appear first, as shown below.

<xsl:attribute-set name="calling-set">       <xsl:attribute name="att2">Attribute2       </xsl:attribute> <xsl:attribute name="att1">Attribute1 </xsl:attribute> </xsl:attribute-set> 

Of course, you would not see the above combined set because it is an example of how the XSLT processor sees the two sets during processing.

6.4.3 Using Attribute Sets with <xsl:attribute-set>

Often in the course of writing an XSLT stylesheet, it is necessary to create additional elements and attributes in the output result tree. There are many times when the same attributes are needed over and over again, although usually with different values. It is therefore convenient to declare such groups of attributes that are likely to be repeatedly utilized in a group, so that they can be inserted all at once by a single named reference, not unlike a macro or subroutine.

A common use for <xsl:attribute-set> would be to have a set of attributes defined for different types of table styles, one with borders and one without in typical HTML style. With our table formatting example for Markup City, it is now possible to call the defined set of attributes by name, as shown in Example 6-8.

The <table> element that is created contains the new attributes for border, cellpadding and cellspacing, as selected with the use-attribute-sets. The table can easily be converted from a table with borders to a table with no borders by changing the attribute value of use-attribute-sets from bordered_table to plain_table.

Example 6-8 Two attribute sets for bordered and unbordered HTML tables, called by the use-attribute-sets attribute.
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/ Transform"              version="1.0"> <!-- attribute set definitions --> <xsl:attribute-set name="plain_table">       <xsl:attribute name="border">0</xsl:attribute>       <xsl:attribute name="cellpadding">3</xsl:attribute>       <xsl:attribute name="cellspacing">4</xsl:attribute> </xsl:attribute-set> <xsl:attribute-set name="bordered_table">       <xsl:attribute name="border">1</xsl:attribute>       <xsl:attribute name="cellpadding">2</xsl:attribute>       <xsl:attribute name="cellspacing">3</xsl:attribute> </xsl:attribute-set> <!-- template rules -->       <xsl:template match="block" >              <xsl:call-template name="table-cell"/> </xsl:template> <xsl:template match="boulevard">       <xsl:call-template name="table-row"/> </xsl:template> <xsl:template match="thoroughfare">       <xsl:call-template name="table-row"/> </xsl:template> <xsl:template match="sidestreet">       <xsl:call-template name="table-cell"/> </xsl:template> <xsl:template match="main"> <xsl:element name="table" use-attribute- sets="bordered_table">                  <xsl:apply-templates/>       </xsl:element>       </xsl:template>       <xsl:template match="/">             <html>             <head><title>Table Example</title>             <head>             <body>                    <xsl:apply-templates/>             </body>             </html>       </xsl:template> <xsl:template name="table-row">       <tr>       <xsl:apply-templates/>       </tr> </xsl:template> <xsl:template name="table-cell">       <td>       <xsl:apply-templates/>       </td> </xsl:template>             </xsl:stylesheet> 

Example 6-9 shows the use of attribute sets which applies to LREs: you can apply attribute sets, using the use-attribute-set attribute in the LRE itself, by adding the xsl prefix.

If a series or set of attributes is to be repeatedly used throughout an XSLT stylesheet, you can declare it once and invoke it by a convenient name. This decreases the likelihood of error in cutting and pasting or, worse, retyping. Further, the values and the attribute names themselves can be generated based on the input XML data instance, adding flexibility to the output.

Example 6-9 Using the attribute xsl:use-attribute-set in an LRE
<xsl:template match="main">     <table xsl:use-attribute-sets="plain_table">           <xsl:apply-templates/>     </table> </xsl:template> 

6.5 The <xsl:text> Instruction Element

Another way to supplement the output result tree is to add text directly using the <xsl:text> element. While this can also be accomplished by typing text directly in the template, the <xsl:text> element serves to distinguish the actual text from other parts of the stylesheet. Sequences of <xsl:text> elements are sent to the output without any line breaks, making it possible to concatenate several strings. The <xsl:text> element, which has one optional attribute, disable-output-escaping, as shown in the following element model definition, can be used to output literal whitespace as well.

<!-- Category: instruction --> <xsl:text disable-output-escaping = "yes" | "no"> <!-- Content: #PCDATA --> </xsl:text> 

In effect, <xsl:text> instructs the XSLT processor to output the exact sequence of keystrokes that are found between the <xsl:text> and </xsl:text> tags. This includes line breaks and tabs. However, there are two special characters, < and &, that are not allowed in the content of <xsl:text> unless they are included as the special character entities, &lt; and &amp;. This is because these two characters are special XML characters and are processed as such when the document is parsed. It is the XML parser, not the XSLT processor, that will generate an error if these characters are used. The processing of these characters can be affected using the disable-output-escaping attribute.

6.5.1 The disable-output-escaping Attribute

When the output method of the document is xml or html, whether declared as such in the <xsl:output> element (see Chapter 10), or defaulted by the lack of an <xsl:output> element, certain special character entities are escaped. In other words, they will appear in the output as the same character entity reference that appeared in the input document. Note that this behavior is only valid for a few character entities, based on the XSLT processor used. The XSLT specification states that:

Normally, the xml output method escapes & and < (and possibly other characters) when outputting text nodes. This ensures that the output is well-formed XML. (XSLT specification, section 16.4)

This means that only & and < are guaranteed to appear in the output as &amp; and &lt;, but that the processor is free to add other characters to this list. In order to by-pass this functionality, you can use the disable-output-escaping to output the characters they represent, which are the text strings the entities resolve to. This is achieved by setting the attribute disable-output-escaping to a value of yes.

ATTRIBUTE:  disable-output-escaping (yes|no) "no" VALUE = (yes|no) "no" 

The default value of the disable-output-escaping attribute is no, as shown in the following sample DTD element declaration for <xsl:text>.

<!ELEMENT xsl:text (#PCDATA)> <!ATTLIST xsl:text   disable-output-escaping (yes|no) "no" > 

When the value of the method attribute of the <xsl:output> element is set to text, the processor ignores any use of the disable-output-escaping attribute altogether, and defaults to generating the actual character in the output. Table 6-1 shows the possible combinations of the disable-output-escaping attribute and the xsl:output method (either "text" or "xml/html") and the results using James Clark's XT.

6.5.2 Using <xsl:text> to Generate Text

New text that is added to the output can be placed inside the <xsl:text> element to distinguish it from other text.Several <xsl:text> elements can be used to output sequential text elements without any additional whitespace because generating text with <xsl:text>, or any other XSLT element, does not generate any additional line-breaks outside the tag in the output. For example, the following lines generate the single line "line1line2line3line4" in the output:

Table 6-1. Output method and disable-output-escaping
disable-output-escaping value text xml/html
  yes no yes no
&amp; & & & &amp;
&lt; < < < &lt;
&gt; > > > &gt;
> > > > &gt;
&quot; " " " "
" " " " "
&apos; ' ' ' '
<xsl:text>line1</xsl:text> <xsl:text>line2</xsl:text> <xsl:text>line3</xsl:text> <xsl:text>line4</xsl:text> 

Line breaks inside the <xsl:text> element, however, do appear in the output:

<xsl:text>line1 </xsl:text> <xsl:text>line2</xsl:text> <xsl:text>line3</xsl:text> <xsl:text>line4</xsl:text> 

Adding the two line breaks inside the <xsl:text> element for line 1 generates the literal line breaks in the output:

line1 line2line3line4 

The <xsl:text> element is very useful for placing extra whitespace like linebreaks and tabs between text generated by other elements. For example, most of the output examples in this book have line breaks added to make them readable, but in reality, the output is bunched up, as shown in Example 6-10.

Example 6-10 Generated elements without line breaks.
STYLESHEET: <?xml version="1.0"?> <xsl:stylesheet              xmlns:xsl="http://www.w3.org/1999/XSL/Transform"       version="1.0"> <xsl:template match="/"> <block>       <xsl:element name="house">1</xsl:element>       <xsl:element name="house">2</xsl:element>       <xsl:element name="house">3</xsl:element>       <xsl:element name="house">4</xsl:element> <xsl:element name="house">5</xsl:element> </block> </xsl:template> </xsl:stylesheet> RESULT: <?xml version="1.0" encoding="utf-8"?> <block><house>1</house><house>2</house><house>3/house><house>4</ house> <house>5</house></block> 

In order to have readable output, with line breaks between the <house> elements, we can add <xsl:text> elements with line breaks inside them, as shown in Example 6-11.

Note that simply putting line breaks between elements in the stylesheet will not generate line breaks in the output, as shown in Example 6-12.

Example 6-11 Generating line breaks with <xsl:text>
STYLESHEET: <?xml version="1.0"?> <xsl:stylesheet            xmlns:xsl="http://www.w3.org/1999/XSL/Transform"       version="1.0"> <xsl:template match="/"> <block> <xsl:text> </xsl:text>       <xsl:element name="house">1</xsl:element> <xsl:text> </xsl:text>       <xsl:element name="house">2</xsl:element> <xsl:text> </xsl:text>       <xsl:element name="house">3</xsl:element> <xsl:text> </xsl:text>       <xsl:element name="house">4</xsl:element> <xsl:text> </xsl:text>       <xsl:element name="house">5</xsl:element> <xsl:text> </xsl:text> </block> </xsl:template> </xsl:stylesheet> RESULT: <?xml version="1.0" encoding="utf-8"?> <block> <house>1</house> <house>2</house> <house>3</house> <house>4</house> <house>5</house> </block> 

6.5.3 Generating Text without <xsl:text>

It is possible to generate text in the output result tree without using <xsl:text> by simply typing the text in the stylesheet. The issues with using text in this way are subtle in the fact that they deal mostly with whitespace. When the processor sees a text string, it normalizes the string before sending it to the output. This means that any extra whitespace is removed according to the XSLT rules for normalizing whitespace. In most cases this means that, if the text between elements is simply line breaks, the line breaks will not appear in the output. If, on the other hand, the text includes line breaks between other text, the line breaks will be preserved. This is demonstrated in Example 6-13.

Example 6-12 No line breaks generated without <xsl:text>.
STYLESHEET: <?xml version="1.0"?> <xsl:stylesheet            xmlns:xsl="http://www.w3.org/1999/XSL/Transform"       version="1.0"> <xsl:template match="/"> <block>       <xsl:element name="house">1</xsl:element>       <xsl:element name="house">2</xsl:element>       <xsl:element name="house">3</xsl:element>       <xsl:element name="house">4</xsl:element>       <xsl:element name="house">5</xsl:element> </block> </xsl:template> </xsl:stylesheet> RESULT: <?xml version="1.0" encoding="utf-8"?> <block><house>1</house><house>2</house><house>3</house><house>4</house> <house>5</house></block> 
Example 6-13 Using text in a stylesheet with line breaks.
STYLESHEET: <?xml version="1.0"?> <xsl:stylesheet              xmlns:xsl="http://www.w3.org/1999/XSL/Transform"       version="1.0"> <xsl:template match="/"> <block> text line1 text line2 <xsl:element name="house">1</xsl:element> <xsl:element name="house">2</xsl:element> <xsl:element name="house">3</xsl:element> <xsl:element name="house">4</xsl:element> <xsl:element name="house">5</xsl:element> </block> </xsl:template> </xsl:stylesheet> RESULT: <?xml version="1.0" encoding="utf-8"?> <block> text line1 text line2 <house>1</house><house>2</house><house>3</house><house>4</house><house> 5</house></block> 

6.6 Adding Attributes to LREs

Attributes can be added to LREs in three ways: by directly typing the attribute and its value in the LRE, by using the <xsl:attribute> element, or by using the <xsl:attribute-set> element in conjunction with either the use-attribute-sets on an element or xsl:use-attribute-sets attribute on an LRE. Because LREs are passed through to the output result tree, using attributes directly in LRE elements can be difficult if the value of the attribute is to be generated or extracted from some node-set in the input document. For example, if we wanted to output a new element called <newblock> instead of our <block>s in Markup City, and then add an attribute with the text content of the <block>, the template in Example 6-14 would not accomplish our goal.

Example 6-14 An ineffective way to add attributes to LREs.
<xsl:template match="block">       <newblock name="text()"/> </xsl:template> 

The result of this template rule would replace each <block> element in the input with a literal element <newblock name="text()"/> in the output. The content of the new attribute would be the literal string text(). It is not possible to use a function directly in an LRE attribute. For this reason, the value of an attribute of a literal result element can be an Attribute Value Template, or AVT.

6.6.1 Attribute Value Templates

Normally, LRE attributes are passed through verbatim to the output result tree. However, if the attribute of an LRE contains curly braces ({}), the content of the curly braces is considered an Attribute Value Template, or AVT. AVTs can contain expressions and patterns, allowing the value of the resulting attribute to be extracted or generated from the input source document, or from some other result of an expression.

Note

The word template in Attribute Value Template should not be misconstrued to mean that it can contain children or anything of the sort, and should not be mistaken with the template contained in the <xsl:template> element.

If we add curly braces to the attribute value of the LRE in the previous example, the result will actually be the correct value of each text() node of each <block> element, as shown in Example 6-15. Note that in this example we are removing any extra text or stylesheet elements that do not apply to the result.

Example 6-15 Using an AVT to create a new attribute in an LRE.
INPUT: <?xml version="1.0"?> <main>       <parkway>              <thoroughfare>Governor Drive</thoroughfare>              <thoroughfare name="Whitesburg Drive">                    <sidestreet>Bob Wallace Avenue</sidestreet>                    <block>1st Street</block>                    <block>2nd Street</block>                    <block>3rd Street</block>                    <sidestreet>Woodridge Street</sidestreet>              </thoroughfare>              <thoroughfare name="Bankhead">                    <sidestreet>Tollgate Road</sidestreet>                    <block>First Street</block>                    <block>Second Street</block>                    <block>Third Street</block>                    <sidestreet>Oak Drive</sidestreet>              </thoroughfare>       </parkway>       <boulevard>                    <block>Panorama Street</block>                    <block>Highland Plaza</block>                    <block>Hutchens Avenue</block>                    <block>Wildwood Drive</block>                    <block>Old Chimney Road</block>                    <block>Carrol Circle</block>       </boulevard>                    </main> TEMPLATE RULE: <xsl:template match="block">       <newblock name="{text()}"/> </xsl:template> OUTPUT: <newblock name="1st Street"/> <newblock name="2nd Street"/> <newblock name="3rd Street"/> <newblock name="First Street"/> <newblock name="Second Street"/> <newblock name="Third Street"/> <newblock name="Panorama Street"/> <newblock name="Highland Plaza"/> <newblock name="Hutchens Avenue"/> <newblock name="Wildwood Drive"/> <newblock name="Old Chimney Road"/> <newblock name="Carrol Circle"/> 

6.6.2 Using <xsl:attribute> with LREs

Adding attributes to LREs can also be accomplished by using the <xsl:attribute> element directly following the open tag for the LRE, as shown in Example 6-16.

Of course, the value of the resulting attribute, which is determined by the content of the <xsl:attribute> element, will be once again hard-coded, or literally output, for each <newblock> as MyAtt, which is not really useful. But because we've moved the resolution of the value of the attribute to an instruction element instead of an AVT, we can now add instruction elements, such as <xsl:value-of>, as the content of the <xsl:attribute> element, as shown in Example 6-17.

Example 6-16 Adding attributes to LREs using <xsl:attribute>.
<xsl:template match="block">       <newblock>             <xsl:attribute name="name">MyAtt<xsl:attribute>       </newblock> </xsl:template> 

The template will result in the same output as was shown in Example 6-15, but this stucture allows additional elements to be included to expand the functionality of the <xsl:attribute> element. In addition, <xsl:attributes> can be nested in <xsl:attribute-set> elements and used on LRE elements as discussed in the next section.

Example 6-17 Using <xsl:value-of> to add attributes to LREs.
<xsl:template match="block">       <newblock>             <xsl:attribute name="name">                   <xsl:value-of select="."/>             </xsl:attribute>       </newblock> </xsl:template> 

6.6.3 Using <xsl:attribute-set> and the xsl:use-attribute-sets Attribute with LREs

LREs can take advantage of attributes defined in attribute sets by calling them directly in the LRE, using the xsl prefix on the use-attribute-sets attribute. For example, the element <newblock> created in Example 6-17 can use the xsl:use-attribute-sets to call a predefined set of attributes. The attributes in the set are added to the <newblock> element in the output result tree, as shown in Example 6-18.

The two attributes, name and context, are added to each <newblock> element, with their value calculated from each node as it is processed.

6.7 Comments and Processing-Instructions

There are two XSLT instruction elements that create what is considered content internal to the output XML document. Normally, internal content is not intended for end users. This internal content can be in the form of XML processing instructions, or XML comments. Processing instructions, or PIs, and comments are embedded in the output XML document as part of the document structure, but are not considered part of the document content, and cannot be seen by most rendering engines.

Processing instructions generated with <xsl:processing-instruction> are used by an external process, identified by the target of the PI, to handle the XML file in a specific way, based on the parameters of the PI. Comments generated with <xsl:comment> are used for special handling of the XML by a human.

Example 6-18 Demonstration of <xsl:attribute-set> with LREs.
STYLESHEET: <xsl:template match="block">       <newblock xsl:use-attribute-sets="block-atts"/> </xsl:template> <xsl:attribute-set name="block-atts">       <xsl:attribute name="name"> <xsl:value-of select="."/> </xsl:attribute>       <xsl:attribute name="context"> <xsl:value-of select="name(..)"/> </xsl:attribute> </xsl:attribute-set> OUTPUT: <newblock name="1st Street" context="thoroughfare"/> <newblock name="2nd Street" context="thoroughfare"/> <newblock name="3rd Street" context="thoroughfare"/> <newblock name="First Street" context="thoroughfare"/> <newblock name="Second Street" context="thoroughfare"/> <newblock name="Third Street" context="thoroughfare"/> <newblock name="Panorama Street" context="boulevard"/> <newblock name="Highland Plaza" context="boulevard"/> <newblock name="Hutchens Avenue" context="boulevard"/> <newblock name="Wildwood Drive" context="boulevard"/> <newblock name="Old Chimney Road" context="boulevard"/> <newblock name="Carrol Circle" context="boulevard"/> 

The loose categorization of internal output holds for processing instructions and comments in that this output is only accessed that is, is only humanly readable inside the XML document containing it. They can, however, be extracted as PI and comment nodes by an XSLT stylesheet.

6.7.1 The <xsl:comment> Instruction Element

The <xsl:comment> element creates an XML comment, identified by the comment delimiters <!-- and -->, in the output result tree. This element has no attributes and its content is a template, as shown in the following element model definition.

<!-- Category: instruction --> <xsl:comment>   <!-- Content: template --> </xsl:comment> 

The result of instantiating the template contained in this element can only be text. Any other kind of node will create an error, because comments are by nature empty elements.

Comments are internal to the XML document, and can be found anywhere in the XML document except within markup. There is no processor specific handling of XML comments, and XML or HTML browsers will not display them. Most XML parsers ignore any characters in the comment, except for the use of the delimiter characters --. Note that using a string of two sequential dashes (--) inside an <xsl:comment> element will cause some XSLT processors to place a space between them. Two sequential dashes are the reserved string that signals the end of a comment and are not allowed inside a comment.

As Example 6-19 shows, the instructions included in the template of the <xsl:commment> element can be used to generate the content of the comment in the output.

Example 6-19 Using <xsl:comment> to make context-specific comments.
<xsl:template match="/">       <xsl:comment>             <xsl:text>This city has </xsl:text>             <xsl:value-of select="count(//block)" />             <xsl:text> blocks in it. </xsl:text>       </xsl:comment> </xsl:template> 

The result of instantiating this template against a Markup City with 12 <block> elements is the XML comment:

<!--This city has 12 blocks in it. --> 

The template in the <xsl:comment> element contains <xsl:text> elements used to generate text output, as well as an <xsl:value-of> element using the count() function in its match attribute to get the number of blocks.

6.7.2 The <xsl:processing-instruction> Instruction Element

The <xsl:processing-instruction> instruction element is used to generate XML processing instructions in the output document instance. The content of this element, as shown in the following element model definition, is a template. It has one required name attribute that sets the name of the PI.

<!-- Category: instruction --> <xsl:processing-instruction   name = { ncname }>   <!-- Content: template --> </xsl:processing-instruction> 

The name of the PI, generated from the name attribute, becomes the target of the PI, which is the name of the application that will be used to process the PI. The template inside the <xsl:processing-instruction> element is instantiated to create the text content of the PI following the name. This text becomes the parameters of the PI that will be passed to the application when the PI is parsed.

Example 6-20 Creating a processing instruction with <xsl:processing-instruction>.
<xsl:processing-instruction name="xml stylesheet">href="mystyles.css" type="text/css"</xsl:processing-instruction> 

Example 6-20 shows a typical use for the <xsl:processing-instruction> element to include a PI to reference to an external cascading stylesheet (CSS).

This would generate the following processing instruction in the XML document instance.

<?xml-stylesheet href="mystyles.css" type="text/css"?> 

Notice that the content of the <xsl:processing-instruction> element is used as the text of the PI, following the name (xml-stylesheet) that is generated with the name attribute. The question marks at the beginning and end of the generated PI are automatically placed in the output by the <xsl:processing-instruction> element.

6.8 Namespace Aliases

When creating new elements it may be necessary to create an element that has a namespace. However, it is often not feasible to use the namespace directly as the name of an LRE, so the XSLT specification provides a mechanism to supply an alias for the prefix of a namespace. The <xsl:namespace-alias> element is used to define an alias for a namespace prefix. As shown in the following element model definition, the <xsl:namespace-alias> element is an empty top-level element with two attributes.

<!-- Category: top-level-element --> <xsl:namespace-alias   stylesheet-prefix = prefix | "#default"   result-prefix = prefix | "#default" /> 

The stylesheet-prefix attribute is used to specify the namespace prefix that will be used in the stylesheet. The result-prefix attribute specifies the namespace prefix that will appear in the result tree. Either value can use the default namespace if specified by using #default.

For example, if the stylesheet is being used to generate another stylesheet, or an XML document with an embedded stylesheet, you cannot use the xsl prefix for the new elements, because they will be interpreted by the processor to be real XSLT stylesheet elements. In this case a prefix alias can be defined, and the processor will convert the alias to the real prefix in the output. Example 6-21 shows the use of <xsl:namespace-alias> to define a prefix alias.

Example 6-21 Using <xsl:namespace-alias> to define a prefix alias.
<?xml version="1.0"?> <xsl:stylesheet   version="1.0"    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"    xmlns:myxsl="http://MyxslPrefixAlias"> <xsl:namespace-alias stylesheet-prefix="myxsl" result- prefix="xsl"/> <xsl:template match="text()"/> <xsl:template match="/"> <myxsl:stylesheet> <xsl:attribute name="version">1.0</xsl:attribute> <xsl:apply-templates/> </myxsl:stylesheet> </xsl:template> <xsl:template match="//*"> <myxsl:template match="{name()}">      <myxsl:apply-templates/>   </myxsl:template> <xsl:apply-templates/> </xsl:template> </xsl:stylesheet> 

Using this stylesheet on any XML document will generate a stylesheet for each element from the input. The myxsl prefix is converted to the xsl prefix in the output, using the <xsl:namespace-alias> element. Notice that the namespace for the alias is defined in the <xsl:stylesheet> element.

The first template rule matching on text() is used to suppress the output of any text nodes from the XML.

The template rule matching on the root (/) is generating the final <xsl:stylesheet> element. The <xsl:attribute> element is adding the version information to the output. Note that the processor automatically adds the xmlns attribute to the <xsl:stylesheet> element in the output (there is no way to define a prefix alias for the xmlns attribute).

The template rule matching the rest of the elements in the document (//*) supplies the new template rules for each element by pulling the name of the element with the name() function. Notice that the name() function in this case is in an attribute value template, signalled by the {} curly braces. Even though the alias prefix is being used, the <myxsl:template> element is considered an LRE, so the attribute values must be pulled using an attribute value template.

We then use <xsl:apply-templates> in each template rule to process the children of each matched node.

Note that there will be duplicate template rules because the template rule used to generate <xsl:template> elements is matching on every element in the document.

Note that XT does not support the <xsl:namespace-alias> element.

CONTENTS


XSLT and XPATH(c) A Guide to XML Transformations
XSLT and XPATH: A Guide to XML Transformations
ISBN: 0130404462
EAN: 2147483647
Year: 2005
Pages: 18

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