views:

67

answers:

2

XSL stylesheet should output following code to Internet Explorer:

<xml:namespace prefix="vml" ns="urn:schemas-microsoft-com:vml"/>

But when I execute following template with any XML

<xsl:template match="*|node()">
    <xml:namespace prefix="vml"
                   ns="urn:schemas-microsoft-com:vml"/>
</xsl:template>

IE throws parsing error: The stylesheet does not contain document element. In the same time Firefox removes xml namespace in the output...

So, how can I preserve xml namespace in my output?

Important

a. Output method I use is html

b. Following code does not fix my problem:

<xsl:template match="*|node()">
    <namespace prefix="vml"
               xmlns="http://www.w3.org/XML/1998/namespace"
               ns="urn:schemas-microsoft-com:vml"/>
</xsl:template>
+1  A: 

You can't use the preserved xml prefix. Use something like this:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dummy="dummy">
<xsl:namespace-alias stylesheet-prefix="dummy" result-prefix="xml"/>
<xsl:template match="/">
    <dummy:namespace prefix="vml"
                   ns="urn:schemas-microsoft-com:vml"/>
</xsl:template>
</xsl:stylesheet>

With any input, you get this result:

<xml:namespace prefix="vml" ns="urn:schemas-microsoft-com:vml" />
Alejandro
A: 

If you literally want the result as shown in the question, this is very simple to achieve:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
 <xsl:output omit-xml-declaration="yes"/>

 <xsl:template match="/">
  <xml:namespace prefix="vml" ns="urn:schemas-microsoft-com:vml"/>
 </xsl:template>
</xsl:stylesheet>

This transformation, when applied on any XML document (not used), produces the wanted result:

<xml:namespace prefix="vml" ns="urn:schemas-microsoft-com:vml"/>

However, it seems to me that you want to add a namespace node to every element of a given XML document (if this isn't so, just let me know via a commentand I'll delete this answer).

If so, here is a simple and efficient way:

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:vml="urn:schemas-microsoft-com:vml"
     exclude-result-prefixes="vml">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:variable name="vNamespace" select=
     "document('')/*/namespace::*[name()='vml']"/>

 <xsl:template match="node()|@*">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match="/*">
     <xsl:copy>
       <xsl:copy-of select="$vNamespace"/>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>
</xsl:stylesheet>

when applied to any document, for example this one:

<t>
    <a x="3">
        <b y="4"/>
    </a>
</t>

the wanted result is produced:

<t xmlns:vml="urn:schemas-microsoft-com:vml">
   <a x="3">
      <b y="4"/>
   </a>
</t>

This may be confusing at first sight as only the top element of the result visibly has the desired namespace node. However, by definition (look at the XML Namespace spec) if an element at the root of a (sub) tree has a given namespace node, then all of its descendent elements also have this namespace node. Even if you copy the namespace to every element, the XSLT serializer will strip it off from the serialized (text) representation of all but the top element.

In XSLT 2.0 you may simply use the <xsl:namespace> instruction:

<xsl:namespace name="vml" select="urn:schemas-microsoft-com:vml"/>
Dimitre Novatchev
@Dimitre: I think your answer doesn't cover all scenarios. If the stylesheet must be client-side parsed with IE, you would get this results: `El prefijo del espacio de nombres no puede comenzar con la cadena reservada "xml"`
Alejandro
@Alejandro: I was not aware of this behavior of MSXML3 (which IE uses). Hmmm... THis may be regarded both as a feature and as a bug. THe fact is that all other XSLT processors I work with allow this. In fact MSXML4 allows this, which means that they corrected the MSXML3 bug in MSXML4. Nevermind, trying to use non-standard elements in the `xml:` namespace is a gross abuse and I'd discourage the author to do so.
Dimitre Novatchev
@Dimitre: I'm with you about discouraging the use of `xml:namespace` and other non-standard elements allowed by MS. More over, this can be done with proper namespace declaration `xmlns:vml="urn:schemas-microsoft-com:vml"`
Alejandro