【问题标题】:Fetch elements referring to exactly two other elements in a single XPath expression在单个 XPath 表达式中获取恰好引用两个其他元素的元素
【发布时间】:2010-11-12 16:25:40
【问题描述】:

我需要获取一个节点集,其中包含恰好引用其他两个元素的元素。我不知道如何在单个 XPath 表达式中做到这一点。

我的(简化的)源 XML 如下所示:

<group>
   <id>1337</id>
</group>
<group>
   <id>1338</id>
</group>
<member>
   <id>31415</id>
   <groupId>1337</groupId>
</member>
<member>
   <id>31416</id>
   <groupId>1337</groupId>
</member>
<member>
   <id>31417</id
   <groupId>1338</groupId>
</member>

现在,我想选择恰好引用两个 &lt;member&gt;s 的所有 &lt;group&gt; 节点,这将导致仅返回 id=1337 的组。我尝试了以下...

<xsl:variable name="groupsWithTwoMembers" select="group[count(../member[id=??]) = 2]"/>

...显然在'??'我需要在 XPath 表达式的开头插入我选择的组的 groupId,但我想不出一种方法来获得这个 groupId。外面的人能想到一个吗?谢谢!

【问题讨论】:

  • 好问题,+1。除了@Alejandro 的好答案,请参阅我对 XPath2.0 单线解决方案的回答。 :)
  • 您好 Dimitre,感谢您的赞许。您的 XPath2.0 解决方案看起来也不错,但不幸的是,由于我们项目的软件架构,我坚持使用 XPath1.0。无论如何感谢您的意见!

标签: xml xslt xpath


【解决方案1】:

问题在于谓词过滤了以前选择的节点,每个节点都作为上下文。因此,您需要引入上下文引用。

这可以通过变量/参数引用或current() 函数来完成(导致整个 XSLT 指令的上下文节点)。

另外,在这种有交叉引用的情况下,最好使用键:

<xsl:key name="kMemberByGroupId" match="member" use="groupId"/>  
...
<xsl:variable name="groupsWithTwoMembers" 
              select="group[count(key('kMemberByGroupId',id)) = 2]"/>

【讨论】:

  • 谢谢,亚历杭德罗!我实施了您的建议(使用密钥),它就像一个魅力!你真的帮了我很多,非常感谢!
  • @Hanno:很高兴它对你有帮助!
【解决方案2】:

XPath2.0

$p/group[count(index-of($p/member/groupId, id)) eq 2]

其中$p 是提供的 XML 片段的父级。

【讨论】:

  • @Dimitre:+1 好答案。您是否意识到您对 fn:index-of 用于“不再重复”的使用的发现可以用于分组而不需要 for ... in distinct-values()
  • @Alejandro:是的,我没有在这个 XPath 表达式中使用 distinct-values()
  • @Dimitre:我的意思是$sequence[index-of($sequence,.)[2]] 给出了重复的值,但$sequence[index-of($sequence,.)[1]] 给出了“同类中的第一个”。
  • @Alejandro:是的,但我不确定哪个更有效。
  • @Dimitre:你说得对。区别在于语义:fn:distinct-values() 应该更高效,但结果是一系列原子值。
【解决方案3】:

你应该看看当前节点和上下文节点之间的区别。它们通常是相同的,但是在处理谓词时,上下文节点(通常用 . 表示)与您所针对的节点匹配。在这种情况下,您应该使用 current() 来访问当前节点而不是上下文节点。

【讨论】:

  • 正如 Mike Kay 所表达的,current() 返回上下文节点,因为它位于整个 XPath 表达式的“外部”。但是在这种情况下,OP 有select="group[count(../member[id=??]) = 2]",这不是我们想要的 XPath 表达式之外的上下文节点;它是每个组的上下文节点(即在外部谓词之外)。不幸的是,XPath 1.0 没有标准的方法来访问这个“中间”上下文。
【解决方案4】:

在 XPath 1.0 中这是不可能的。在 XPath 2.0 中,您可以执行以下操作(未经测试):

for $a in fn:distinct-values(//group/id) 
  if count(../../member[@id = $a]) = 2 then return $a

【讨论】:

  • 除了缺少右括号外,它看起来不太正确...//group[...] 没有意义,因为谓词不使用除 .. 之外的上下文组,它对所有组都是一样的。相反,也许你的意思是for $a in fn:distinct-values(//group/id) if count(../../member[@id = $a]) = 2 then return $a
  • 感谢您的收获。你的提议看起来是正确的。我更新了我的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-18
  • 2010-12-16
  • 2017-12-25
  • 2023-02-24
  • 1970-01-01
相关资源
最近更新 更多