renaming an element -- how to copy namespace nodes?

A

Adam Barr

I have a tag foo that I want to copy unchanged when it is a subtag of
bar, so I have a template (x is the namespace for the document):

<xsl:template match="x:bar/x:foo">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>

BUT, I discovered that someone has been mis-speling foo as foop in the
source files. So I add another template to fix this up:

<xsl:template match="x:bar/x:foop">
<foo>
<xsl:apply-templates/>
</foo>
</xsl:template>

The problem is that the output now has xmlns attributes added to the
foo tag that I output. If the input spells "foo" correctly, matching
the first template above, this doesn't happen.

I read in the docs that <xsl:copy> copies the namespace nodes, and I
surmise that the fact that this is not done when I specify the
explicit "<foo>" output is the reason for the xmlns attributes showing
up. However, I can't figure out how to copy the namespace nodes. I try
things such as

<xsl:for-each select="namespace::*">
<xsl:copy/>
</xsl:for-each>

or

<xsl:copy-of select="namespace::*"/>

but nothing seems to work (and it's not clear where exactly to put
these). Changing <foo> to <xsl:element name="foo"> doesn't help
either.

The actual xmlns attribute varies between Microsoft's .Net XSLT (which
outputs xmlns="") and Xalan (which outputs xmlns:x="[the URI for x]"
xmlns="[the URI for x]". But what I want is no xlmns attributes at
all, as it appears when the "foo" tag is copied by <xsl:copy>. Can
this be done?

Thanks.


- adam
 
B

Ben Edgington

I have a tag foo that I want to copy unchanged when it is a subtag of
bar, so I have a template (x is the namespace for the document):

<xsl:template match="x:bar/x:foo">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>

BUT, I discovered that someone has been mis-speling foo as foop in the
source files. So I add another template to fix this up:

<xsl:template match="x:bar/x:foop">
<foo>
<xsl:apply-templates/>
</foo>
</xsl:template>

The problem is that the output now has xmlns attributes added to the
foo tag that I output. If the input spells "foo" correctly, matching
the first template above, this doesn't happen.
<snip>

I think you need to make the default output namespace the same as the
x namespace here with a 'xmlns="..."' declaration in the
<xsl:stylesheet/> element. This will result in the new <foo/>
elements being created in the same output namespace, and thus they
*shouldn't* have an extra namespace declaration.

So, with this XML

----
<test xmlns="http://example.com/foo">
<bar>
<foo>Wibble</foo>
<foop>Wobble</foop>
</bar>
</test>
----

and this XSLT

----
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:x="http://example.com/foo"
xmlns="http://example.com/foo"
<xsl:template match="/">
<output>
<xsl:apply-templates/>
</output>
</xsl:template>

<xsl:template match="x:bar/x:foo">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>

<xsl:template match="x:bar/x:foop">
<foo>
<xsl:apply-templates/>
</foo>
</xsl:template>

</xsl:stylesheet>
 
D

David Carlisle

<foo>

generates a foo element in the default namespace at that point (in the stylesheet).
If that isn't the namespace used in te hrest of your source document
then the serialiser will inser a namespace decaration to make sure that
foo stays in this namespace.

If you want to generate a foo element in the namespace you have bound to
x: then you could go

<x:foo>

or perhaps you would prefer

<foo xmlns=" whatever you have bound to x">

normally you'd put xmlns=" whatever you have bound to x" on the
xsl:stylesheet element rather than on each literal result element, so it
is in scope over the whole stylesheet.
but nothing seems to work
both of those work, as in copy namespace nodes but probably have no
effect on the serialised result. Namespace nodes don't affect the name
of the element (which is a pair consisting of namespace uri and local
name) so once you have generated an element in no-namespace adding
namespace nodes never affects that element it might cause namespace
declaarations to be generated, but the system must make sure that these
don't change the namespace of the elements being serialised.
Don't think of namespaces as a type of attribute, think of them as part
of the element name. the fact that they get serialised using attribute
syntax is just a historical quirk.

David
 
R

Richard Tobin

Adam Barr said:
<xsl:template match="x:bar/x:foo">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>

This will output a foo in the namespace x is bound to.
<xsl:template match="x:bar/x:foop">
<foo>
<xsl:apply-templates/>
</foo>
</xsl:template>

This will output a foo in no namespace, unless you have a default
namespace declaration in the stylesheet. You probably want:

<xsl:template match="x:bar/x:foop">
<x:foo>
<xsl:apply-templates/>
</x:foo>
</xsl:template>

-- Richard
 
A

Adam Barr

David Carlisle said:
<foo>

generates a foo element in the default namespace at that point (in the stylesheet).
If that isn't the namespace used in te hrest of your source document
then the serialiser will inser a namespace decaration to make sure that
foo stays in this namespace.

If you want to generate a foo element in the namespace you have bound to
x: then you could go

<x:foo>

or perhaps you would prefer

<foo xmlns=" whatever you have bound to x">

normally you'd put xmlns=" whatever you have bound to x" on the
xsl:stylesheet element rather than on each literal result element, so it
is in scope over the whole stylesheet.


David


Thank you! The xmlns= did the trick (actually I did an <xsl:element
name="foo" xmlns="...">).

The .Net XslTransform was happy with just that; I had to add an
exclude-result-prefixes="x" to my <xsl:stylesheet> to get Xalan to
stop emitting the xlmns= attribute (in one place anyway...there were
actually several places I did this renaming, and they seem to behave
slightly differently based on whether the action inside of the
renaming <xsl:element> was an <xsl:apply-templates> or <xsl:value-of>.
More XSLT mystery...)

- adam
 
A

Adam Barr

This will output a foo in the namespace x is bound to.


This will output a foo in no namespace, unless you have a default
namespace declaration in the stylesheet. You probably want:

<xsl:template match="x:bar/x:foop">
<x:foo>
<xsl:apply-templates/>
</x:foo>
</xsl:template>

-- Richard



I tried <x:foo> but then it output the "x:" also which I didn't want.
The only reason I was using a namespace to begin with was because the
input XML had an xmlns= attribute in it (and various web searching
revealed the "x:" solution to that). Instead I did <xsl:element
name="foo" xmlns="[what x is bound to]"> and that worked (see other
post).

Thanks.

- adam
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,996
Messages
2,570,238
Members
46,826
Latest member
robinsontor

Latest Threads

Top