1.0 1.0 1.0

Is there a way to add attributes with namespaces when creating an element in XSLT?

40 Views Asked by At

I'm trying to create an XSLT file with another one,

<xsl:element name="xsl:stylesheet">
      <xsl:attribute name="version">1.0</xsl:attribute>
      <xsl:attribute name="xmlns:msxsl">urn:schemas-microsoft-com:xslt</xsl:attribute>
      <xsl:attribute name="xlink">http://www.w3.org/1999/xlink</xsl:attribute>
      <xsl:attribute name="exclude-result-prefixes">msxsl</xsl:attribute>

        <xsl:apply-templates select="Root"/>
    </xsl:element>

The second attribute has a namespace "xmlns" which throws an error: Prefix is not defined.

It works fine without the namespace as in the third attribute, xlink.

How can I specify the namespace then?

Thank you

2

There are 2 best solutions below

1
y.arazim On BEST ANSWER

Here is a simplified version of the last suggestion in Michael Kay's answer:

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
xmlns:xlink="http://www.w3.org/1999/xlink">
<xsl:output method="xml" indent="yes"/>

<xsl:template match="/">
    <xsl:element name="xsl:stylesheet">
        <xsl:copy-of select="document('')/xsl:stylesheet/namespace::*"/>
        <xsl:attribute name="version">1.0</xsl:attribute>
        <xsl:attribute name="exclude-result-prefixes">msxsl xlink</xsl:attribute>
        <!-- more here -->
    </xsl:element> 
</xsl:template> 

</xsl:stylesheet>

The result:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.0" exclude-result-prefixes="msxsl xlink"/>

However this does not work with Xalan 2.7.2 and I am not able to test it with a MS processor (I don't think the documentfunction will work with an online tester). You might be better off using a namespace alias.

0
Michael Kay On

You can't create namespace nodes using xsl:attribute, because in the XSLT data model, namespaces and attributes are different things.

There are several ways of creating namespace nodes in your result tree:

(a) if you copy an element from the source tree (for example using <xsl:copy-of/>) then its namespaces will be copied too.

(b) if you write a literal result element in the stylesheet (for example <thing xmlns:z="http://z/"/> then its namespaces will be copied too, even if they are not used in any element or attribute names.

(c) if you construct an element using xsl:element, then any namespaces used in the element name, or in the names of its attributes, will appear automatically in the result tree, by a process known as namespace fixup.

(d) From XSLT 2.0, there is an xsl:namespace instruction for use when all of the above fail.

You haven't said which version of XSLT you are using, which is always a mistake, but since your code mentions msxsl then I guess it's probably legacy XSLT 1.0. If that's the case then I think you have two options:

(1) use literal result elements with xsl:namespace-alias - there are plenty of examples of this in the spec and elsewhere.

(2) Create a result tree fragment like this:

<xsl:variable name="dummy">
  <msxml:dummy xmlns:msxml="..."/>
</xsl:variable>

and then copy its namespaces into the final result tree using <xsl:copy-of select="exslt:node-set($dummy)//namespace::*"/>