Transform which produces default namespace convention xmlns="..."

236 Views Asked by At

Given the following xml:

<root xmlns="example.com">
  <child />
</root>

What xslt (version 1.0) can be used to produce:

<newRoot xmlns="stackoverflow.com">
  <child />
</newroot>

I've tried various combinations of exclude-result-prefixes and namespace-alias. E.g,

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:e="example.com" xmlns:s="stackoverflow.com" exclude-result-prefixes="e">

<xsl:namespace-alias stylesheet-prefix="s" result-prefix="#default" />

    <xsl:template match="e:root">
        <s:newRoot>
            <xsl:apply-templates />
        </s:newRoot>
    </xsl:template>

    <xsl:template match="e:child">
        <s:child />
    </xsl:template>

</xsl:stylesheet>

The closest I've come is the following incorrect xml

<newRoot>
  <child />
</newroot>

EDIT: I apologize for the overly simple sample. The solution I'm searching for will change the default namespace AND make transformations to my xml. Here is a more sophisticated example of what I would like to do:

<Data xmlns="sample.com/public">
  <Insured>
    <Name>Sample Client</Name>
    <Locations>
      <Location Number="1">
        <Address>
          <City>New York</City>
          <State>New York</State>
          <Street>222 10 Street</Street>
        </Address>
      </Location>
      <Location Number="2">
        <Address>
          <City>New York</City>
          <State>New York</State>
          <Street>3538 27 Street</Street>
        </Address>
      </Location>
    </Locations>
    <Coverages>
      <LocationSplit>
        <LocationNumber>1</LocationNumber>
        <Clause>
          <Limit>10000000</Limit>
        </Clause>
      </LocationSplit>
    </Coverages>
  </Insured>
</Data>

Which would become

<projection xmlns="sample.com/projected">
  <insured>
    <name>Sample Client</name>
    <location address="222 10 Street New York, New York">
      <clause>
        <limit>10000000</limit>
      </clause>
    </location>
  </insured>
</projection>

I thought exclude-result-prefix and namespace-alias were the ticket because I could explicitly use each namespace by declaring them in my stylesheet and then remove the /public namespace while aliasing the /projection namespace to the #default. However, the alias causes the namespace to simply be removed.

2

There are 2 best solutions below

3
On BEST ANSWER

It is difficult to understand what in your question is real and what is just an example. To take your example literally (as your own answer does), the answer would be:

XSLT 1.0

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

<xsl:template match="/e:root">
    <newRoot>
        <xsl:apply-templates />
    </newRoot>
</xsl:template>

<xsl:template match="e:child">
    <child/>
</xsl:template>

</xsl:stylesheet>

A more generic answer, that would move all elements from their existing namespace/s to the new namespace would be:

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

<xsl:template match="*">
    <xsl:element name="{local-name()}" namespace="stackoverflow.com">
        <xsl:apply-templates/>
    </xsl:element>
</xsl:template>

</xsl:stylesheet>
0
On

If you merely want to literally match the input root and literally output your result document, just do this:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
                xmlns:ex="example.com"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                exclude-result-prefixes="ex">
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="/ex:root">
    <newRoot xmlns="stackoverflow.com">
      <child/>
    </newRoot>
  </xsl:template>

</xsl:stylesheet>

That works but may or may not meet your general needs. Below is another transformation that you or others might find more useful...

XSLT to Change All Element Namespaces

The following XSLT will change the namespace of all elements to stackoverflow.com:

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

  <xsl:template match="@*|processing-instruction()|comment()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="*">
    <xsl:element name="{local-name()}" namespace="stackoverflow.com">
      <xsl:apply-templates select="@*|node()"/>
    </xsl:element>
  </xsl:template>

</xsl:stylesheet>