Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Remove namespace declaration from XSLT stylesheet with XSLT

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>
like image 397
Svish Avatar asked Dec 15 '22 19:12

Svish


1 Answers

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.)

like image 141
LarsH Avatar answered Jan 14 '23 06:01

LarsH