Namespaces

1. Default namespace
2. Process all except a specific namespace
3. Selecting based on namespace
4. namespace wrangling
5. Remove namespace declarations
6. Controlling namespace generation.

1.

Default namespace

Michael Kay




> Is it true that once I have used the 
> xpath-default-namespace I can't select this an element with no 
> namespace?

Unfortunately there is an error in the book here, and also an error in the Saxon implementation; more embarrassingly still, the two errors are different. This is only partially excused by the fact that the spec was changed at some stage.

The answer to your question is yes: if an xpath-default-namespace is in force, then there is no way to select elements in no namespace. But you can reset it, for any region of the stylesheet, by putting xpath-default-namespace="" on any XSLT element.

2.

Process all except a specific namespace

Jeni Tennison



>>  looks like it should be:
>> select="$style-biblio/cs:reftype[@name='book']/cs:*[not(self::cs: 
>> creator)]">

> Hah!  That does it; thanks!

Alternatively, since you're using XSLT 2.0, you could do:

   select="$style-biblio
             /cs:reftype[@name = 'book']
               /(cs:* except cs:creator)"

The (cs:* except cs:creator) selects all child elements in the cs namespace, and then removes from that sequence the cs:creator child elements. It's slightly more understandable than using the self:: axis, I think.

3.

Selecting based on namespace

James A. Robinson




>   I have been reading the FAQ entry:
> [XHTL to fo, namespace problems.]
> http://www.dpawson.co.uk/xsl/sect2/N5536.html#d6784e1669
>   I thought this would work for me, but I can't get any output using
> (1). My xml is the following:

You haven't told us what output you want, so I'm going to go with the assumption that the use of that FAQ question indicates you want to extract elements and have them tagged with a default namespace.

> <html xmlns="http://www.w3.org/1999/xhtml";>
> <head>...</head>
> <body>...</body>
> </html>

So this is XML tagged with an XHTML namespace, they values are unprefixed, but the root contains an xmlns attribute, meaning untagged elements are in the specified namespace (http://www.w3.org/1999/xhtml).

I know that's probably an obvious statement, but it's an important one to remember, and here is why: XSLT needs to know what namespace you are interested in.

> <?xml version="1.0" encoding="UTF-8"?>
> <xsl:stylesheet version="1.0"
>                 xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
>                 xmlns="http://www.w3.org/1999/xhtml";>
> <xsl:template match="/">
>     <xsl:for-each select="html/body">
>       <xsl:value-of select="."/>
>     </xsl:for-each>
> </xsl:template>
> </xsl:stylesheet>

This is where the above warning re namespaces comes in. Your stylesheet says to copy the textual value of the descendent html/body element in the *null* namespace. The declaration of the xmlns default namespace you set in your xsl:stylesheet element has zero impact on what the XPath selection 'html/body" is targeting.

The null namespace isn't what you want, you want the extract the html/body descendent in the xhtml namespace. I'm also assuming you want xsl:copy-of instead of xsl:value-of. The former will copy an element wholesale, the latter creates a text node.

If my guess about what you want for output is correct, perhaps something like this will work better:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; version="1.0"
 xmlns:xhtml="http://www.w3.org/1999/xhtml";>
 <xsl:template match="/">
   <xsl:copy-of select="xhtml:html/xhtml:body"/>
 </xsl:template>
</xsl:stylesheet>

which for me, using an XSLT 1.0 processor, emits

<?xml version="1.0" encoding="utf-8"?>
<body xmlns="http://www.w3.org/1999/xhtml">...</body>

Now, if you were using XSLT 2.0 you could use a nice feature which allows you to set the default namespace used in XPath selections by using an xpath-default-namespace attribute:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; version="2.0"
 xpath-default-namespace="http://www.w3.org/1999/xhtml";>
 <xsl:template match="/">
   <xsl:copy-of select="html/body"/>
 </xsl:template>
</xsl:stylesheet>

If you start adding multiple namespaces into the mix you will also need to read up on the exclude-result-prefixes attribute, as that can also get in your way when generating some XML documents which are DTD oriented (and which therefore often cause problems for XML using namespace prefixes)

4.

namespace wrangling

Michael Kay





> I am new to XSL and writing a XSL to transform list of XSDs
> to another list of XSD.
>
> The issue is, i want to assign a dynamic value for "xmlns"
> attribute in <xs:schema>. From the mailing archieves i see
> that i cannot add "xmlns" as an attribute. If i try below
>
> *<xs:schema>
>     <xsl:attribute name="xmlns">
>        <xsl:value-of select="$ReqResName" />
>   </xsl:attribute>
> </xs:schema>
> *
> where "ReqResName" is a variable(<xsl:variable>), i am
> getting the below error.
>
> *Illegal value used for attribute name: name*

> So if i want to change the value of "xmlns" attribute in
> "<xs:schema>", what is the solution?

The general rule here is: create your elements and attributes in the right namespace, and the namespace declarations will look after themselves. For example if your stylesheet says:

<xsl:element name="{$x}" namespace="{$uri}">

where $x is an unprefixed name, then the system will output a declaration of the default namespace without any special action on your part.

There are a couple of cases where this might not be good enough:

(a) for cosmetic reasons, you might want the namespace declaration to appear on the xs:schema element, rather than on the elements where it is actually needed

(b) you might want to declare a namespace prefix that isn't actually used in any element and attribute names, for example a prefix that is only used in QName-valued attribute content.

For these situations XSLT 2.0 has an xsl:namespace instruction, which works like xsl:attribute except that it generates a namespace node rather than an attribute node. The namespace node will convert into a namespace declaration when the document is serialized.

5.

Remove namespace declarations

Abel Braaksma


>    I'm trying to remove all the unused and duplicate declarations from
> my document, but they can change depending on the input, is there an
> easy way to do this?
>

If you transform something with XSLT 2.0, you can set exclude-result-prefixes="#all" on the main xsl:stylesheet or xsl:transform element, which will remove all namespace declarations that are unused.

It doesn't matter whether your prefixes change. If your namespace changes, your whole document (i.e, the identity of your document and nodes) changes and you'll have to pull other tricks. But different namespaces for the same content are unlikely, so I presume you meant prefixes, right?

MK amends this with:

No, that will only stop new namespaces being added...

If you want to remove existing namespaces, try:

<xsl:template match="/">
 <xsl:copy-of select="." copy-namespaces="no"/>
</xsl:template>

Or if you want to do this in the course of a transformation, use a modified version of the identity template:

<xsl:template match="*">
 <xsl:element name="name()" namespace="namespace-uri()">
   <xsl:copy-of select="@*"/>
   <xsl:apply-templates/>
 </xsl:element>
</xsl:template>

Of course, this may also remove namespaces that are in fact used, if they are only used "in content" as distinct from being used in element and attribute names.

6.

Controlling namespace generation.

David Carlisle, Mike Kay


I have a stylesheet which outputs XHTML documents that look like this:

   <?xml version="1.0"?>
   <xhtml:html
       xmlns="http://example.com/";
       xmlns:xhtml="http://www.w3.org/1999/xhtml";>
     <xhtml:head>
       <xhtml:title>Hello</xhtml:title>
     </xhtml:head>
     <xhtml:body>
       <ul xmlns="http://www.w3.org/1999/xhtml";>
         <li>1</li>
         <li>2</li>
       </ul>
    </xhtml:body>
   </xhtml:html>

However, I want those documents to look like this:

   <?xml version="1.0"?>
   <html xmlns="http://www.w3.org/1999/xhtml";>
     <head>
       <title>Hello</title>
     </head>
     <body>
       <ul>
         <li>1</li>
         <li>2</li>
       </ul>
     </body>
   </html>

That is, I want all namespace prefixes and unneeded namespace declarations
removed and a single default namespace declaration at the top level.

Answer. DC

Firstly make sure you have xmlns="http://www.w3.org/1999/xhtml"; on your xsl:stylesheet so it is in scope in the whole stylesheet.

then, If you are generating the elements, just use the unprefixed form in the stylesheet, if you are copying then from elsewhere and they are already prefixed then instead of

<xsl:copy>

use

<xsl:element name="{local-name()}">

MK If you output an element without specifying a prefix, for example

<html xmlns="http://www.w3.org/1999/xhtml";>

or

<xsl:element name="html" namespace="http://www.w3.org/1999/xhtml";>

then the system will usually output the name without a prefix.