XSLT:删除除第一次出现的给定节点之外的所有节点

时间:2009-10-12 17:59:33

标签: xslt

我有这样的XML:

<MyXml>  
  <RandomNode1>  
    <TheNode>  
      <a/>  
      <b/>  
      <c/>  
    </TheNode>  
  </RandomeNode1>  
  <RandomNode2>  
  </RandomNode2>  
  <RandomNode3>  
    <RandomNode4>  
      <TheNode>  
        <a/>  
        <b/>  
        <c/>  
      </TheNode>    
    </RandomNode4>  
  </RandomNode3>  
</MyXml>

<TheNode>出现在整个XML中但不在同一级别,通常在其他节点内。我需要做的是消除所有出现的<TheNode>除了第一次。其余的都是多余的,占用空间。什么是XSL可以做到这一点?

我有这样的事情:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">  
  <xsl:output method="xml" indent="yes"/>  

  <xsl:template match="node() | @*">  
    <xsl:copy>  
      <xsl:apply-templates select="node() | @*" />  
    </xsl:copy>  
  </xsl:template>  

  <xsl:template match="//TheNode[position()!=1]">
  </xsl:template>

</xsl:stylesheet>

但这不正确。有什么建议吗?

3 个答案:

答案 0 :(得分:4)

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>
  <xsl:template match="node() | @*">
    <xsl:copy>
      <xsl:apply-templates select="node() | @*"/>
    </xsl:copy>
  </xsl:template>
  <xsl:template match="TheNode[preceding::TheNode]"/>
</xsl:stylesheet>

答案 1 :(得分:2)

//TheNode[position()!=1]不起作用,因为此处position()相对于每个<TheNode>的父上下文。它将选择所有<TheNode> s,这些{{1}}不在其各自的父级中。

但你走在正确的轨道上。您的含义是

(//TheNode)[position()!=1]

请注意括号 - 它们会将谓词应用于整个选定的节点集,而不是单独应用于每个节点。

不幸的是,即使这是有效的XPath表达式,它也无法作为匹配模式。匹配模式必须对单个节点有意义(适用),它不能是选择表达式。

所以@ Alohci的解决方案,

//TheNode[preceding::TheNode]

是表达你想要的正确方法。

答案 2 :(得分:0)

该模式的其他方法是:

<xsl:template match="TheNode[generate-id()
                             != generate-id(/descendant::TheNode[1)]"/>

注意:绝对表达式更有可能获得相对表达式的优化整数,如preceding::TheNode