[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message]

Re: How to move the namespaces onto the root element w

Subject: Re: How to move the namespaces onto the root element when there is a namespace prefix that is bound to different namespaces?
From: Dimitre Novatchev <dnovatchev@xxxxxxxxx>
Date: Sun, 13 Jan 2013 12:31:43 -0800
Re:  How to move the namespaces onto the root element w
Here is a complete solution that renames the prefixes, so that there
are no two different namespaces with the same prefix:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema"
 xmlns:my="my:my">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:variable name="vNamespaces" select="//namespace::*[not(name()='xml')]"/>
 <xsl:variable name="vPrefixes" select="$vNamespaces/name()"/>

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

  <xsl:template match="/*">
     <xsl:copy>
       <xsl:copy-of select="@*"/>
       <xsl:for-each-group select="$vPrefixes" group-by=".">
         <xsl:for-each-group select="$vNamespaces[name()=current()]"
group-by=".">
           <xsl:namespace name="unique-{name()}-{position()}" select="."/>
         </xsl:for-each-group>
       </xsl:for-each-group>
       <xsl:apply-templates select="node()"/>
     </xsl:copy>
   </xsl:template>

   <xsl:template match="*/*">
    <xsl:variable name="vNSUri" select="namespace-uri()"/>
    <xsl:variable name="vPrefix" select="prefix-from-QName(xs:QName(name()))"/>

    <xsl:variable name="vNewPrefix" select=
     "my:new-prefix(substring-before(name(),':'), $vNSUri)"/>

     <xsl:element name="{$vNewPrefix}:{local-name()}" namespace="{$vNSUri}">
      <xsl:apply-templates select="@*|node()"/>
     </xsl:element>
   </xsl:template>

   <xsl:template match="*/*/@*">
    <xsl:variable name="vNSUri" select="namespace-uri()"/>
    <xsl:variable name="vPrefix" select="prefix-from-QName(xs:QName(name()))"/>

    <xsl:variable name="vNewPrefix" select=
     "my:new-prefix(prefix-from-QName(xs:QName(name())), $vNSUri)"/>

    <xsl:attribute name="{$vNewPrefix}:{local-name()}" namespace="{$vNSUri}"
                   select="."/>
   </xsl:template>

   <xsl:function name="my:new-prefix" as="xs:string">
    <xsl:param name="pPrefix" as="xs:string"/>
    <xsl:param name="pNSUri" as="xs:string"/>
      <xsl:for-each-group select="$vNamespaces[name()=$pPrefix]" group-by=".">
        <xsl:if test=". eq $pNSUri">
          <xsl:sequence select="concat('unique-',name(),'-', position())"/>
        </xsl:if>
      </xsl:for-each-group>
   </xsl:function>
 </xsl:stylesheet>

When this transformation is applied to the provided XML document:

<Test xmlns="A">
     <ns1:element xmlns:ns1="B">Hello</ns1:element>
     <ns1:element xmlns:ns1="C">C</ns1:element>
 </Test>

the correct result is produced:

<Test xmlns="A" xmlns:unique--1="A" xmlns:unique-ns1-1="B"
xmlns:unique-ns1-2="C">
     <unique-ns1-1:element>Hello</unique-ns1-1:element>
     <unique-ns1-2:element>C</unique-ns1-2:element>
 </Test>

Note:

I wanted to use the function:

    prefix-from-QName()

however it requires an xs:QName as argument and an xs:QName
constructor only accepts *literal* strings as arguments.

The question arizes then: What is the above function useful for?

Cheers,

Dimitre

On Sun, Jan 13, 2013 at 11:29 AM, Costello, Roger L. <costello@xxxxxxxxx> wrote:
> Hi Folks,
>
> I found this wonderful code [1] from Michael Kay to move the namespace declarations up onto the root element:
>
>   <xsl:template match="/*">
>     <xsl:copy>
>       <xsl:copy-of select="@*, //namespace::*, child::node()"/>
>     </xsl:copy>
>   </xsl:template>
>
> That works great, provided the XML document doesn't have the same namespace prefix bound to different namespaces. For example, it fails on this XML document:
>
> <Test xmlns="A">
>     <ns1:element xmlns:ns1="B">Hello</ns1:element>
>     <ns1:element xmlns:ns1="C">C</ns1:element>
> </Test>
>
> Notice that the namespace prefix, ns1, is bound to two different namespaces.
>
> Applying the XSLT program to the XML document results in this  error:
>
>     Cannot create two namespace nodes with the same
>     prefix mapped to different URIs (prefix=ns1, URI=C,
>     URI=B)
>
> How do I move the namespace declarations up onto the root element, while taking in account that the XML document may contain a namespace prefix that is bound to different namespaces?
>
> /Roger
>
> [1] http://www.mhonarc.org/archive/html/xsl-list/2009-10/msg00153.html
>



-- 
Cheers,
Dimitre Novatchev
---------------------------------------
Truly great madness cannot be achieved without significant intelligence.
---------------------------------------
To invent, you need a good imagination and a pile of junk
-------------------------------------
Never fight an inanimate object
-------------------------------------
To avoid situations in which you might make mistakes may be the
biggest mistake of all
------------------------------------
Quality means doing it right when no one is looking.
-------------------------------------
You've achieved success in your field when you don't know whether what
you're doing is work or play
-------------------------------------
Facts do not cease to exist because they are ignored.
-------------------------------------
Typing monkeys will write all Shakespeare's works in 200yrs.Will they
write all patents, too? :)
-------------------------------------
I finally figured out the only reason to be alive is to enjoy it.

Current Thread

PURCHASE STYLUS STUDIO ONLINE TODAY!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!

Buy Stylus Studio Now

Download The World's Best XML IDE!

Accelerate XML development with our award-winning XML IDE - Download a free trial today!

Don't miss another message! Subscribe to this list today.
Email
First Name
Last Name
Company
Subscribe in XML format
RSS 2.0
Atom 0.3
Site Map | Privacy Policy | Terms of Use | Trademarks
Free Stylus Studio XML Training:
W3C Member
Stylus Studio® and DataDirect XQuery ™are products from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2013 All Rights Reserved.