Использование XPath в SelectSingleNode: получение отдельного элемента из XML, если он присутствует

Мой XML выглядит так:

<?xml version=\"1.0\"?>
<itemSet>
       <Item>one</Item>
       <Item>two</Item>
       <Item>three</Item>
       .....maybe more Items here.
</itemSet>

Некоторые отдельные элементы могут присутствовать или отсутствовать. Скажем, я хочу получить элемент <Item>two</Item>, если он присутствует. Я пробовал следующие XPaths (на С#).

  • XMLNode node = myXMLdoc.SelectSingleNode("/itemSet[Item='two']") --- Если присутствует элемент два, он возвращает мне только первый элемент один. Возможно, этот запрос просто указывает на первый элемент в itemSet, если он имеет Item со значением два где-то в качестве дочернего элемента. Верна ли эта интерпретация?

Итак, я попытался:

  • XMLNode node = myXMLdoc.SelectSingleNode("/itemSet[Item='two']/Item[1]") --- Я прочитал этот запрос как, верните мне первый элемент <Item> в itemSet со значением = 'two'. Я прав?

Это по-прежнему возвращает только первый элемент one. Что я делаю неправильно? В обоих случаях, используя братьев и сестер, я могу пройти через дочерние узлы и добраться до двух, но это не то, на что я смотрю. Также, если два отсутствуют, SelectSingleNode возвращает null. Таким образом, сам факт, что я получаю успешный возвращаемый узел, действительно указывает на присутствие элемента два, поэтому, если бы я хотел, чтобы логический тест проверял наличие два, любой из приведенных выше XPath был бы достаточен, но я на самом деле мне нужен полный элемент <Item>two</Item> в качестве возвращаемого узла.

[Мой первый вопрос здесь, и я впервые работаю с веб-программированием, поэтому я только что изучил приведенные выше XPaths и связанный с ними материал xml на лету из прошлых вопросов в SO. Так что будьте нежны и дайте мне знать, если я дурак или нарушаю какие-либо правила сообщества. Спасибо.]


person Community    schedule 19.05.2009    source источник


Ответы (1)


Я думаю, вы хотите:

myXMLdoc.SelectSingleNode("/itemSet/Item[text()='two']")

Другими словами, вам нужен Элемент с текстом из двух, а не содержащий его itemSet.

Вы также можете использовать одну точку для обозначения узла контекста в вашем случае:

myXMLdoc.SelectSingleNode("/itemSet/Item[.='two']")

РЕДАКТИРОВАТЬ: Разница между . и text() заключается в том, что . фактически означает "этот узел", а text() означает "все дочерние текстовые узлы этого узла". В обоих случаях сравнение будет со «строковым значением» LHS. Для узла элемента строковое значение представляет собой «конкатенацию строковых значений всех потомков текстового узла узла элемента в порядке документа», а для набора текстовых узлов сравнение проверит, равен ли какой-либо текстовый узел тот, против которого вы тестируете.

Так что не имеет значения, когда содержимое элемента имеет только один текстовый узел, но предположим, что у нас есть:

<root>
  <item name="first">x<foo/>y</item>
  <item name="second">xy<foo/>ab</item>
</root>

Тогда выражение XPath «root/item[.='xy']» будет соответствовать первому элементу, а «root/item[text()='xy']» — второму.

person Jon Skeet    schedule 19.05.2009
comment
Огромное спасибо, Джон. Оба ваших решения работали как шарм. Раз уж по теме, могу я спросить, в чем разница между использованием text() и .? В моем примере XML это простой элемент с одним текстовым значением, поэтому оба решения возвращают одно и то же. Есть ли сложная ситуация с XML, когда один предпочтительнее другого или результаты разные? (Кроме того, что я отметил год как правильный и проголосовал за него, есть ли что-то ТАКОЕ, что я могу сделать, чтобы отблагодарить вас от сообщества?) - person ; 19.05.2009
comment
@areaMan: Честно говоря, я не уверен в разнице между text() и .. Мой XPath-fu довольно минимален :) Вы можете посмотреть спецификации XPath, чтобы узнать больше: w3.org/TR/xpath Что вы можете сделать, чтобы поблагодарить меня... найдите вопрос, на который вы можете ответить , и ответьте на него, как сможете. О, и продолжайте задавать хорошие вопросы :) - person Jon Skeet; 19.05.2009
comment
Сказав это о том, что я не знаю разницы, я знаю некоторые различия между . и text() - будет редактировать. - person Jon Skeet; 19.05.2009