Использование 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();
}