Re: [xsl] Namespace attached to host doc rather than payload

Subject: Re: [xsl] Namespace attached to host doc rather than payload
From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx>
Date: Wed, 18 Jun 2003 10:44:15 +0100
Hi David,

> To be conformant with the specification I am trying to meet, the
> namespace of the payload document must appear on the "payload"
> element as above. However, when I run a stylesheet transformation on
> the document (using .NET 1.1 System.Xml.Xsl.XslTransform) the
> namespace is moved to top-level "ListRecords" element.

First, you need to understand that the namespace declarations that you
see in the result of your transformation come about because of the
position of namespace nodes within the result tree that you're
generating. A namespace declaration will be added to an element if it
has a namespace node that its parent doesn't have.

So the tree that you want to create looks like:

  ListRecords
    +- record
        +- header
        |   +- identifier
        |       +- "i1"
        +- body
            +- payload
                |  \- namespace: x = http://www.example.com/ex/
                +- x:one
                |   |  \- namespace: x = http://www.example.com/ex/
                |   +- "one"
                +- x:two
                |   |  \- namespace: x = http://www.example.com/ex/
                    +- "two"

(I've omitted the namespace node for the XML namespace from the above,
for brevity.)
                    
You want the <payload> element to have a namespace node that
associates the prefix 'x' with the namespace
'http://www.example.com/ex/' but for none of its parents to have that
namespace node.

When you create an element using a literal result element such as the
<ListRecords> element in:

> <xsl:template match="data">
>   <ListRecords>
>     <xsl:apply-templates select=".//datum" />
>   </ListRecords>
> </xsl:template>

then the resulting element is given namespace nodes for all the
namespaces that are in-scope for that element, minus the XSLT
namespace and minus those namespaces that are specified as being
excluded result prefixes (using the [xsl:]exclude-result-prefixes
attribute).

In your stylesheet, you declare the http://www.example.com/ex/
namespace right at the top level of the stylesheet, on the
<xsl:transform> element, and you don't list it as an excluded
namespace. That means that it's in-scope throughout the stylesheet, so
every element that you create with a literal result element gets a
namespace node for that namespace. This is why you get the namespace
declaration on the <ListRecords> element in the result.

What you need to do is make sure that the namespace node for the
http://www.example.com/ex/ namespace is either only in scope for the
<payload> element or exclude it for all but the <payload> element.

To achieve the effect that you want by only having the namespace in
scope for the <payload> element, I think it would be easiest to split
the stylesheet into two, since you want to use the 'x' namespace in
other templates -- one part that handles the wrapper and one part that
handles the payload -- and include the former into the latter. For
example:

--- wrapper.xsl ---
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform version="1.0"
               xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>

<xsl:include href="payload.xsl" />
               
<xsl:output method="xml" omit-xml-declaration="yes" />

<xsl:template match="data">
  <ListRecords>
    <xsl:apply-templates select=".//datum" />
  </ListRecords>
</xsl:template>

<xsl:template match="datum">
  <record>
    <header>
      <identifier>
        <xsl:value-of select="identifier" />
      </identifier>
    </header>
    <body>
      <xsl:apply-templates select="." mode="payload" />
    </body>
  </record>
</xsl:template>

</xsl:transform>
---

--- payload.xsl ---
<xsl:transform version="1.0"
               xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
               xmlns:q="http://www.example.com/queue/";
               xmlns:x="http://www.example.com/ex/";
               exclude-result-prefixes="q">

<xsl:template match="datum" mode="payload">
  <payload>
    <xsl:apply-templates select=".//q:one" />
    <xsl:apply-templates select=".//q:two" />
  </payload>
</xsl:template>

<xsl:template match="q:one">
  <x:one>
    <xsl:value-of select="." />
  </x:one>
</xsl:template>

<xsl:template match="q:two">
  <x:two>
    <xsl:value-of select="." />
  </x:two>
</xsl:template>
               
</xsl:transform>
---

To achieve the effect you want by managing exclude-result-prefixes,
you need to exclude the 'x' prefix only on the subtree that's used for
generating the wrapper:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform version="1.0"
               xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
               xmlns:q="http://www.example.com/queue/";
               xmlns:x="http://www.example.com/ex/";
               exclude-result-prefixes="q">
               
<xsl:output method="xml" omit-xml-declaration="yes" />

<xsl:template match="data">
  <ListRecords xsl:exclude-result-prefixes="x">
    <xsl:apply-templates select=".//datum" />
  </ListRecords>
</xsl:template>

<xsl:template match="datum">
  <record xsl:exclude-result-prefixes="x">
    <header>
      <identifier>
        <xsl:value-of select="identifier" />
      </identifier>
    </header>
    <body>
      <xsl:apply-templates select="." mode="payload" />
    </body>
  </record>
</xsl:template>

<xsl:template match="datum" mode="payload">
  <payload>
    <xsl:apply-templates select=".//q:one" />
    <xsl:apply-templates select=".//q:two" />
  </payload>
</xsl:template>

<xsl:template match="q:one">
  <x:one>
    <xsl:value-of select="." />
  </x:one>
</xsl:template>

<xsl:template match="q:two">
  <x:two>
    <xsl:value-of select="." />
  </x:two>
</xsl:template>
                
</xsl:transform>

You'll notice that in both stylesheets I've used a separate template,
in 'payload' mode, to generate the <payload> element, so that it
appears in a different scope from its parent and can therefore have
different namespace nodes on it.

Let us know if anything is unclear.

Cheers,

Jeni

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


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


Current Thread