Использование XPath для анализа XML-документа

Допустим, у меня есть следующий xml (быстрый пример)

<rows>
   <row>
      <name>one</name>
   </row>
   <row>
      <name>two</name>
   </row>
</rows>

Я пытаюсь разобрать это с помощью XmlDocument и XPath (в конечном итоге, я могу составить список строк).

Например...

XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);

foreach(XmlNode row in doc.SelectNodes("//row"))
{
   string rowName = row.SelectSingleNode("//name").InnerText;
}

Почему в моем цикле foreach значение rowName всегда "одно"? Я ожидаю, что это будет "один" на первой итерации, а "второй" - на второй.

Кажется, что//имя получает первый экземпляр в документе, а не первый экземпляр в строке, как я ожидал. В конце концов, я вызываю метод на узле "строка". Если это "то, как это работает", тогда кто-нибудь может объяснить, как я могу изменить его, чтобы работать на мои нужды?

спасибо

Ответ 1

XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);

foreach(XmlNode row in doc.SelectNodes("//row"))
{
   var rowName = row.SelectSingleNode("name");
}

Правильно ли введенный вами код? Я получаю ошибку компиляции в строке.SelectNode(), поскольку она не является членом XmlNode.

Во всяком случае, мой пример выше работает, но предполагает только один узел <name> узле <row> поэтому вам может потребоваться использовать SelectNodes() вместо SelectSingleNode() если это не так.

Как показали другие, используйте .InnerText чтобы получить только значение.

Ответ 2

Используйте LINQ to XML. Включить using System.Xml.Linq; в вашем файле кода, а затем выполните следующий код, чтобы получить список

XDocument xDoc = XDocument.Load(filepath);
IEnumerable<XElement> xNames;

xNames = xDoc.Descendants("name");

Это даст вам список элементов названия. Затем, если вы хотите превратить это в List<string> просто выполните это:

List<string> list = new List<string>();
foreach (XElement element in xNames)
{
    list.Add(element.value);
}

Ответ 3

Второй xpath начинается с //. Это аббревиатура для /descendant-or-self::node(), которую вы можете видеть, начинается с /, что означает, что он ищет из корня документа, независимо от контекста, в котором вы его используете.

Вероятно, вы хотите:

var rowName = row.SelectSingleNode("name");

найти узлы name которые являются непосредственными дочерними элементами row, или

var rowName = row.SelectSingleNode(".//name");

найти name узла * в любом месте под the строке . Note the . Note the. в этом втором xpath, который заставляет xpath начинаться с контекстного узла.

Ответ 4

Используйте относительный путь, например string rowName = row.SelectSingleNode("name").InnerText; ,

Ответ 5

Проблема заключается в следующем запросе XPath:

//row

Это имеет глобальный масштаб, поэтому независимо от того, где вы его вызываете, он будет выбирать все элементы row.

Он должен работать, если вы замените выражение следующим образом:

.//row

Ответ 6

Я бы использовал SelectSingleNode, а затем свойство InnerText.

var rowName = row.SelectSingleNode("name").InnerText;

Ответ 7

Используйте следующее

        doc.LoadXml(xml);

            foreach(XmlNode row in doc.SelectNodes("/rows/row"))
            {
                string rowName = row.SelectSingleNode("//name").InnerText.ToString();
            }