如何在XPath中使用递归和条件选择?
例如,鉴于此文件:
Tickable
我想选择:
<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]/)+/*
不是XPath语法,而是类似于我想要的正则表达式。
答案 0 :(得分:1)
递归意味着自引用,并且在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>
根据要求。
答案 1 :(得分:1)
据我所知,没有递归XPath这样的东西。因此,您需要将XPath与其他一些内容(如XSLT或编程语言)结合起来才能进行递归。使用纯XPath,如果可能,您需要以不同方式制定要求。
我不知道这是否适用于您的实际数据,但如果您可以将要求表达为以下内容,例如:
&#34;在
file[@name='foo.mp4']
内,找到包含 leaf<chunk>
的第一个<file>
,即不包含<file>
元素39; t包含任何元素,仅包含文本节点,并返回 leaf<file>
元素&#34;
然后会有一个可能的纯XPath解决方案:
(//file[@name='foo.mp4']//chunks[not(file/*)])[1]/file
给出了相关的示例XML,在测试here
时,上述XPath表达式返回file
1到4的预期输出。