Subject: Re: [xsl] 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 |
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 |
---|
|
<- Previous | Index | Next -> |
---|---|---|
Re: [xsl] How to move the namespace, Michael Kay | Thread | Re: [xsl] How to move the namespace, Philip Fearon |
Re: [xsl] How to move the namespace, Michael Kay | Date | Re: [xsl] How to move the namespace, Philip Fearon |
Month |