Remove namespace declaration from XSLT stylesheet with XSLT

13,839

I would add

 exclude-result-prefixes="foo"

onto your

 <xsl:stylesheet>

element. Then the namespace declaration for foo will be omitted if possible, i.e. if there no elements or attributes in that namespace to output.

FYI, the reason tnat this line

<xsl:template match="xsl:stylesheet/@xmlns:foo" />`

throws an error is because xmlns:foo in the input document is not an attribute; it's a pseudoattribute. What your match pattern is asking to match is an attribute named foo that is in a namespace corresponding to a namespace prefix xmlns. Since you have not declared a namespace prefix xmlns in your stylesheet, you get the error "prefix xmlns is not defined."

Update:

I see from your posted output (and my own testing) that exclude-result-prefixes hasn't been effective in removing the namespace declaration.

1) First I would ask why it matters. It doesn't change the namespace of anything in your output XSLT. Are you just trying to remove it for aesthetic reasons?

2) Looking at the XSLT 1.0 spec, it appears to me that <xsl:copy> pays no attention to exclude-result-prefixes:

Instantiating the xsl:copy element creates a copy of the current node. The namespace nodes of the current node are automatically copied as well...

AFAICT, only literal result elements will omit namespace nodes based on exclude-result-prefixes.

On that basis, I would try replacing <xsl:copy> in your identity template (for elements) with <xsl:element name="{name()}"> or some variant thereof. You would then need a separate identity template for non-element nodes.

I replaced your identity template with the following two templates:

<!-- Copy elements -->
<xsl:template match="*" priority="-1">
   <xsl:element name="{name()}">
      <xsl:apply-templates select="node()|@*"/>
   </xsl:element>
</xsl:template>

<!-- Copy all other nodes -->
<xsl:template match="node()|@*" priority="-2">
   <xsl:copy />      
</xsl:template>

and that gave what I believe is the desired output, with no extraneous ns declarations:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
   <xsl:output indent="yes" omit-xml-declaration="yes" />

   <xsl:template match="/">
      <xsl:variable name="processId" select="''" />
      <root>
         <xsl:apply-templates />
      </root>
   </xsl:template>

   <!-- Other stuff -->
</xsl:stylesheet>

(I have adjusted the whitespace for clarity.)

Share:
13,839

Related videos on Youtube

Lemon
Author by

Lemon

Software Developer, Geek, HSP, SDA, ..., open, honest, careful, perfectionist, ... Currently into indoor rowing and rock climbing, just to mention something non-computer-related... Not the best at bragging about myself... so... not sure what more to write... 🤔

Updated on September 14, 2022

Comments

  • Lemon
    Lemon over 1 year

    I have an XSLT stylesheet like the following:

    <?xml version="1.0" encoding="utf-8"?>
    <xsl:stylesheet version="2.0"
                    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                      xmlns:XQHeaderFunc="java:com.sonicsw.xq.service.xform.HeaderExtension"
                      xmlns:saxon="http://saxon.sf.net/">
    
      <saxon:script language="java" implements-prefix="XQHeaderFunc" src="java:com.sonicsw.xq.service.xform.HeaderExtension" />
    
      <xsl:output indent="yes" omit-xml-declaration="yes"/>
    
      <xsl:template match="/">
        <xsl:variable name="processId" select="XQHeaderFunc:getProperty(XQHeaderFunc:new(),'processId',-1)" />
        <xsl:value-of select="XQHeaderFunc:setProperty(XQHeaderFunc:new(),'processId',string(@id),-1)"/>
    
        <root>
          <xsl:apply-templates />
        </root>
    
      </xsl:template>
    
      <!-- Other stuff -->
    
    </xsl:stylesheet>
    

    I want to transform this stylesheet using a second XSLT stylesheet to remove anything that has to do with the XQHeaderFunc and saxon namespaces. Is there a way I can do this?


    I have now tried the following, which successfully deals with the elements, but the namespace declaration doesn't seem to want to disappear.

    <xsl:stylesheet version="1.0"
                    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                    xmlns:XQHeaderFunc="java:com.sonicsw.xq.service.xform.HeaderExtension"
                    xmlns:saxon="http://saxon.sf.net/"
                    exclude-result-prefixes="XQHeaderFunc saxon">
    
      <xsl:param name="XQHeaderReplacement" />
      <xsl:variable name="apos">'</xsl:variable>
    
      <!-- Copy all nodes -->
      <xsl:template match="node()|@*">
        <xsl:copy>
          <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
      </xsl:template>
    
      <!-- Remove saxon script tag -->
      <xsl:template match="saxon:script" />
    
      <!-- Remove elements with setProperty calls -->
      <xsl:template match="*[starts-with(@select, 'XQHeaderFunc:setProperty')]" />
    
      <!-- Replace getProperty calls with replacement value-->
      <xsl:template match="@select[starts-with(., 'XQHeaderFunc:getProperty')]">
          <xsl:attribute name="select">
            <xsl:value-of select="concat($apos, $XQHeaderReplacement, $apos)"/>
          </xsl:attribute>
        </xsl:template>
    </xsl:stylesheet>
    

    Output:

    <?xml version="1.0" encoding="utf-8"?>
    <xsl:stylesheet version="2.0" 
                    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
                    xmlns:XQHeaderFunc="java:com.sonicsw.xq.service.xform.HeaderExtension" 
                    xmlns:saxon="http://saxon.sf.net/">
    
      <xsl:output indent="yes" omit-xml-declaration="yes" />
    
      <xsl:template match="/">
        <xsl:variable name="processId" select="''" />
    
    
        <root>
          <xsl:apply-templates />
        </root>
    
      </xsl:template>
    
      <!-- Other stuff -->
    
    </xsl:stylesheet>
    
    • Dimitre Novatchev
      Dimitre Novatchev over 11 years
      Please, provide a complete source XML document (the 1st stylesheet). There are operations that must be done of which you don't seem to be aware of. In general, simply removing the namespace declaration leads to a non-(namespace-)well-formed result and the XSLT processor will prevent this by generating a new namespace declaration.
    • Lemon
      Lemon over 11 years
      Updated the question with more specific source and a new example of what I've tried out now.
    • Lemon
      Lemon over 11 years
      Added the exact source of the two xslt files and the source of the output after a running it in Visual Studio 2012.
  • Lemon
    Lemon over 11 years
    This would remove all namespaces though? I'm just interested in removing those two in particular. But yes, it's not very important now that I've managed to remove the actual elements and such. More like an annoyance :p
  • LarsH
    LarsH over 11 years
    @Svish: (For clarity, please distinguish between "namespaces" and ns declarations or ns prefixes.) Test it. The output will still be namespace-well-formed. The above transformation will not remove namespaces: notice that <xsl:template> is still in the "XSL/Transform" namespace. It won't remove needed ns declarations either. If there are some unneeded ns declarations that you want it to leave in, you'll probably have to copy the relevant namespace nodes explicity, but that makes even less sense than wanting to remove unnecessary ns decls.
  • Lemon
    Lemon over 11 years
    Seems to work perfectly! Thank you very much. (I'll try to remember that distinction which sure makes things clearer :)