Search code examples
xslt-2.0xml-namespaces

using a single namespace declaration for literal result element and element constructor methods


Given the XML source

<Content>
</Content>

and transformation:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
  office:version="1.0"
  xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
  xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0">

  <xsl:output indent="yes" encoding="UTF-8"/>
  <xsl:template match="Content">
    <xsl:element name="office:document">
      <xsl:attribute name="office:version">1.2</xsl:attribute>
      <xsl:attribute name="office:mimetype">application/vnd.oasis.opendocument.text</xsl:attribute>

      <xsl:element name="office:body">
        <xsl:element name="office:text">
          <xsl:element name="text:p">Hello world.
          </xsl:element>
          <xsl:element name="text:p">Goodbye world.
          </xsl:element>
        </xsl:element>
      </xsl:element>

    </xsl:element>
  </xsl:template>
</xsl:stylesheet>

The result

<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
                 office:version="1.2"
                 office:mimetype="application/vnd.oasis.opendocument.text">
   <office:body>
      <office:text>
         <text:p xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0">Hello world.
          </text:p>
         <text:p xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0">Goodbye world.
          </text:p>
      </office:text>
   </office:body>
</office:document>

The namespace for paragraph elements is repeated. I want it applied to the root element to avoid this, as is the norm in odf files.

But if I add the namespaces to the root element, the XSL will include redundant namespace declarations, for the spreadsheet and root elements. If I then remove the namespaces from the stylesheet element, I won't be able to add literal result elements in those namespaces.

I read in Kay's 4th edition reference p473 "Avoiding duplicate namespace declarations is entirely the job of the XSLT serializer.." But I'm unable to leverage this insight to produce the required result.


Solution

  • For the included sample you get the included result as the elements generated with xsl:element don't have any namespaces in scope that you declare in the stylesheet element, they are only used to create an element in a certain namespace. It is not clear from that sample why you need xsl:element at all and can't simply use literal result elements.

    If you really need to construct your root element with xsl:element, you can however construct a namespace node with <xsl:namespace name="text" select="'urn:oasis:names:tc:opendocument:xmlns:text:1.0'"/>. See https://xsltfiddle.liberty-development.net/jyH9rMg for an online example which transforms your input sample with

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
      office:version="1.0"
      xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
      xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0">
    
      <xsl:output indent="yes" encoding="UTF-8"/>
      <xsl:template match="Content">
        <xsl:element name="office:document">
          <xsl:namespace name="text" select="'urn:oasis:names:tc:opendocument:xmlns:text:1.0'"/>
          <xsl:attribute name="office:version">1.2</xsl:attribute>
          <xsl:attribute name="office:mimetype">application/vnd.oasis.opendocument.text</xsl:attribute>
    
          <xsl:element name="office:body">
            <xsl:element name="office:text">
              <xsl:element name="text:p">Hello world.
              </xsl:element>
              <xsl:element name="text:p">Goodbye world.
              </xsl:element>
            </xsl:element>
          </xsl:element>
    
        </xsl:element>
      </xsl:template>
    </xsl:stylesheet>
    

    into

    <office:document xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
                     xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
                     office:version="1.2"
                     office:mimetype="application/vnd.oasis.opendocument.text">
       <office:body>
          <office:text>
             <text:p>Hello world.
              </text:p>
             <text:p>Goodbye world.
              </text:p>
          </office:text>
       </office:body>
    </office:document>