xpath 'или' ведет себя как union ('|') с xmllib2

У меня есть такие XML-документы, как:

<rootelement>
<myelement>test1</myelement>
<myelement>test2</myelement>
<myelement type='specific'>test3</myelement>
</rootelement>

Я хотел бы получить конкретный myelement и , если его нет, , затем первый. Поэтому я пишу:

/rootelement/myelement[@type='specific' or position()=1]

The В спецификации XPath говорится о выражении 'or', которое:

Правый операнд не оценивается, если левый операнд принимает значение true

Проблема в том, что libxml2-2.6.26, похоже, применяется объединение обоих выражений, возвращающее «Набор из 2 узлов» (например, используя xmllint --shell ).

Это libxml2 или я что-то делаю не так?

6
задан foudfou 16 August 2010 в 14:39
поделиться

2 ответа

Краткий ответ: ваш селектор не выражает то, что, по вашему мнению, он делает.


Оператор или - это объединение.

Указанная вами часть спецификации («Правый операнд не оценивается ...») является частью стандартного короткого замыкания логической логики .

Вот почему вы получаете набор из двух узлов для примера ввода: XPath просматривает каждый myelement , который является дочерним для корневого элемента , и применяет [@ type = 'specific' или position () = 1] для каждого такого узла, чтобы определить, соответствует ли он селектору.

  1. test1 не соответствует @ type = 'specific' , но соответствует position () = 1 , поэтому соответствует весь селектор.
  2. test2 не соответствует @ type = 'specific' , а также не соответствует position () = 1 , поэтому не соответствует всему селектору.
  3. test3 соответствует @ type = 'specific' (поэтому XPath не должен проверять его положение - это часть короткого замыкания) поэтому он соответствует всему селектору.

Первый и последний совпадают со всем селектором, поэтому он возвращает набор из двух узлов.

Самый простой способ выбрать элементы так, как вы хотите, - это сделать это в два этапа. Вот псевдокод (я не знаю, в каком контексте вы на самом деле используете XPath, и я не слишком знаком с написанием селекторов синтаксиса XPath):

  1. Выберите элементы , соответствующие / rootelement / myelement [@ type = 'specific']
  2. Если elements пусто, выберите элементов , соответствующих / rootelement / myelement [position () = 1]
10
ответ дан 8 December 2019 в 13:43
поделиться

@Matt Ball очень хорошо объяснил причину вашей проблемы.

Вот однострочник XPath, который выбирает именно то, что вы хотите :

/*/myelement[@type='specific'] | /*[not(myelement[@type='specific'])]/myelement[1] 
7
ответ дан 8 December 2019 в 13:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: