XSLT - 当前节点等于上一个节点时删除节点

时间:2018-05-30 04:12:36

标签: html xml xslt

我需要为xml编写XSLT,其中包含以下格式。

<books>
<book>
 <a>name</a>
 <a>name</a>
 <b>name</b>
 <b>name</b>
</book>
</books>

我需要在某些条件下消除重复的子节点。

  1. 仅当(当前节点==上一个节点)应该删除它。
  2. ie ..如果前一个节点(元素)是<a>而当前节点(元素)也是<a>,那么应该删除一个节点。

    以上输出,

    `<a>name</a>`
    
    `<b>name</b>`
    

    请帮我这样做。

2 个答案:

答案 0 :(得分:2)

在XSLT 2或3中,您可以轻松地将相邻的兄弟元素按其节点名称与for-each-group select="*" group-adjacent="node-name()"分组,并简单地输出每个组中的第一个项目(等于上下文项.):< / p>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="3.0">

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:output method="xml" indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="book">
      <xsl:copy>
          <xsl:for-each-group select="*" group-adjacent="node-name()">
              <xsl:copy-of select="."/>
          </xsl:for-each-group>
      </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/6qVRKw4/1

答案 1 :(得分:1)

据我所知,你想省略叶元素(没有子元素) 如果它有一个以前的兄弟,其中:

  • 也是叶元素
  • 具有同名
  • 具有相同的文字内容

所以最直观的解决方案(我认为)是写一个空模板, 只匹配这些节点:

<xsl:template match="*[not(*)][preceding-sibling::*[1][not(*)]
  [name() = current()/name()][text() = current()/text()]]"/>

匹配属性的简要说明:

  • *[not(*)] - 每个没有子元素的元素(叶元素)。
  • [ - 第二个谓词的开头。
    • preceding-sibling::*[1] - 采取前面的第一个兄弟姐妹。
    • [not(*)] - 不得有任何子元素。
    • [name() = current()/name()] - 它的名称必须与 “开始”元素。
    • [text() = current()/text()] - 必须与文字相同 “开始”元素。
  • ] - 第二个谓词的结尾。

当然,脚本还必须包含身份模板

对于具有位扩展源的工作示例,请参阅http://xsltransform.net/jxN8Nqm

如果不需要相同文本的要求,请删除相应的文本 谓词片段。