Re: [xsl] spurious attribute

Subject: Re: [xsl] spurious attribute
From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx>
Date: Tue, 26 Feb 2002 09:50:54 +0000
Hi Simon,

> I have some xml I'm transforming either into html or into xhtml. i'd
> prefer the latter, but if that's going to cause a problem, i'll
> settle for the former). I'm using MSXML 3.0 parser and transforming
> by running a little JS script with the Windows Scripting Host. A
> majority of the tags generated are coming out with an xmlsn="" empty
> attribute and I don't know why. I'm sure this is something to do
> with the xsl:stylesheet and xsl:output elements i'm using, but can't
> immediately see what about them may cause this to happen.

The xmlns="" attributes are there to reset the default namespace to
no namespace. My guess would be that somewhere in the stylesheet, you
have something like:

<xsl:template match="/">
  <html xmlns="http://www.w3.org/1999/xhtml";>
    ...
    <xsl:apply-templates />
    ...
  </html>
</xsl:template>

<xsl:template match="foo">
  <p>
    <xsl:apply-templates />
  </p>
</xsl:template>

To understand what's going on, you have to understand namespaces and
how XSLT generates elements.

Attributes that begin with 'xmlns' are namespace declarations; they
associate a prefix with a namespace URI. In the above, the xmlns
attribute is a namespace declaration for the XHTML namespace, and it
makes the XHTML namespace the default namespace.

Namespace declarations have a certain scope, namely the element that
they are on and their descendants. In the above, the XHTML default
namespace declaration has a scope of the html element, its children in
that template, down to the xsl:apply-templates element. Note that the
scope of the namespace follows the structure of the XSLT stylesheet as
an XML document, not the flow of the stylesheet as it runs.

Setting the default namespace means that any element in the scope of
the namespace that doesn't have a prefix is placed in that namespace.
So in the above, the html element is in the XHTML namespace because it
doesn't have a prefix and because there's a default namespace
declaration for the XHTML namespace in scope.

On the other hand, there's no default namespace declaration in scope
for the p element in the second template. That means that the p
element is in no namespace.

When the XSLT processor generates the result tree, it creates new
elements, which might or might not have a namespace. When you create
an element with a literal result element, such as the html and p
elements in the above, then the namespace of the element in the result
is the same as the namespace of the literal result element in the
stylesheet. Thus the above generates an html element in the XHTML
namespace, and a p element in no namespace.

When the XSLT processor serialises the result tree, it needs to make
sure that the elements in the result document are in the correct
namespaces. Elements in no namespace cannot have a prefix, so it only
has a couple of options here:

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

[I've used the prefix 'html' for clarity; usually a processor would
actually use something like 'ns1', since it can't know what prefix
'makes sense' for a particular namespace.]

or:

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

Processors will usually opt for the second of the choices because they
try to preserve the prefixes (or lack of them) that you've used on the
literal result elements.

So how do you fix it? Well, what you wanted was for both the html and
the p element to be in the XHTML namespace. If you move the default
namespace declaration so that it covers both the html element and the
p element in the stylesheet, then both the elements will be in the
XHTML namespace, and therefore the processor won't have to reassign
the default namespace when it serialises the result tree.

To make the XHTML namespace the default namespace throughout the
stylesheet, declare it in the xsl:stylesheet document element:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
                version="1.0"
                xmlns:msxsl="urn:schemas-microsoft-com:xslt"
                xmlns:xql="#xql-functions"
                xmlns:auto-ns1="http://www.w3.org/TR/WD-xsl";
                xmlns:global="#local-functions"
                xmlns="http://www.w3.org/1999/xhtml";>
...
</xsl:stylesheet>

That way any literal result element that you specify without a prefix
will be placed in the XHTML namespace, and the elements in the result
will therefore all be in the XHTML namespace. The processor will work
out that it only needs to place a namespace declaration on the html
element and all the elements in the document will be in scope of that
namespace declaration.

The moral of the story is that you can't treat namespace declarations
like other attributes.

Cheers,

Jeni

---
Jeni Tennison
http://www.jenitennison.com/


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread