使用 XSL 用新节点替换 XML 节点
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2952562/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
using XSL to replace XML nodes with new nodes
提问by developer
I need an XSL solution to replace XML nodes with new nodes.
我需要一个 XSL 解决方案来用新节点替换 XML 节点。
Say I have the following existing XML structure:
假设我有以下现有的 XML 结构:
<root>
<criteria>
<criterion>AAA</criterion>
</criteria>
</root>
And I want to replace the one criterion node with:
我想用以下方法替换一个标准节点:
<criterion>BBB</criterion>
<criterion>CCC</criterion>
<criterion>DDD</criterion>
So that the final XML result is:
这样最终的 XML 结果是:
<root>
<criteria>
<criterion>BBB</criterion>
<criterion>CCC</criterion>
<criterion>DDD</criterion>
</criteria>
</root>
I have tried using substring-before and substring-after to just copy the first half of the structure, then just copy the second half (in order to fill in my new nodes in between the two halves) but it appears that the substring functions only recognize text in between the nodes' tags, and not the tags themselves like I want them to. :( :(
我尝试使用 substring-before 和 substring-after 来复制结构的前半部分,然后复制后半部分(为了填充两半之间的新节点),但似乎子字符串仅起作用识别节点标签之间的文本,而不是我想要的标签本身。:( :(
Any other solutions?
还有其他解决方案吗?
回答by John Saunders
XSL cannot replaceanything. The best you can do is to copy the parts you want to keep, then output the parts you want to change instead of the parts you don't want to keep.
XSL不能替代任何东西。你能做的最好的事情就是复制你想保留的部分,然后输出你想改变的部分而不是你不想保留的部分。
Example:
例子:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
<xsl:output method="xml" indent="yes"/>
<!-- This is an identity template - it copies everything
that doesn't match another template -->
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<!-- This is the "other template". It says to use your BBB-DDD elements
instead of the AAA element -->
<xsl:template match="criterion[.='AAA']">
<xsl:element name="criterion">
<xsl:text>BBB</xsl:text>
</xsl:element>
<xsl:element name="criterion">
<xsl:text>CCC</xsl:text>
</xsl:element>
<xsl:element name="criterion">
<xsl:text>DDD</xsl:text>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
The template match @* | node()matches any attribute or any other kind of node. The trick is that template matches have priorities. You can think of the rule as being "the more specific match wins". Anythingis going to be more specific than "any attribute or other node". This makes the "identity" match a very low priority.
模板匹配@* | node()匹配任何属性或任何其他类型的节点。诀窍是模板匹配具有优先级。您可以将规则视为“越具体的比赛获胜”。任何东西都将比“任何属性或其他节点”更具体。这使得“身份”匹配的优先级非常低。
When it ismatched, it simply copies any nodes it finds inside the matched attribute or node.
当它被匹配时,它简单地拷贝的任何节点找到匹配的属性或节点的内部。
Any other templates you have will have a higher priority. Whatever they match, it's the code inside the more specific template that will have effect. For example, if you simply removed everything inside of the criterion[.='AAA']template, you'd find that you had copied your input exactly, except for the "AAA" element.
您拥有的任何其他模板将具有更高的优先级。无论它们匹配什么,更具体的模板中的代码都会起作用。例如,如果您简单地删除criterion[.='AAA']模板中的所有内容,您会发现您完全复制了您的输入,除了“AAA”元素。
回答by Dimitre Novatchev
Here is one correct solution, which is probably one of the shortest:
这是一个正确的解决方案,它可能是最短的解决方案之一:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="criterion[. = 'AAA']">
<criterion>BBB</criterion>
<criterion>CCC</criterion>
<criterion>DDD</criterion> </xsl:template>
</xsl:stylesheet>
When this transformation is applied on the provided XML document, the wanted result is produced:
当此转换应用于提供的 XML 文档时,会产生所需的结果:
<root>
<criteria>
<criterion>BBB</criterion>
<criterion>CCC</criterion>
<criterion>DDD</criterion>
</criteria>
</root>
Do note:
请注意:
The use of the identity template.
How the identity template is overriden by a specific template -- only for a
criterionelement, whose string value is'AAA'.
身份模板的使用。
特定模板如何覆盖标识模板——仅适用于
criterion字符串值为的元素'AAA'。
回答by Dave G
Under the general rule of more-than-one-way-to-skin-a-cat
在多于一种方式给皮肤一只猫的一般规则下
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml"/>
<xsl:template match="/">
<xsl:apply-templates />
</xsl:template>
<!--
when you capture a node with the text 'AAA'
emit the BBB, CCC, DDD nodes
-->
<xsl:template match="criterion[text() = 'AAA']">
<xsl:element name="criterion">
<xsl:text>BBB</xsl:text>
</xsl:element>
<xsl:element name="criterion">
<xsl:text>CCC</xsl:text>
</xsl:element>
<xsl:element name="criterion">
<xsl:text>DDD</xsl:text>
</xsl:element>
</xsl:template>
<!-- identity template -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

