xsl-list
[Top] [All Lists]

Re: 'copying' the default namespace

2003-01-16 17:02:52
Carl Yu wrote:
I know this has been covered before... and I know that XSLT 2.0 will probably 
have the robust answer, but this XSL generates some interesting behavior.  I 
wonder if any of the XSL gurus can figure out why Xalan would generate this 
type 
of output.  And, if there's any way around it.

You didn't say what you expected/wanted the result to be, so
I'm not clear on what you want to work around.

in.xml
--
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<root version="0.1" xmlns="http://www.teradyne.com/test";>
   <child/>
</root>

test.xsl
--
<?xml version="1.0"?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; 
xmlns:ter="http://www.teradyne.com/test"; version="1.0">
<xsl:output method="xml" indent="yes"/>

<!-- IDENTITY copy, exclude failed patterns -->
<xsl:template match="ter:*|@*">

* matches any element, regardless of namespace, so the prefix
here isn't strictly necessary

   <xsl:copy>
      <xsl:apply-templates select="ter:*|@*" />
   </xsl:copy>
</xsl:template>

<xsl:template match="ter:root/ter:child">
   <xsl:element name="newChild" />

Unlike a literal result element, xsl:element creates a new
element without copying any namespace nodes from the stylesheet tree.

The name attribute is an AVT that resolves to a QName. If you want the element
to be 'newChild' in the 'http://www.teradyne.com/test' namespace, you should
use <xsl:element name="ter:newChild"/> or <xsl:element name="newChild"
namespace="http://www.teradyne.com/test"/> or just a literal <ter:newChild/>.


</xsl:template>

</xsl:transform>

out.xml
--
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns="http://www.teradyne.com/test"; version="0.1">
<newChild xmlns:ter="http://www.teradyne.com/test"; xmlns=""/>
</root>

So here's the question.  First, what's the deal with the xmlns:"{uri}" and 
xmlns=""?

You created an element named 'newChild' in no namespace, in a place
where the default namespace was already 'http://www.teradyne.com/test'.

The element must reflect the fact that it's in no namespace (hence no prefix 
on the name, and xmlns="") and it should also reflect the fact that the 
'http://www.teradyne.com/test' namespace is still in scope (xmlns:ter="...").

Technically, there was no need to emit the xmlns:ter binding, but most XSLT
processors serialize as soon as the result tree is built; they can't look
ahead to find out whether a namespace binding is actually needed or not. And
some might argue that the presence of a namespace node in the result tree is
reason enough to serialize it, even if it's not needed.

 Second, is there a way to prevent newChild from carrying any kind of 
namespace declaration.

Only if it is in the same namespace as its parent. The way you were creating
it, you were forcing it to be in no namespace, while its parent was in the 
'http://www.teradyne.com/test' namespace.

Finally, in my XSLT doc I want to only match against

<root xmlns="http://www.teradyne.com/test";>
   <child/>
</root>

my match statement was the utterly redundant "ter:root/ter:child"... there's 
gotta be a better match statement (like "ter:root/child"... which doesn't 
work.)

The way you are matching is the only option. In XPath, a node test that is a
QName with no prefix is interpreted as that name in no namespace; there's no
way to make it default to any other namespace.


Mike

-- 
  Mike J. Brown   |  http://skew.org/~mike/resume/
  Denver, CO, USA |  http://skew.org/xml/

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



<Prev in Thread] Current Thread [Next in Thread>