Условия на рекурсивных XPath
Как я могу использовать рекурсивный И условный выбор в XPath?
Например, учитывая этот документ:
<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, а регулярное выражение того, что я хочу.
2 ответа
Рекурсия подразумевает самоссылку и не доступна напрямую в XPath. Обычный способ игнорировать промежуточные уровни элементов через descendant-or-self
ось (//
), закрепленный желаемым свойством.
Например, каждое из следующих выражений XPath,
Все
file
элементы со значениями менее 5://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']
найди первое<chunk>
который содержит лист<file>
т.е.<file>
элемент, который не содержит никакого элемента, только текстовые узлы и возвращает лист<file>
элементы"
тогда будет возможное чистое решение XPath:
(//file[@name='foo.mp4']//chunks[not(file/*)])[1]/file
данный образец XML в вопросе, ожидаемый результат file
1-4 возвращаются вышеприведенным выражением XPath при тестировании here
,