як використовувати XPath з XDocument?


109

Існує аналогічне запитання, але, схоже, рішення не вийшло у моєму випадку: Дивацтво з XDocument, XPath та просторами імен

Ось XML, з яким я працюю:

<?xml version="1.0" encoding="utf-8"?>
<Report Id="ID1" Type="Demo Report" Created="2011-01-01T01:01:01+11:00" Culture="en" xmlns="http://demo.com/2011/demo-schema">
    <ReportInfo>
        <Name>Demo Report</Name>
        <CreatedBy>Unit Test</CreatedBy>
    </ReportInfo>
</Report>

А нижче - код, який я вважав, що він повинен працювати, але він не став ...

XDocument xdoc = XDocument.Load(@"C:\SampleXML.xml");
XmlNamespaceManager xnm = new XmlNamespaceManager(new NameTable()); 
xnm.AddNamespace(String.Empty, "http://demo.com/2011/demo-schema");
Console.WriteLine(xdoc.XPathSelectElement("/Report/ReportInfo/Name", xnm) == null);

Хтось має ідеї? Дякую.


1
Дивіться іншу відповідь нижче, вона не працює, оскільки реалізація XPath 1.0 не може впоратися з порожнім префіксом
— Пол Хетчер

1
Як було сказано тут, не використовуйте порожній префікс, додаючи простір імен до [XmlNamespaceManager]. Я просто додаю цей коментар у випадку, якщо хтось хоче побачити невеликий приклад коду з документом, який має кілька атрибутів [xmlns], із суфіксом та без нього. Дивіться тут: stackoverflow.com/a/38272604/5838538
— Jelgab

Відповіді:


158

Якщо у вас є XDocument, простіше використовувати LINQ-to-XML:

var document = XDocument.Load(fileName);
var name = document.Descendants(XName.Get("Name", @"http://demo.com/2011/demo-schema")).First().Value;

Якщо ви впевнені, що XPath є єдиним необхідним рішенням:

using System.Xml.XPath;

var document = XDocument.Load(fileName);
var namespaceManager = new XmlNamespaceManager(new NameTable());
namespaceManager.AddNamespace("empty", "http://demo.com/2011/demo-schema");
var name = document.XPathSelectElement("/empty:Report/empty:ReportInfo/empty:Name", namespaceManager).Value;

13
Я б сказав, що важко сказати, що linq у більшості випадків простіше, ніж xpath. Наприклад, у цьому випадку еквівалент LINQ насправді не є еквівалентним, оскільки він також отримає вузли "Ім'я" під іншими вузлами (яких зараз немає, але вони можуть бути додані пізнішими змінами до формату файлу). Однак ваше рішення, безумовно, правильне.
— Марко Мп

12
ПРИМІТКА: використовуючи System.Xml.XPath; є досить важливим, оскільки XPathSelectElement - це метод розширення. Не роби так, як я, і ігноруй цю частину;)
— Марк ван Стратен

7
XPath все ще корисний тим, що дозволяє контекстуалізувати стосунки батьків з дитиною. Наприклад, якщо ви хотіли дістатися до / Banana / Banana / Banana замість того, щоб отримувати кожного банана
— Себастьян Паттен

2
"порожній" тут трохи оманливий і заплутаний. Ви можете використовувати що завгодно, крім XPath, String.Empty (як виявив запитувач). "демо" було б більше відповідати прикладу.
— Том Блоджет

7

XPath 1.0, який реалізує MS, не має ідеї простору імен за замовчуванням. Тому спробуйте це:

XDocument xdoc = XDocument.Load(@"C:\SampleXML.xml");
XmlNamespaceManager xnm = new XmlNamespaceManager(new NameTable()); 
xnm.AddNamespace("x", "http://demo.com/2011/demo-schema");
Console.WriteLine(xdoc.XPathSelectElement("/x:Report/x:ReportInfo/x:Name", xnm) == null);

8
З вашої відповіді випливає, що XPath 2.0 на відміну від XPath 1.0 "* має" уявлення "про область імен за замовчуванням. Я не знаю такої нової функції XPath (ми говоримо тут XPath, а не XSLT чи XQuery). Тому ви могли б , будь ласка, прямо у своїй відповіді зазначте, що ви маєте на увазі?
— Димитрей Новатчев

2
Я думаю, що він отримує тут, що якщо у вас є документ, який визначає простір імен, ваш xpath повинен містити кваліфіковані елементи, тобто ви не можете робити xnm.AddNamespace (string.Empty, " demo.com/2011/demo-schema" ); а потім xdoc.XPathSelectElement ("/ Report / ReportInfo / Name", xnm) - результат завжди залишається нульовим
— Пол Хетчер

3

ви можете використовувати приклад від Microsoft - для вас без простору імен:

using System.Xml.Linq;
using System.Xml.XPath;
var e = xdoc.XPathSelectElement("./Report/ReportInfo/Name");     

повинен це зробити


не працює для мене
— користувач1623521
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.