2

How do I write the XSL namespace in my output?

I'm using XSL to analyze an XSL document and report problems it finds, including copying the node. The problem is that I can't get xmlns:xsl="http://www.w3.org/1999/XSL/Transform" written into the output's root node, which means it gets repeated every time I copy an xsl:* element.

This doesn't seem to happen with other namespaces. For example, take the following XSL

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:custom="custom uri" xmlns:custom2="custom2 uri" exclude-result-prefixes="" version="3.0">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:template match="/" name="xsl:initial-template">
        <custom:element xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
            <xsl:element name="custom2:function">
                <xsl:attribute name="name">whatever</xsl:attribute>
            </xsl:element>
            <xsl:element name="custom2:function">
                <xsl:attribute name="name">whatever2</xsl:attribute>
            </xsl:element>
        </custom:element>
    </xsl:template>
</xsl:stylesheet>

When run against any XML document, I get what I expect except that xmlns:xsl is missing from custom:element even though I specify it and exclude-result-prefixes is explicitly blank... but that's fine, it's not used in the output.

<custom:element xmlns:custom="custom uri" xmlns:custom2="custom2 uri">
    <custom2:function name="whatever"/>
    <custom2:function name="whatever2"/>
</custom:element>

However, if I replace both name="custom2:function" with name="xsl:function" like so...

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:custom="custom uri" xmlns:custom2="custom2 uri" exclude-result-prefixes="" version="3.0">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:template match="/" name="xsl:initial-template">
        <custom:element xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
            <xsl:element name="xsl:function">
                <xsl:attribute name="name">whatever</xsl:attribute>
            </xsl:element>
            <xsl:element name="xsl:function">
                <xsl:attribute name="name">whatever2</xsl:attribute>
            </xsl:element>
        </custom:element>
    </xsl:template>
</xsl:stylesheet>

then xmlns:xsl is still missing from custom:element and I get

<custom:element xmlns:custom="custom uri" xmlns:custom2="custom2 uri">
    <xsl:function xmlns:xsl="http://www.w3.org/1999/XSL/Transform" name="whatever"/>
    <xsl:function xmlns:xsl="http://www.w3.org/1999/XSL/Transform" name="whatever2"/>
</custom:element>

instead of what I want:

<custom:element  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:custom="custom uri" xmlns:custom2="custom2 uri">
    <xsl:function name="whatever"/>
    <xsl:function name="whatever2"/>
</custom:element>

How do I change my stylesheet to declare xmlns:xsl="http://www.w3.org/1999/XSL/Transform" I the root node?

JSmart523
  • 2,069
  • 1
  • 7
  • 17

1 Answers1

1

With Saxon a namespace alias helps:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:custom="custom-uri" xmlns:custom2="custom2-uri" version="3.0">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:namespace-alias stylesheet-prefix="axsl" result-prefix="xsl" xmlns:axsl="http://www.w3.org/1999/XSL/Transform-alias"/>
    <xsl:template match="/" name="xsl:initial-template">
        <custom:element xmlns:axsl="http://www.w3.org/1999/XSL/Transform-alias">
            <xsl:element name="xsl:function">
                <xsl:attribute name="name">whatever</xsl:attribute>
            </xsl:element>
            <xsl:element name="xsl:function">
                <xsl:attribute name="name">whatever2</xsl:attribute>
            </xsl:element>
        </custom:element>
    </xsl:template>
</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/gVhEaiX outputs

<custom:element xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:custom="custom-uri"
                xmlns:custom2="custom2-uri">
   <xsl:function name="whatever"/>
   <xsl:function name="whatever2"/>
</custom:element>

Most times you would just put the namespace declaration on the root element with e.g.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:custom="custom-uri" xmlns:custom2="custom2-uri" version="3.0"
    xmlns:axsl="http://www.w3.org/1999/XSL/Transform-alias">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:namespace-alias stylesheet-prefix="axsl" result-prefix="xsl" />
    <xsl:template match="/" name="xsl:initial-template">
        <custom:element>
            <xsl:element name="xsl:function">
                <xsl:attribute name="name">whatever</xsl:attribute>
            </xsl:element>
            <xsl:element name="xsl:function">
                <xsl:attribute name="name">whatever2</xsl:attribute>
            </xsl:element>
        </custom:element>
    </xsl:template>
</xsl:stylesheet>

I was not sure whether you want to restrict it to a certain element so the first sample declares it on that element and then of course additionally on the xsl:namespace-alias so that it makes sense.

Martin Honnen
  • 160,499
  • 6
  • 90
  • 110
  • 1
    Note that you can use the namespace-alias on literal element constructors. No need for `xsl:element` and `xsl:attribute` (unless you just really like typing a lot). I would use: `` and `` – Mads Hansen Aug 08 '20 at 21:01