як використовувати 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.