如何在 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 的预期输出。