【问题标题】:xpath: How to select only nearby parent siblings of current child node?xpath:如何仅选择当前子节点附近的父兄弟姐妹?
【发布时间】:2021-06-13 11:02:25
【问题描述】:

我正在使用 xpath 1.0,我想选择当前子节点的父节点的兄弟姐妹。

我所在的当前节点是<w:instrText>,我怎样才能获得仅在<!-- SELECT FROM HERE --><!-- SELECT TILL HERE -->范围内的父兄弟节点<w:r>

    <w:p>
      <w:pPr>
        <w:rPr>
          <w:lang w:val='en-US'/>
        </w:rPr>
      </w:pPr>
      <w:r>
        <w:t>TEXT 1</w:t>
      </w:r>
      <w:r w:rsidR='002D5530'>
        <w:t xml:space='preserve'> </w:t>
      </w:r>

      <!-- SELECT FROM HERE -->
      <w:r w:rsidR='002D5530'>
        <w:fldChar w:fldCharType='begin'/>
      </w:r>
      <w:r w:rsidR='002D5530'>
        <w:instrText xml:space='preserve'> SOME DYNAMIC TEXT THAT CAN CHANGE </w:instrText> <!-- My cursor is here! -->
      </w:r>
      <w:r w:rsidR='002D5530'>
        <w:fldChar w:fldCharType='separate'/>
      </w:r>
      <w:r w:rsidR='00E5783C'>
        <w:t>SOME DYNAMIC TEXT</w:t>
      </w:r>
      <w:r w:rsidR='002D5530'>
        <w:fldChar w:fldCharType='end'/>
      </w:r>
      <!-- SELECT TILL HERE -->

      <w:r w:rsidR='002D5530'>
        <w:fldChar w:fldCharType='begin'/>
      </w:r>
      <w:r w:rsidR='002D5530'>
        <w:instrText xml:space='preserve'> SOME DYNAMIC TEXT THAT CAN CHANGE </w:instrText>
      </w:r>
      <w:r w:rsidR='002D5530'>
        <w:fldChar w:fldCharType='separate'/>
      </w:r>
      <w:r w:rsidR='00E5783C'>
        <w:t>SOME DYNAMIC TEXT</w:t>
      </w:r>
      <w:r w:rsidR='002D5530'>
        <w:fldChar w:fldCharType='end'/>
      </w:r>
    </w:p>

这是我尝试过的,但只有 3 个节点...

../preceding-sibling::w:r[w:fldChar/@w:fldCharType='begin'] | ../following-sibling::w:r[w:fldChar/@w:fldCharType='end']

【问题讨论】:

  • 可以使用哪些模式来区分您想要的范围?范围是否总是以包含w:fldChar/@w:fldCharType='begin'w:r 开头?范围是否总是以包含w:fldChar/@w:fldCharType='end'w:r 结尾? w:r/w:* 节点是否总是按照此处所示的顺序出现(fldchar、instrText、fldChar、t、fldChar)?
  • @DavidDenenberg 1st:是的;第二:是;第三:是的; ;)

标签: xpath


【解决方案1】:

鉴于 XPath 1.0 的限制以及五个 w:r 元素的集合的顺序是一致的假设,您可以使用有点暴力的方法,例如:

(
  (../preceding-sibling::w:r[w:fldChar/@w:fldCharType='begin'])[last()],
  (../following-sibling::w:r[w:fldChar/@w:fldCharType='separate'])[position() = 1],
  (../following-sibling::w:r[w:t])[position() = 1],
  (../following-sibling::w:r[w:fldChar/@w:fldCharType='end'])[position() = 1]
)

构成四个元素的序列:

  • 前面的“开始”元素中的最后一个
  • 以下“独立”元素中的第一个
  • 以下“t”元素中的第一个(w:r 包含 w:t
  • 以下“结束”元素中的第一个

如果您还需要包含上下文的直接父级,则只需将..parent::*parent::w:r 添加到序列中:

(
  (../preceding-sibling::w:r[w:fldChar/@w:fldCharType='begin'])[last()],
  ..,
  (../following-sibling::w:r[w:fldChar/@w:fldCharType='separate'])[position() = 1],
  (../following-sibling::w:r[w:t])[position() = 1],
  (../following-sibling::w:r[w:fldChar/@w:fldCharType='end'])[position() = 1]
)

但是,如果您的输入文档很大或性能是一个重要因素,这可能效率不高。

如果您好奇为什么您的尝试返回了三个元素而不是两个,那可能是因为您选择了超出上下文位置的两个“结束”元素。这里的答案可能不是您所需要的,但我怀疑 last()/position() 谓词示例将为您指明正确的方向。

顺便说一句,如果您有机会将 XQuery 用于类似的事情,这是 XQuery 3“翻滚窗口”语法的完美用例,它可以很容易地识别同级组的边界并迭代组。

【讨论】:

  • 有了这个 xpath 查询,我有 4 个元素而不是 5 个
  • 你也期望父节点吗?问题是“父母兄弟姐妹”。
  • 更新了答案,提供了在选定节点序列中包含直接父节点的指南。
  • 顺便说一句..在我的情况下,逗号不起作用......我将它与|联合起来
  • 我相信形成逗号的序列应该是有效的 XPath 1.0 语法,但我也看到了某些处理器不完全兼容的这种行为。管道字符是联合运算符。在这个用例中它肯定会返回相同的节点,但我不确定是否保证节点的顺序被保留。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多