【问题标题】:How to get all preceding nodes regardless of the current position无论当前位置如何,如何获取所有前面的节点
【发布时间】:2025-12-17 00:40:01
【问题描述】:

我的 XML 结构

<root>
    <Q id="a">1</Q>
    <Q id="b">2</Q>
    <Q id="c">3</Q>
      <x> 
          <Q id="d">3.1</Q> 
          <Q id="e">3.2</Q>
          <Q id="f">3.3</Q>
      </x>
    <Q id="g">4</Q>
    <Q id="h">5</Q>
</root>

这是我的 XPath 表达式:

//Q[@id=$CurrentQid]/preceding::Q

无论当前位置如何,我都在尝试获取前面 Q 节点的列表(我将当前位置作为参数传递给我的 xslt) 当我在"a""b""c""g""h" 节点上时,它会返回正确的先前节点列表。但是当我在"d""e""f" 上时,它无法正常工作。

例如:当我的当前节点是"g"时它返回,

a,b,c,d,e,f

但是当我的当前节点是 "f" 时,它只返回

d,e,f

虽然我希望它是

a,b,c,d,e

如果有人能找到一个非常好的解决方案。

谢谢。

【问题讨论】:

  • 您确定此示例 xml 会发生这种情况吗?它不应该也不适合我。
  • 你能编辑问题并添加你的XSL吗?
  • 我仍然不知道会发生什么。看起来像前面的兄弟而不是前面的以某种方式执行。你用什么 xslt / xpaht 处理器?
  • @hr_117:我会说同样的话,除了如果 XPath 表达式使用 preceding-sibling::,来自上下文节点 g 的结果将不会包含 d,e,f做了。
  • 是的,你是对的,所以这真的很奇怪。

标签: xslt nodes


【解决方案1】:

使用

($yourNode/preceding::Q | $yourNode/ancestor::Q)/@id 

基于 XSLT 的验证

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

 <xsl:variable name="vQg" select="(//Q[@id='g'])[1]"/>
 <xsl:variable name="vQf" select="(//Q[@id='f'])[1]"/>

 <xsl:template match="/">
  "Preceding" $vQg:

  <xsl:for-each select=
  "($vQg/preceding::Q | $vQg/ancestor::Q)/@id">
   <xsl:value-of select="concat(., ' ')"/>
  </xsl:for-each>
=====================

  "Preceding" $vQf:

  <xsl:for-each select=
  "($vQf/preceding::Q | $vQf/ancestor::Q)/@id">
   <xsl:value-of select="concat(., ' ')"/>
  </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

当此转换应用于提供的 XML 文档时:

<root>
    <Q id="a">1</Q>
    <Q id="b">2</Q>
    <Q id="c">3</Q>
      <x>
          <Q id="d">3.1</Q>
          <Q id="e">3.2</Q>
          <Q id="f">3.3</Q>
      </x>
    <Q id="g">4</Q>
    <Q id="h">5</Q>
</root>

XPath 表达式被计算两次(针对您问题中的两个 Q 元素),结果的字符串值以空格分隔输出

  "Preceding" $vQg:

  a b c d e f 
=====================

  "Preceding" $vQf:

  a b c d e 

解释

preceding:: 轴不会按文档顺序选择所有前面的节点 -- 为此还需要使用 ancestor:: 轴。

来自W3C XPath 1.0 specification

"• 前面的轴包含与 在文档顺序中位于上下文节点之前的上下文节点, 排除任何祖先并排除属性节点和命名空间 节点"

【讨论】:

  • 这是对前面的一个很好的解释::。但是 xml 示例中的任何 Q 都没有 Q 祖先。因此前面的:: 应该有相同的结果。或者我在这里想念什么?
  • @hr_117,哦,我被问题中的缩进误导了。也许 OP 没有提供真实的文档(从缩进来看),他的问题正是由于没有考虑到 ancestor:: 轴。
  • 谢谢 Dimitre> 通过参考您的答案,我设法使用以下 xPath 表达式获得了预期的结果。 -------------------------------------------------- -------------------- ($yourNode//Q[@id]/preceding::Q | $yourNode//Q[@id]/ancestor::Q )