问题
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:
- The first template - The Identity Template - copies all nodes and attributes as-is from the source XML to the result XML.
- The second template replaces the original
<Accounts>
element with a new one; incidentally, this new<Accounts>
element does not define thehttp:example.com/test1
namespace. Finally, this template applies templates to all child elements of<Accounts>
. - 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