使用XSL用新节点替换XML节点

dev*_*per 9 xml xslt xpath

我需要一个XSL解决方案来用新节点替换XML节点.

假设我有以下现有的XML结构:

<root>
    <criteria>
        <criterion>AAA</criterion>
    </criteria>
</root>
Run Code Online (Sandbox Code Playgroud)

我想用以下内容替换一个标准节点:

<criterion>BBB</criterion>
<criterion>CCC</criterion>
<criterion>DDD</criterion>
Run Code Online (Sandbox Code Playgroud)

这样最终的XML结果是:

<root>
    <criteria>
        <criterion>BBB</criterion>
        <criterion>CCC</criterion>
        <criterion>DDD</criterion>
    </criteria>
</root>
Run Code Online (Sandbox Code Playgroud)

我已经尝试使用substring-before和substring-after来复制结构的前半部分,然后只复制下半部分(为了在两半之间填充我的新节点)但是看起来子串仅起作用识别节点标签之间的文本,而不是像我想要的那样识别标签本身.:( :(

还有其他方法吗?

Joh*_*ers 24

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>
Run Code Online (Sandbox Code Playgroud)

模板匹配@* | node()匹配任何属性或任何其他类型的节点.诀窍是模板匹配具有优先级.您可以将规则视为"更具体的匹配胜利".任何事情都会比"任何属性或其他节点"更具体.这使得"身份"匹配的优先级非常低.

当它匹配时,它简单地拷贝的任何节点找到匹配的属性或节点的内部.

您拥有的任何其他模板都将具有更高的优先级.无论它们匹配什么,它都是更有效的模板中的代码.例如,如果您只是删除了criterion[.='AAA']模板中的所有内容,您会发现您已完全复制了输入,但"AAA"元素除外.


Dim*_*hev 7

这是一个正确的解决方案,可能是最短的解决方案之一:

 <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>
Run Code Online (Sandbox Code Playgroud)

在提供的XML文档上应用此转换时,将生成所需的结果:

<root>
    <criteria>
        <criterion>BBB</criterion>
        <criterion>CCC</criterion>
        <criterion>DDD</criterion>
    </criteria>
</root>
Run Code Online (Sandbox Code Playgroud)

请注意:

  1. 使用身份模板.

  2. 身份模板如何被特定模板覆盖 - 仅适用criterion于其字符串值为的元素'AAA'.

  • @Dimitre:你的态度没有帮助.我试图回答这个问题.我犯了一个错误.我未修正的代码中的测试评估为`true()`.结果,样式表似乎有效.您没有理由"多关注"评论.如果你不能在这里参与社区活动(其中包括帮助纠正错误的答案),那么你可能会考虑另一个不同的问题,在这个问题中,你对无声的downvote的无益贡献将无法用到. (3认同)