XSLT 1.0 to move namespace to child node

蹲街弑〆低调 提交于 2021-02-05 11:28:08

问题


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.

Source 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>

Desired XML:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Accounts x>
    <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>

Any bright ideas?


回答1:


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>.


来源:https://stackoverflow.com/questions/16361986/xslt-1-0-to-move-namespace-to-child-node

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!