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

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

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

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

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

Итак, я попробовал:

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

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

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

Ответы

Ответ 1

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

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

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

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

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

EDIT: разница между . и text() заключается в том, что . означает "этот node", а text() означает "все текстовые node дочерние элементы этого node". В обоих случаях сравнение будет проводиться против "строковой стоимости" LHS. Для элемента node строковое значение представляет собой "конкатенацию строковых значений всех текстовых node потомков элемента node в порядке документа" и для набора текстовых узлов сравнение проверит, любой текст node равен тому, который вы тестируете.

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

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

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