XSL选择所有节点,而不是另一个节点的节点

时间:2010-08-09 13:26:43

标签: xml xslt xpath

这是我的xml

<element1> <subel1/> </element1> <element2> <subel2/> </element2> <element3> <subel3/> </element3> <criteria> <subel3/> </criteria>

我如何选择xsl不属于条件子节点的所有节点? 喜欢这些

 <subel1/> <subel2/>

这是怎么做到的?

如果xml格式为:

<element1> 
<el> subel1 </el>
</element1>
 <element2> 
<el> subel2 
</el> 
</element2> 
<element3> 
<el> subel3 </el> 
</element3> 
<criteria> 
<subel3/> 
</criteria>

3 个答案:

答案 0 :(得分:6)

此转化

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

 <xsl:template match="/">
  <xsl:for-each select=
  "/*/*[not(self::criteria)]/*">
   <xsl:copy-of select=
   "self::node()[not(/*/criteria/*[name()=name(current())])]"/>
  </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

应用于此XML文档(基于提供的XML片段,但将XML片段包含在顶部元素中,并将另外一个子元素添加到criteria以使问题变得不那么简单) :

<t>
    <element1>
        <subel1/>
    </element1>
    <element2>
        <subel2/>
    </element2>
    <element3>
        <subel3/>
    </element3>
    <criteria>
        <subel3/>
        <subel1/>
    </criteria>
</t>

产生想要的结果(在撰写时没有其他公布的答案会产生正确的结果):

<subel2/>

分步说明

  1. XPath表达式:

    /*/*[not(self::criteria)]/*

  2. 选择其父元素是未命名为"criteria"的元素的每个元素,并且该元素是文档顶部元素的子元素。

    1. <xsl:for-each>指令中,我们检查当前节点的名称是否不是criteria的任何子项的名称之一,并且只复制这样的节点:
    2. self::node()[not(/*/criteria/*[name()=name(current())])]

      仅当不存在self::node()的子节点时,此XPath表达式才会选择当前节点(/*/criteria),其子节点的名称与当前节点的名称相同({{1} })。

      我们仅在节点集not(/*/criteria/*[name()=name(current())])为空时使用not(someNode-Set)false()的事实。

答案 1 :(得分:2)

最简单的方法是构造一个xpath表达式,它对条件节点进行交叉检查。例如:

步骤1:以下将选择不在标准区域中的所有节点(因此所有没有父级的节点都标记为“条件”)

//*[name(..) != 'criteria'] 

步骤2:过滤掉也出现在critera部分

中的所有节点
//*[name(..) != 'criteria' and not(name(//criteria/*) = name(.))]

现在最后一条语句将选择与条件节点不匹配的所有节点。但是你只想要子节点,所以我们可以修改选择器只抓取“子元素”元素或没有子节点的叶子元素。

//*[name(..) != 'criteria' and not(name(//criteria/*) = name(.)) and not(*)]

所以这是我们每个条件的细分再次出现:

name(..)!='criteria' - 对不在条件部分的节点的限制

not(name(// criteria / *)= name(。)) - 对与标准部分中的节点名称不同的节点的限制

而不是(*) - 限制没有任何子节点的节点(所以你想要的叶子节点。)

所以,如果你做了类似的事情:

<xsl:for-each select="//*[name(..) != 'criteria' and not(name(//criteria/*) = name(.)) and not(*)]">
 <xsl:value-of select="name(current())"/> :
</xsl:for-each>

对于上面的示例,这将打印:

subel1 : subel2

希望这有帮助。

干杯,

凯西

答案 2 :(得分:1)

你不错过xmlcode吗?如果您输入代码并在编辑器中将其标记为源代码(带有“101 010”的按钮)将更容易提供帮助