Як використовувати XPath з XElement або LINQ?


77

Розглянемо такий XML:

<response>
  <status_code>200</status_code>
  <status_txt>OK</status_txt>
  <data>
    <url>http://bit.ly/b47LVi</url>
    <hash>b47LVi</hash>
    <global_hash>9EJa3m</global_hash>
    <long_url>http://www.tumblr.com/docs/en/api#api_write</long_url>
    <new_hash>0</new_hash>
  </data>
</response>

Я шукаю дійсно короткий спосіб отримати лише значення <hash>елемента. Я намагався:

var hash = xml.Element("hash").Value;

Але це не працює. Чи можна надати запит XPath до XElement? Я можу це зробити зі старішим System.Xmlфреймворком, роблячи щось на зразок:

xml.Node("/response/data/hash").Value

Чи є щось подібне у просторі імен LINQ?


ОНОВЛЕННЯ:

Після мавпування з цим ще трохи, я знайшов спосіб зробити те, що я намагаюся зробити:

var hash = xml.Descendants("hash").FirstOrDefault().Value;

Мені все одно буде цікаво побачити, чи хтось має краще рішення?


3
Не використовуйте FirstOfDefault () у цьому випадку, тому що якщо "хеш" не знайдено, ви отримаєте NullReferenceException. Замість цього використовуйте First (), ви отримаєте більш описовий виняток.
kaalus 03.03.12

3
Використовуйте First (), якщо ви очікуєте, що "хеш" існує завжди. В іншому випадку FirstOrDefault () добре, якщо ви перевіряєте наявність нуля перед тим, як отримати доступ до властивості Value.
пху

Відповіді:


137

Щоб використовувати XPath з LINQ до XML, додайте декларацію using System.Xml.XPath, це призведе до розширення методів розширення System.Xml.XPath.Extensions.

У вашому прикладі:

var value = (string)xml.XPathEvaluate("/response/data/hash");

1
Добре, здається, найближче до вихідного питання
Хенк Холтерман,

3
На насправді, це (зараз?) В System.Xml.XPath.
Ден Фрідман,

@DanFriedman це не зрушило з місця. Примітка посилання на документи класу, трохи раніше я даю простір імен (без посилання).
Річард

Також зверніть увагу, що вам потрібно додати збірку за допомогою NuGet для програм UWP: посилання
Matt__C

1
Мені простіше використовувати метод XPathSelectElement і повернути XElement замість об’єкта.
user3042674

38

Інші цілком обґрунтовано пропонують, як використовувати "рідну" LINQ для запитів XML, щоб робити те, що ви хочете.

Тим НЕ менше, в інтересах забезпечення безліч альтернатив, розглянути XPathSelectElement, XPathSelectElementsі XPathEvaluateоцінювати XPath виразів проти XNode(вони всі методи розширення на XNode). Ви також можете використовувати CreateNavigatorдля створення XPathNavigatorфайлу XNode.

Особисто я великий шанувальник безпосереднього використання API LINQ to XML, оскільки я великий шанувальник LINQ, але якщо вам зручніше користуватися XPath, вищесказане може вам допомогти.


14

Подивіться, коли ви маєте справу з LINQ to XML, чому ви не використовуєте LINQ для отримання фактичного об’єкта.

Нащадки знаходять кожен елемент із цілого XML і перелічують усі об'єкти, що відповідають вказаному імені. Отже, у вашому випадку хеш - це ім’я, яке він знаходить.

Отже, а не робити

var hash = xml.Descendants("hash").FirstOrDefault().Value;

Я б розпався, як:

var elements = xml.Descendants("hash");
var hash = elements.FirstOrDefault();

if(hash != null)
 hash.Value // as hash can be null when default. 

Таким чином ви також можете отримати атрибути, елементи вузлів тощо.

Перегляньте цю статтю, щоб отримати чітке уявлення про неї, щоб вона допомогла. http://www.codeproject.com/KB/linq/LINQtoXML.aspx Сподіваюсь, це вам допоможе.


2
@adhishek +1 для пояснення значення відокремлення елемента від його власної змінної, щоб ви могли робити інші речі, такі як отримання атрибутів тощо.
Пол Фрайер,

1
Однією з причин використання XPath є те, що ви втрачаєте все те, що може робити XPath, а Linq - ні. Перший очевидний, що спадає на думку, - це виконати запит, який визначається під час виконання (скажімо, вираз, прочитаний із конфігурації або чогось іншого).
Marco Mp

8

Ви можете використовувати метод .Element () для зв’язування елементів, щоб сформувати структуру, подібну до XPath.

Для вашого прикладу:

XElement xml = XElement.Parse(@"...your xml...");
XElement hash = xml.Element("data").Element("hash");

1
Я думаю, що це найкраща відповідь, оскільки вона виконує роботу, продовжуючи використовувати LINQ to XML (що рекомендується) замість використання XPath із запитом LINQ to XML (що не рекомендується).
Girish Jain

2
Використання XPath є більш стислим, особливо якщо ви шукаєте когось із онуків чи не тільки.
пху

Element () може повернути null, тому це небезпечно.
Саймон Морган,

2

Я спробував придумати структуру LINQesq для генерації xpath. Це дозволяє описати xpath за допомогою лямбда-виразів c #

var xpath = CreateXpath.Where(e => e.TargetElementName == "td" && e.Parent.Name == "tr");

var xpath = CreateXpath.Where(e => e.TargetElementName == "td").Select(e => e.Text);

Не впевнений, чи корисно це в цьому контексті, але документацію ви можете знайти тут:

http://www.syntaxsuccess.com/viewarticle/how-to-create-xpath-using-linq

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