XSLT 1.0 to move namespace to child node

前端 未结 1 1384
清歌不尽
清歌不尽 2021-01-27 11:12

I only have access to xpath 1.0 commands and functions. I need to move the namespace declaration from the root node to a child node where that namespace starts to be used.

相关标签:
1条回答
  • 2021-01-27 11:28

    Here's one way to do it.

    When this XSLT:

    <?xml version="1.0"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
      <xsl:output omit-xml-declaration="no" indent="yes"/>
      <xsl:strip-space elements="*"/>
    
      <xsl:template match="@*|node()">
        <xsl:copy>
          <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="Accounts">
         <Accounts>
           <xsl:apply-templates />
         </Accounts>
      </xsl:template>
    
    </xsl:stylesheet>
    

    ...is applied against the provided XML:

    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <Accounts xmlns:test="http:example.com/test1">
      <ParentAccount>10113146</ParentAccount>
      <test1>test1</test1>
      <test2>test2</test2>
      <test:Siblings>
        <test:CustomerNumber>10113146</test:CustomerNumber>
        <test:CustomerNumber>120051520</test:CustomerNumber>
      </test:Siblings>
    </Accounts>
    

    ...the wanted result is produced:

    <?xml version="1.0"?>
    <Accounts>
      <ParentAccount>10113146</ParentAccount>
      <test1>test1</test1>
      <test2>test2</test2>
      <test:Siblings xmlns:test="http:example.com/test1">
        <test:CustomerNumber>10113146</test:CustomerNumber>
        <test:CustomerNumber>120051520</test:CustomerNumber>
      </test:Siblings>
    </Accounts>
    

    Explanation:

    The explanation behind why this works starts with a section from the Namespaces in XML 1.0 spec:

    The scope of a namespace declaration declaring a prefix extends from the beginning of the start-tag in which it appears to the end of the corresponding end-tag, excluding the scope of any inner declarations with the same NSAttName part. In the case of an empty tag, the scope is the tag itself.

    Such a namespace declaration applies to all element and attribute names within its scope whose prefix matches that specified in the declaration.

    In a nutshell, this means that when a namespace is declared on an element, it is, in effect, defined for use on all elements underneath that original scope. Additionally, should a namespace be used on an element without first being defined elsewhere, the appropriate definition occurs on that element.

    So, using your document and my XSLT, let's see how this plays out:

    1. The first template - The Identity Template - copies all nodes and attributes as-is from the source XML to the result XML.
    2. The second template replaces the original <Accounts> element with a new one; incidentally, this new <Accounts> element does not define the http:example.com/test1 namespace. Finally, this template applies templates to all child elements of <Accounts>.
    3. When the processor reaches <test:Siblings>, it sees a namespace that, although present in the original XML, has not been properly defined in the result document. As such, this definition is added to <test:Siblings>.
    0 讨论(0)
提交回复
热议问题