owagh
owagh

Reputation: 3528

how to output an attribute in a specified namespace

Why does the following not work as I'd expect it to?

<root xmlns:ns0="xmlns" 
      ns0:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      xmlns:ns1="xsi" 
      ns1:schemaLocation="[some schema location]" />

Basically, I'm trying to add schemaLocation to an xml file that doesn't have this by doing :-

<xsl:template match="/s:*">
  <xsl:element name="{local-name()}" namespace="some other namespace">
    <xsl:attribute namespace="xmlns" name="xsi">http://www.w3.org/2001/XMLSchema-instance</xsl:attribute>
    <xsl:attribute namespace="xsi" name="schemaLocation">[some-loc]</xsl-attribute>
    <xsl:apply-templates select="@*|node()"/>
  </xsl:element>
</xsl:template>

and Xalan-C gives the xml shown above.

What I'm trying to get is something like :-

<root xmlns:ns0="http://www.w3.org/2001/XMLSchema-instance"
      ns0:schemaLocation="[some schema location]" />

Upvotes: 0

Views: 921

Answers (2)

Dabbler
Dabbler

Reputation: 9863

You need <xsl:attribute name="xsi:schemaLocation">[some-loc]</xsl:attribute>.

Edit (adding complete example):

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
   <xsl:template match="root">
      <xsl:element name="{local-name()}" namespace="some other namespace">
         <!--<xsl:attribute namespace="xmlns" name="xsi">http://www.w3.org/2001/XMLSchema-instance</xsl:attribute>-->
         <xsl:attribute name="xsi:schemaLocation">[some-loc]</xsl:attribute>
         <xsl:apply-templates select="@*|node()"/>
      </xsl:element>
   </xsl:template>
</xsl:stylesheet>

Depending on what exactly you're doing you can possibly use <xsl:copy> to copy the element instead of <xsl:element name="{local-name()}"/>; it's somewhat simpler.

Upvotes: 3

LarsH
LarsH

Reputation: 27996

As I'm interpreting your question and inferring what you actually wanted, the problem is that you are putting a value in namespace="..." that you intend to be a namespace prefix, but is actually supposed to be a namespace URI.

Thus the code you probably want is just one <xsl:attribute> element:

<xsl:template match="/s:*">
  <xsl:element name="{local-name()}" namespace="some other namespace">
    <xsl:attribute namespace="http://www.w3.org/2001/XMLSchema-instance" 
        name="xsi:schemaLocation">[some-loc]</xsl-attribute>
    <xsl:apply-templates select="@*|node()"/>
  </xsl:element>
</xsl:template>

Then the XSLT processor will output the specified schemaLocation attribute in the right namespace, and will also emit a namespace declaration for its prefix where needed (and its prefix may be xsi:, but doesn't have to be).

Part of the problem here is that people throw around the word "namespace" (mentally or to others) without being clear about what they mean. A namespace is not a namespace prefix, nor is it really a namespace URI. A namespace is globally identified by its URI, and locally identified by its prefix.

If the XSLT spec had named this attribute namespace-uri="..." instead of namespace="...", fewer people would fall into this trap. You can also protect yourself by asking whether someone who says "namespace" really means "namespace URI", "namespace prefix", "namespace declaration", etc. etc.

Upvotes: 3

Related Questions