【问题标题】:XSL select all node where not node of another nodeXSL选择不是另一个节点的节点的所有节点
【发布时间】:2010-08-09 13:26:42
【问题描述】:

这是我的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>

【问题讨论】:

  • 好问题 (+1)。目前请参阅我的答案以获得完整且唯一正确的解决方案。

标签: xml xslt xpath


【解决方案1】:

这种转变

<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)]/*

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

  1. &lt;xsl:for-each&gt; 指令中,我们检查当前节点的名称是否不是criteria 的任何子节点的名称之一,并且只复制这样的节点:

self::node()[not(/*/criteria/*[name()=name(current())])]

此 XPath 表达式仅在不存在 /*/criteria 的子节点且其名称与当前节点的名称 (not(/*/criteria/*[name()=name(current())])) 相同时选择当前节点 (self::node())。

这里我们使用not(someNode-Set)false() 的事实,仅当节点集someNode-Set 为空时。

【讨论】:

    【解决方案2】:

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

    第1步:下面将选择所有不在条件区域中的节点(因此所有没有名为“criteria”的父节点的节点)

    //*[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(.)) -- 限制与条件部分中的节点名称不同的节点

    and not(*) - 仅限于没有任何子节点的节点(因此是您想要的叶节点。)

    因此,如果您要执行以下操作:

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

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

    subel1 : subel2
    

    希望这会有所帮助。

    干杯,

    凯西

    【讨论】:

    • 此解决方案在我的回答中应用于 XML 文档时会产生两个元素名称,但正确的结果只有一个元素名称。
    • 确实,我的解决方案不适用于您提供的 xml。但是,这与他提供的 xml 不同。我的解决方案确实适用于他的 xml。话虽如此,您的解决方案更强大。这就是我给它评分的原因!
    【解决方案3】:

    您是否缺少 xmlcode?如果您输入代码并在编辑器中将其标记为源代码(带有“101 010”的按钮)会更容易提供帮助

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-17
      • 2011-08-26
      • 1970-01-01
      相关资源
      最近更新 更多