Search code examples
xsltnamespacesprefix

xsl generate attribute with prefix


I'm totally new to XSL and have the task of generating output xml with xmlns:A.B.C prefix/value as an attribute of the root node. Specifically like this:

<GetVersionResponse xmlns:A.B.C="www.somesite.co.uk/A/B/C">
    <Class>GetVersionRequest</Class>
    <Errors>
        <Error>
            <Text>Some message</Text>
        </Error>
    </Errors>
</GetVersionResponse>

This is my input:

<Error>
    <Namespace>xmlns:A.B.C</Namespace>
    <NamespaceValue>www.somesite.com/A/B/C</NamespaceValue>
    <Class>GetVersionRequest</Class>
    <Message>Some message</Message>
</Error>

This is the important snippet from the Error.xsl file:

<xsl:template match="Error">                    
    <xsl:variable name="ResponseType">
        <xsl:value-of select="concat(substring-before(Class, 'Request'),'Response')"/>
    </xsl:variable>        
    <xsl:variable name="NS">
        <xsl:value-of  select="Namespace"/>
    </xsl:variable>
    <xsl:variable name="NSV">
        <xsl:value-of  select="NamespaceValue"/>
    </xsl:variable>

    <xsl:element name="{$ResponseType}" namespace="{$NSV}" xml:space="default">
    ...
</xsl:template 

It generates the following error because I have a colon in the Namespace element of my input:

XSLT 2.0 Debugging Error: Unknown namespace prefix

If I replace the colon with an underscore I get the exact out put I require but only with an underscore of course. Like this:

<GetVersionResponse xmlns_A.B.C="www.somesite.co.uk/A/B/C">
    <Class>GetVersionRequest</Class>
    <Errors>
        <Error>
            <Text>Some message</Text>
        </Error>
    </Errors>
</GetVersionResponse>

I've trawled the web for hours and think I'm trying to insert the xmlns: as text instead of using the proper objects that will generate xmlns:MYTEXT but cannot figure out how to do it.

Many Thanks for any help !!!!


Solution

  • The complicating factor here is that xmlns:... namespace declarations are not attributes as far as the XPath data model is concerned, so you can't create them using xsl:attribute. However, in XSLT 2.0 you can create them using xsl:namespace.

    <xsl:template match="Error">
      <xsl:element name="{substring-before(Class, 'Request')}Response">
        <xsl:namespace name="{substring-after(Namespace, 'xmlns:')}"
                       select="NamespaceValue" />
        <xsl:copy-of select="Class" />
        <Errors>
          <Error>
            <Text><xsl:value-of select="Message" /></Text>
          </Error>
        </Errors>
      </xsl:element>
    </xsl:template>
    

    Live demo

    The name attribute of xsl:namespace is the prefix you want to bind (so not including xmlns:), and the select gives the URI you want to bind it to.