Ant's
Ant's

Reputation: 13811

Copy without namespace with criteria in xslt

I'm using this template for copying without namespace:

<xsl:template match="*" mode="copy-no-namespaces">
    <xsl:element name="{local-name()}">
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates select="node()" mode="copy-no-namespaces"/>
    </xsl:element>
</xsl:template>

<xsl:template match="comment()| processing-instruction()" mode="copy-no-namespaces">
    <xsl:copy/>
</xsl:template>

this works. But I want it to copy without certain namespace rather than all namespace. For example I want to ignore few namespaces like http://test.com, http://test2.com, the copy should remove only these namespaces, not all the namespace.

Example:

<xs:schema xmlns:xxx="http://include.com" xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:zzz="http:test.com" >
   <zzz:element>
   </zzz:element>

   <xxx:complexType>
   </xxx:complexType>
</xs:schema>

Here zzz namespace should be removed but preserve xxx as zzz only matches http://test.com, so the output will be

<xs:schema xmlns:xxx="http://include.com" xmlns:xs="http://www.w3.org/2001/XMLSchema">
   <element>
   </element>

   <xxx:complexType>
   </xxx:complexType>
</xs:schema>

How can I achieve this?

Upvotes: 0

Views: 2722

Answers (2)

michael.hor257k
michael.hor257k

Reputation: 116992

I think you may be confusing between moving elements to a different (or no) namespace and copying namespaces (i.e. namespace declarations). You should only need to move the zzz: prefixed elements to no-namespace - and not care if the output contains a by now redundant namespace declaration:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns1="http:test.com"
exclude-result-prefixes="ns1">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

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

<xsl:template match="ns1:*">
    <xsl:element name="{local-name()}">
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates/>
    </xsl:element>
</xsl:template>

</xsl:stylesheet>

P.S. If you prefer, you can do the same thing without declaring any prefix:

<xsl:template match="*[namespace-uri()='http:test.com']">
    <xsl:element name="{local-name()}">
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates/>
    </xsl:element>
</xsl:template>

Upvotes: 3

jelovirt
jelovirt

Reputation: 5892

Use a template with higher priority to keep elements in given namespace:

<xsl:template match="*"
              mode="copy-no-namespaces">
  <xsl:element name="{local-name()}">
    <xsl:apply-templates select="node() | @*" mode="copy-no-namespaces"/>
  </xsl:element>
</xsl:template>

<xsl:template match="xxx:*" xmlns:xxx="http://include.com"
              mode="copy-no-namespaces">
  <xsl:element name="{name()}" namespace="{namespace-uri()}">
    <xsl:apply-templates select="node() | @*" mode="copy-no-namespaces"/>
  </xsl:element>
</xsl:template>

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

The first template strips namespaces from elements, the second retains namespace http://include.com in elements, and the last copies everything else.

The second template could use xsl:copy instead of xsl:element, but that would copy all namespaces in scope and you'd end up with redundant namespace declarations.

Upvotes: 0

Related Questions