Tomasz
Tomasz

Reputation: 23

Change namespace in XSLT with unknown prefix

I would like to change namespace in XML file with XSLT based only on namespace-uri without knowing what prefix this namespace has defined. Is it possible?

I get some solution but they work only with small files when I know the input and can setup xsl file kinda manualy.

What I would like to achieve:

INPUT XML:

    <?xml version="1.0" encoding="UTF-8"?>
    <re:rootElement xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:re="http://something.com/root"
xmlns:ns1="http://something.com/some/schema"
xmlns:cs2="http://something.com/another/schema"
xmlns:ns3="http://something.com/different/schema"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
<xsd:import namespace="http://something.com/another/schema" schemaLocation="/schema/location"/>

(multiple nodes below)

XSLT that takes 2 parameters:

<xsl:param name="old_namespace" select="'http://something.com/another/schema'"/>
<xsl:param name="new_namespace" select="'http://something.com/another/schemaNEW'"/>

And output as xml:

    <re:rootElement xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:re="http://something.com/root"
xmlns:ns1="http://something.com/some/schema"
xmlns:cs2="http://something.com/another/schemaNEW"
xmlns:ns3="http://something.com/different/schema"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
 <xsd:import namespace="http://something.com/another/schemaNEW" schemaLocation="/schema/location"/>
(multiple nodes below)

Upvotes: 0

Views: 626

Answers (1)

Michael Kay
Michael Kay

Reputation: 163615

It's not difficult to change the namespace URI used in namespace nodes and in the names of elements and attributes. In a schema-aware stylesheet, it's also possible (but perhaps harder) to change the namespace URI used in values of type QName. It's rather harder, I suspect, to change namespace URIs that appear:

  • directly in attributes such as xsi:schemaLocation or xs:import (unless you enumerate such attributes)

  • in the names of NOTATIONs

  • in content with a micro-syntax, e.g. consider

<xsl:if test="namespace-uri() = 'http://old-namespace.com/'>

If it's just namespaces used in element and attributes that you're after, then you can use

<xsl:template match="*[namespace-uri()=$old-namespace]">
  <xsl:element name="{name()}" namespace="{$new-namespace}">
    <xsl:apply-templates select="@*, node()"/>
  </xsl:element>
</xsl:template>

<xsl:template match="@*[namespace-uri()='$old-namespace']">
  <xsl:attribute name="{name()}" namespace="{$new-namespace}" select="."/>
</xsl:template>

along with the identity template (or in 3.0, <xsl:mode on-no-match="shallow-copy"/>) to make sure that other elements and attributes are copied unchanged.

(This is XSLT 2.0 but could easily be rewritten in 1.0).

Upvotes: 1

Related Questions