递归 XPath 的条件



如何在 XPath 中使用递归 AND 条件选择?

例如,给定此文档:

<root xmlns:foo="http://www.foo.org/" xmlns:bar="http://www.bar.org">
  <file name="foo.mp4">
    <chunks>
      <file>
        <chunks>
          <file>
          <chunks>
            <file>1</file>
            <file>2</file>
            <file>3</file>
            <file>4</file>
          </chunks>
          </file>
          <file>
          <chunks>
            <file>5</file>
            <file>6</file>
            <file>7</file>
            <file>8</file>
          </chunks>
          </file>
        </chunks>
      </file>
      <file>
        <chunks>
          <file>
          <chunks>
            <file>9</file>
            <file>10</file>
            <file>11</file>
            <file>12</file>
          </chunks>
          </file>
          <file>
          <chunks>
            <file>13</file>
            <file>14</file>
            <file>15</file>
            <file>16</file>
          </chunks>
          </file>
        </chunks>
      </file>
    </chunks>
  </file>
</root>

我只想选择:

<file>1</file>
<file>2</file>
<file>3</file>
<file>4</file>

所以,有效地这个:

//[name="foo.mp4"]/chunks/*[1]/chunks/*[1]/*

但是使用通用方法 - 即可以覆盖更深嵌套对象的东西。像这样:

//[name="foo.mp4"]/(chunks/*[1]/)+/*

(cond)+不是 XPath 语法,而是我想要的类似正则表达式的表示。

归意味着自引用,在XPath中不直接可用。 忽略元素干预级别的常用方法是通过descendant-or-self轴(//),由所需的属性锚定。

例如,以下每个 XPath 表达式,

  • 值小于 5 的所有file元素:

    //file[number() < 5]
    
  • 前 4 个叶子file元素:

    //file[not(*)][count(preceding::file[not(*)]) < 4]
    
  • 祖先没有前辈的file叶元素:

    //file[not(*)][not(ancestor::*[preceding::*])]
    

将选择

<file>1</file>
<file>2</file>
<file>3</file>
<file>4</file>

根据要求。

据我所知,没有递归XPath这样的东西。因此,您需要将 XPath 与其他一些东西(如 XSLT 或编程语言)结合使用,以便能够执行递归。使用纯 XPath,如果可能的话,您需要以不同的方式制定需求。

我不知道这是否适用于您的实际数据,但是您是否可以将要求表述为以下内容,例如:

"在file[@name='foo.mp4']中,找到第一个包含<file><chunk>,即<file>不包含任何元素,只包含文本节点的元素,并返回<file>元素"

那么将有一个可能的纯 XPath 解决方案:

(//file[@name='foo.mp4']//chunks[not(file/*)])[1]/file

给定有问题的示例 XML,在测试here时,上述 XPath 表达式返回file 1 到 4 的预期输出。

最新更新