Generating More Sophisticated XML Output
A version of this page is also available for
4/8/2010
When generating XML, it is often useful to generate comments, processing instructions, and so on. XSLT provides a set of commands for creating specific kinds of nodes in the output. Just as the <xsl:attribute> element can insert an attribute into the tree, XSLT provides a similar set of elements for inserting other types of nodes. For more information about the <xsl:attribute> element, see Accessing and Outputting Attributes.
The <xsl:comment> element inserts a comment into the output. Comments within the style sheet are not passed through to the output, but are treated as comments upon the style sheet itself. When a comment is required in the output, place the comment text within an <xsl:comment> element.
The <xsl:processing-instruction> element allows processing instructions to be inserted into the output. The name attribute specifies the name of the attribute, and the content of the element becomes the text of the processing instruction.
The <xsl:element> element provides an alternative mechanism for creating elements in the output. The name attribute specifies the name of the element. The following code example shows two ways of creating a <DIV> element produce identical results.
1) <DIV class="menuItem">
Choose me
</DIV>
2) <xsl:element name="DIV">
<xsl:attribute name="class">menuItem</xsl:attribute>
Choose me
</xsl:element>
Attributes must be added to elements created using the <xsl:element> element with the <xsl:attribute> element instead of being placed directly on the element.
Because XSLT allows output elements to be specified directly, there are only a few situations where <xsl:element> is useful, for example, as an escaping mechanism for creating XSLT elements in the output, which allows style sheets to generate style sheets.
The following sample converts style sheets to use the <xsl:element> syntax. In the process, it uses the <xsl:element> to generate elements in the XSLT namespace and inserts processing instructions and a comment at the start of the file.
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="https://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:processing-instruction name="xml-stylesheet">type="text/xsl"
href="style.xsl"</xsl:processing-instruction>
<xsl:comment>Style sheet converted automatically to
<xsl:element> syntax</xsl:comment>
<xsl:apply-templates select="comment()"/>
<xsl:apply-templates select="*"/>
</xsl:template>
<!-- Copy text, comments and processing instructions -->
<xsl:template match="comment() | processing-instruction() | text()">
<xsl:copy>
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
<!-- Convert non-XSL elements to <xsl:element> syntax -->
<xsl:template match="*">
<xsl:element name="xsl:element">
<xsl:attribute name="name"><xsl:value-of select="name(.)"/></xsl:attribute>
<xsl:apply-templates select="@*"/> <!-- consolidate -->
<xsl:apply-templates select="node()"/>
</xsl:element>
</xsl:template>
<!-- Convert non-XSL attribute to <xsl:attribute> syntax -->
<xsl:template match="@*">
<xsl:element name="xsl:attribute">
<xsl:attribute name="name"><xsl:value-of select="name(.)"/></xsl:attribute>
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
<!-- Copy namespace attributes -->
<xsl:template match="@xmlns:*">
<xsl:copy><xsl:value-of select="."/></xsl:copy>
</xsl:template>
<!-- Copy XSL elements and their attributes -->
<xsl:template match="xsl:*">
<xsl:copy>
<xsl:for-each select="@*">
<xsl:copy><xsl:value-of select="."/></xsl:copy>
</xsl:for-each>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
The preceding style sheet has five templates. The first adds a boilerplate to the root of the output document, and selects all comments and the document element for copying to the output. The second template copies comments, processing instructions, and text nodes to the output. The third template converts elements to the <xsl:element> syntax. The fourth template converts attributes to the <xsl:attribute> syntax. The fifth template ensures that any elements from the XSLT namespace are copied to the output with their attributes and not converted by the third template.
Using XSL as the Default Namespace
Another use for <xsl:element> is to generate elements when the default namespace of the style sheet is set to XSL. Some style sheets, such as the following one, consist of nearly all elements from the XSL namespace and contain virtually no output elements. It might be convenient to set the default namespace of the document to the XSL namespace so that prefixes can be omitted. <xsl:element> can be used for the rare output elements. Style sheets written in this way are more readable and compact, and more amenable to validation with an XML schema.
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="https://www.w3.org/1999/XSL/Transform" version="1.0">
<!-- Identity transformation template -->
<template>
<copy>
<apply-templates select="@* | * | comment() | processing-instruction() | text()"/>
</copy>
</template>
<!-- Rename "stock" elements to "security" -->
<template match="stock">
<element name="security">
<apply-templates select="@* | * | comment() | processing-instruction() | text()"/>
</element>
</template>
</stylesheet>
This sample uses just one named output element, "security", so it is easier to use the XSL namespace as the default, and use the <xsl:element> element for this one output element. However, consistently using the "xsl" prefix helps make your style sheets look familiar to other authors.