Jesper Tverskov, March 2, 2009

xsl:namespace in XSLT 2.0

The xsl:namespace element is most often useful if namespaces are created dynamically or if they are part of content of elements and attributes as QNames, or if we for cosmetic reasons want to transfer namespace declarations from inner elements to outer element in output.

The best way to learn how to use xsl:namespace is by looking at a handful of code examples. Often when xsl:namespace is necessary it is not necessary strictly speaking. We could live without xsl:namespace in XSLT 1.0 but the workarounds can be very clumsy.

1. Cosmetic use

Let us start with the cosmetic use of xsl:namespace because it is easy to understand. Very often when elements and attributes in a namespace are created inside other elements in no namespace or in another namespace, the namespace declarations for the nested elements will show up in the nested elements in output.

This is as it should be, but very often the result document would be nicer to look at if all those namespace declarations were replaced with just one namespace declaration in some outer element or most often in the outermost element.

1.1 Cosmetic static example

Note that many of the following stylesheets don't have an input file. For that reason both a name attribute and a match attribute is used. You can start the transformation with a dummy input file, or, e.g. at the command line, you can use a parameter for initial template.

Stylesheet
<?xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:x="someNamespace">
  <xsl:output indent="yes"/>
  <xsl:template name="start" match="/">
    <xsl:element name="catalog">
      <xsl:namespace name="x" select="'someNamespace'"/>
      <xsl:element name="x:product"/>
      <x:product/>
    </xsl:element>
  </xsl:template></xsl:stylesheet>

Output
<?xml version="1.0"?>
<catalog xmlns:x="someNamespace">
  <x:product/>
  <x:product/>
</catalog>

In the example above we have a proper namespace declaration in place in the xsl:stylesheet element. This declaration will show up in the product element created the literal way even if the "x" prefix is not used.

The namespace declaration will also show up in the product element created with xsl:element, but only if the "x" prefix is used!

Now, in most situation we would prefer for the namespace declaration to show up in the outermost element, "catalog", instead of in the children elements. Here xsl:namespace can be put to use. In the example above we don’t need to use xsl:namespace. We could have made the outermost element the literal way. But in some situations we need xsl:element for the outermost element in order to compute its name.

1.2 Cosmetic dynamic example

In the following example we use two external variables, two xsl:param elements. We don't care why they are used. The xsl:param elements indicate some need to create the prefix or the namespace dynamically.

Stylesheet
<?xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:param name="ns-prefix" select="'x'"/>
  <xsl:param name="ns-namespace" select="'someNamespace'"/>

  <xsl:template name="start" match="/">
    <catalog>
      <xsl:namespace name="{$ns-prefix}" select="$ns-namespace"/>
      <xsl:element name="{$ns-prefix}:product" namespace="{$ns-namespace}"/>
      <xsl:element name="{$ns-prefix}:product" namespace="{$ns-namespace}"/>
    </catalog>
  </xsl:template></xsl:stylesheet>

Output
<?xml version="1.0"?>
<catalog xmlns:x="someNamespace">
  <x:product/>
  <x:product/>
</catalog>

Since we don't know the prefix or the namespace in advance, except that we have indicated the use of defaults if no parameters are supplied from outside, we can not declare them in the xsl:stylesheet element. We need xsl:element to declare the namespaces when we construct the children elements. And we also need xsl:namespace to transfer the namespace declarations from children to outermost element in output.

We need xsl:namespace both if we create the outermost element the literal way and if we use xsl:element. We don't need it for xsl:element if it is in the same namespace as the two children, the "name" and the "namespace" attriubtes of xsl:element will do.

1.3 Cosmetic example and xsl:copy

When we use xsl:copy typically as part of the modified "identity template", namespaces declared in the xsl:stylesheet element only are not copied to output unless prefixes make them needed. We need them in xsl:stylesheet to be allowed to create them in the templates as in the example below.

Input
<?xml version="1.0"?>
<catalog>
  <product id="p1" stock="4"/>
  <product id="p2" stock="1"/>
  <product id="p3" stock="3"/>
</catalog>

Stylesheet
<?xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:x="someNamespace">
  <xsl:output indent="yes"/>

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="catalog">
    <xsl:copy>
      <xsl:namespace name="x" select="'someNamespace'"/>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="product">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
      <xsl:attribute name="x:reorder" select="'yes'"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

Output
<?xml version="1.0"?>
<catalog xmlns:x="someNamespace">
  <product id="p1" stock="4" x:reorder="yes"/>
  <product id="p2" stock="1" x:reorder="yes"/>  
  <product id="p3" stock="3" x:reorder="yes"/>
</catalog>

Above we only need to make a template to recreate the "catalog" element in order to transfer the namespace declarations from the "product" elements to "catalog" in output. Instead of using xsl:copy when recreating "catalog", we could just have created "catalog" the literal way with no need for using xsl:namespace.

2. Output in one namespace

If we are only creating output to one namespace we don't need xsl:namespace not even when it is created dynamically. The "name" and the "namespace" attributes of xsl:element and xsl:attribute both take an attribute value template as value, and we can always use xsl:element and xsl:attribute instead of the literal constructors.

Stylesheet
<?xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:param name="ns-prefix" select="'x'"/>
  <xsl:param name="ns-namespace" select="'someNamespace'"/>

  <xsl:template name="start" match="/">
    <xsl:element name="{$ns-prefix}:catalog" namespace="{$ns-namespace}">
      <xsl:element name="{$ns-prefix}:product" namespace="{$ns-namespace}"/>
      <xsl:element name="{$ns-prefix}:product" namespace="{$ns-namespace}"/>
    </xsl:element>
  </xsl:template></xsl:stylesheet>

Output
<?xml version="1.0"?>
<x:catalog xmlns:x="someNamespace">
  <x:product/>
  <x:product/>
</x:catalog>

The example above is basically the "Cosmetic dynamic example" one more time except that all the output is in the same namespace. For that reason xsl:namespace is not needed.

3. QName data and xsl:element

Both the spec, http://www.w3.org/TR/xslt20/#element-namespace, and Michael Kay in "XSLT 2,0 and XPath 2.0", 4th Edition, page 392, use creation of namespace for QName in data as example of how to use xsl:namespace. The following three code examples spell the problem out to make it easier to understand.

Stylesheet
<?xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:template name="start" match="/">
    <xsl:element name="price">
      <xsl:attribute name="xsi:type" select="'xs:decimal'" namespace="http://www.w3.org/2001/XMLSchema-instance"/>
      <xsl:namespace name="xs" select="'http://www.w3.org/2001/XMLSchema'"/>
      <xsl:text>23.50</xsl:text>
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>

Output
<?xml version="1.0"?>
<price xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:decimal">23.50</price>

In the above stylesheet xsl:namespace is necessary to create the xsd namespace for "xs:decimal", the QName of an attribute value. This has nothing to do with what namespaces are mostly about: element and attribute names. We are now talking about content of elements or values of attributes.

As we will see from the next example, we can sometimes do without xsl:namespace, if the element's name don't need to be computed.

4. QName data and literal element

It is confusing that both the spec and MK have chosen to use literally created result elements to illustrate how xsl:namespace can be used, considering that we can make the code more simple and easier to understand by not using xsl:namespace as in this example:

Stylesheet
<?xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:template name="start" match="/">
    <price xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xml:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:decimal">
<xsl:text>23.50</xsl:text>
    </price>
  </xsl:template>
</xsl:stylesheet>

Output
<?xml version="1.0"?>
<price xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xml:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:decimal">23.50</price>

As long as the namespace declarations are not created dynamically we can always put at many namespaces as we need directly into result elements created the literal way. Most often they will show up automatically just by being declared in the xsl:stylesheet element.

5. QName data and dynamic namespace

When creating QName content dynamically for elements or for values of attributes we need to use xsl:namespace both if elements or attributes are created the literal way or with xsl:element and xsl:attribute.

Stylesheet
<?xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
  <xsl:param name="ns-prefix" select="'xs'"/>
  <xsl:param name="ns-identifier" select="'http://www.w3.org/2001/XMLSchema'"/>
  <xsl:template name="start" match="/">
    <price xsi:type="{$ns-prefix}:decimal" xmlns:xsi="http://w ww.w3.org/2001/XMLSchema-instance'">
    <xsl:namespace name="{$ns-prefix}" select="$ns-identifier"/>
    <xsl:text>23.50</xsl:text>
    </price>
  </xsl:template>
</xsl:stylesheet>

Output
<?xml version="1.0"?>
<price xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance'" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:decimal">23.50</price>

In the stylesheet above the parameters are just to indicate that the namespace for the QName content is created in some dynamic way. The finer details of how or why is not important.

6. Advanced examples

The following two examples are provided by members of the XSL-List.

6.1 Namespaces returned by user-defined function

Florent Georges has provided an interesting example of using xsl:namespace when creating meta XSLT stylesheets to create stylesheets. See the XSL-List, 200902/msg00286.html for how a user-defined function can return namespaces using xsl:namespace.

6.2 Namespaces in XPath expressions

G. Ken Holman has provided an interesting example of how xml:namespace can be used if a Schematron schema has namespaces in the XPath expressions, see the XSL-List, 200902/msg00290.html.

A Schematron schema most often uses an XSLT stylesheet as schema processor creating an XSLT stylesheet as output that can then be used for validation.

6.3 What to do in XSLT 1.0

In the example provided by G. Ken Holman, 200902/msg00290.html, we also have some hints to how we can solve the namespace problems in this tutorial in XSLT 1.0 where xsl:namespace is not available:

"When using XSLT 1.0 one creates dummy attributes on the document element that trigger the need for a namespace declaration, which then has scope through the entire stylesheet. The dummy attribute is ignored. With access to a node-set() extension, one can create the dummy attribute in a result tree fragment and then copy that one node to the document element. But without such an extension you have to create the dummy attribute to trigger the declaration on the document element."

7. Some sources of confusion

7.1 Output created literally or with xsl elements

Namespaces declared in the xsl:stylesheet element are automatically copied to elements created the literal way but not to elements created with xsl:element except if needed (e.g.: an attribute in a namespace is created inside it, or the element has a prefix). Namespace declarations are copied from input if we use xsl:copy and xsl:copy-of.

7.2 Declarations contra namespace nodes

Namespace declarations and namespace nodes are different things. We can see the first directly in the source code of input documents, stylesheet and output documents. We can only see the namespace nodes if we use the namespace axis, "namespace::*", deprecated in XSLT 2.0, or the new functions in-scope-prefixes() and namespace-uri-for-prefix().

The namespace fixup process normally copies namespace nodes for all namespaces in scope to an element. The namespace fixup process ensures that when we try to use a prefix for a result element or attribute, and there is no namespace node for it present, that is a proper namespace declaration is not in scope, we get an error message.

The namespace fixup process only works for element and attribute names. If we forget to get a proper namespace declaration in place for QNames as part of content of elements and attributes, we will not get an error message.

7.3 xmlns attribute is special

The xmlns and the xmlns:* attributes don't behave like other attributes. Most often they are inserted in output automatically. We can't get to their values with the same methods we use for other attributes. We can't create them with xsl:attribute, but we can create xmlns and xmlns:* the literal way except that an attribute value template for the namespace will be interpreted as a string.

Updated 2009-08-06