我需要一个XSL解决方案来用新节点替换XML节点。
假设我有以下现有的XML结构:
<root>
<criteria>
<criterion>AAA</criterion>
</criteria>
</root>
我想用以下内容替换一个标准节点:
<criterion>BBB</criterion>
<criterion>CCC</criterion>
<criterion>DDD</criterion>
这样最终的XML结果是:
<root>
<criteria>
<criterion>BBB</criterion>
<criterion>CCC</criterion>
<criterion>DDD</criterion>
</criteria>
</root>
我已经尝试过使用substring-before和substring-after来复制结构的前半部分,然后只复制下半部分(为了填补两半之间的新节点),但似乎是substring函数只识别节点标签之间的文本,而不是我想要的标签本身。 :( :(
还有其他解决方案吗?
答案 0 :(得分:23)
XSL无法替换任何内容。您可以做的最好的事情是复制要保留的部分,然后输出您想要更改的部分,而不是您不想保留的部分。
示例:
<?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>
模板匹配@* | node()
匹配任何属性或任何其他类型的节点。诀窍是模板匹配具有优先级。您可以将规则视为“更具体的匹配胜利”。 任何将比“任何属性或其他节点”更具体。这使得“身份”匹配的优先级非常低。
当 匹配时,它只是复制它在匹配的属性或节点中找到的任何节点。
您拥有的任何其他模板都将具有更高的优先级。无论它们匹配什么,它都是更有效的模板中的代码。例如,如果您只是删除了criterion[.='AAA']
模板中的所有内容,则会发现您已完全复制了输入,但“AAA”元素除外。
答案 1 :(得分:6)
这是一个正确的解决方案,可能是最短的之一:
<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>
在提供的XML文档上应用此转换后,生成所需结果:
<root>
<criteria>
<criterion>BBB</criterion>
<criterion>CCC</criterion>
<criterion>DDD</criterion>
</criteria>
</root>
请注意:
使用身份模板。
特定模板如何覆盖标识模板 - 仅适用于criterion
元素,其字符串值为'AAA'
。
答案 2 :(得分:0)
根据超过一对一皮肤的一般规则
<?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>