Как я могу адресовать узлы между двумя элементами - PullRequest
0 голосов
/ 16 апреля 2019

Я хочу обратиться к узлам между двумя элементами; второй идентифицируется с помощью @xml: id, первый ссылается на второй через этот идентификатор. Чаще всего другие два элемента (которые не имеют отношения к этой проблеме / должны обрабатываться как обычно) находятся между этими двумя элементами.

<root>
... text i'm not interested in ...
<A ref="#id_1"/> interesting <C>text</C> no 1 <B xml:id="id_1"/>
... text i'm not interested in ...
<A ref="#id_2"/> interesting text no 2 <B xml:id="id_2"/>
... text i'm not interested in ...
</root>

То, что я ищу, - это команда xPath, которая выбирает для каждого элемента «A» с атрибутом «ref» узлы, следующие за этим элементом, до конкретного элемента «B» с идентификатором, указанным в «ref».

Таким образом, в приведенном выше примере для первого «A» следует выбрать

"interesting <C>text</C> no 1"

и для второго "А"

"interesting text no 2"

(и т. Д .; число элементов «A» и «B» довольно велико).

Пока что мое приблизительное предположение состоит в том, что пересечение fn может быть частью решения. (Я использую xPath 2.0.)

Ответы [ 2 ]

0 голосов
/ 16 апреля 2019

Это выражение XPath 2.0

/root/(
   for $a in A, 
       $b in B[concat('#', @xml:id) = $a/@ref][1] 
   return .//text()[$b >> .][. >> $a]
)

Выбирает этот текстовые узлы (добавлена ​​цитата для ясности):

' interesting '
'text'
' no 1 '
' interesting text no 2 '

Тест в https://xsltfiddle.liberty -development.net / bFN1y9t

Обратите внимание : использование for выражения для "внутреннего соединения".

В XPath 1.0 нет способа объявить замыкание, поэтому нет и способа сделать «внутреннее соединение». Но если вы уверены, что между начальными и конечными отметками нет совпадений, вы можете использовать:

/root//text()[
  (preceding::A|preceding::B)[last()][self::A]
][(following::A|following::B)[1][self::B]
]

или

/root//text()[
   preceding::*[self::A|self::B][1][self::A]
][following::*[self::A|self::B][1][self::B]
]

Тест в http://www.xpathtester.com/xpath/a3051d2ad3af3423502b221bef6a580e

Отредактированный вопрос

Я ищу команду xPath, которая выбирает для каждого элемент "A" с атрибутом "ref" узлы, следующие за этим элементом до определенного элемента "B" с идентификатором, указанным в "ref".

Если вы хотите теперь узлы вместо текстовых узлов-потомков, просто замените путь в выражении:

XPath 2.0 выражение

/root/(
   for $a in A, 
       $b in B[concat('#', @xml:id) = $a/@ref][1] 
   return node()[$b >> .][. >> $a]
)

XPath 1.0 выражение

/root/node()[
  (preceding::A|preceding::B)[last()][self::A]
][(following::A|following::B)[1][self::B]
]
0 голосов
/ 16 апреля 2019

Как написал пользователь choroba в комментарии, вы можете получить значения, используя Оси XPath :

//A/following-sibling::text()[1]

Чтобы получить только элементы с атрибутом ref , вы можете использовать:

//A[@ref]/following-sibling::text()[1]

Обновление : Возможно Метод Кейсиана для пересечения наборов узлов может помочь вам ( см. Это SO ):

/*/A[1]/following-sibling::node()[count(.|/*/B[1]/preceding-sibling::node()) = count(/*/B[1]/preceding-sibling::node())]

Чтобы получить второй случай, просто замените все [1] на [2].

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...