How can I dynamically set the default namespace declaration of an XSLT transformation's output XML?

前端 未结 3 1448
长发绾君心
长发绾君心 2021-02-04 20:04

I can do it, but not for the default namespace, using the . If I try to do it for the default namespace:



        
相关标签:
3条回答
  • 2021-02-04 20:23

    Try this:

    <xsl:template match="root">
      <xsl:param name ="ns">my-computed-namespace</xsl:param>
      <xsl:element name="newRoot" namespace="{$ns}"/>
    </xsl:template>
    

    Then you can call that like so:

        <xsl:apply-templates select="root">
          <xsl:with-param name="ns" select="computationXPath"/>
        </xsl:apply-templates>
    

    EDIT Or with a variable instead of a param:

      <xsl:variable name ="ns">my-computed-namespace</xsl:variable>
      <xsl:template match="root">
        <xsl:element name="newRoot" namespace="{$ns}">
           <xsl:apply-templates/>
        </xsl:element>
      </xsl:template>
    

    (no need to call templates with-param)

    0 讨论(0)
  • 2021-02-04 20:25

    In addition to @Tomalak who has provided the precise answer, do note that <xsl:namespace> is not intended to create a namespace declaration to be used by the XSLT processor generally with all elements or attributes.

    The purpose of <xsl:namespace> is to create a specific namespace node. This node has a limited scope only: the current element or attribute, and all children of the current node, if they do not re-assign the prefix to another namespace-uri.

    Using <xsl:namespace> is necessary only if we want to create a namespace dynamically for a namespace-uri that must be generated dynamically (was not known statically at the start of the transformation). Such cases are extremely rare.

    In all cases when the desired namspace-uri is known statically, simply declare this namespace at a suitable level of visibility (usually at the <xsl:stylesheet> instruction) and then simply use the associated prefix, anywhere this namespace must be used.

    UPDATE: I have just confirmed in a dialog with specialists in another forum that this is not possible to do with <xsl:namespace>. It adds a namespace node with no name to the current element, but literal result elements are copied 1:1 and remain in their (no) namespace.

    Here is how Dr. Michael Kay, the Editor of the W3C WG on XSLT explains this:

    "You need to create elements and attributes with the correct expanded name at the time you create them. If that means using xsl:element, so be it. xsl:namespace can only be used to create additional namespace nodes to those that are created automatically for the prefixes/uris used in element and attribute names; it can't be used to modify the name of an element or attribute node. As always, to understand this you need to understand the data model for namespaces. An element/attribute name is a triple, containing (prefix, uri, localname). A namespace node is a pair (prefix, uri). There is a consistency rule that if an element or attribute name exists containing prefix=P uri=U then there must be a namespace node (P, U). The namespace fixup process ensures that this namespace node is created automatically when you create an element or attribute. xsl:namespace is there to allow you to create additional namespace nodes, typically for namespaces used in QName-valued content".

    If such result is needed, the solution is to use a second pass and to convert any element belonging to "no namespace" to the desired new namespace.

    This is the transformation to use in the second pass (the two passes can be combined into a single stylesheet/transformation):

    <xsl:stylesheet  version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
      <xsl:variable name="vUrl" select="'my:Url'"/>
    
     <xsl:template match="*[namespace-uri()='']">
       <xsl:element name="{name()}" namespace="{$vUrl}">
         <xsl:copy-of select="@*"/>
         <xsl:apply-templates/>
       </xsl:element>
    
     </xsl:template>
    </xsl:stylesheet>
    

    When the above transformation is applied on the following sample (pass-1-result) xml document:

    <a>
      <b>
        <c/>
      </b>
    </a>
    

    The desired result is produced:

    <a xmlns="my:Url">
        <b>
            <c/>
        </b>
    </a>
    
    0 讨论(0)
  • 2021-02-04 20:47

    Simple:

    <xsl:stylesheet
     version="1.0"
     xmlns:xsl="..."
     xmlns="default output namespace for unprefixed elements"
    >
      <!-- ... -->
    </xsl:stylesheet>
    
    0 讨论(0)
提交回复
热议问题