Как использовать XPath с XElement или LINQ?

Рассмотрим следующий 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?


UPDATE:

После обезьяны с этим еще немного я нашел способ сделать то, что я пытаюсь сделать:

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

Мне все равно интересно узнать, есть ли у кого-то лучшее решение?

Ответ 1

Чтобы использовать XPath с LINQ to XML, добавьте объявление использования для System.Xml.XPath, это приведет к расширению методов System.Xml.XPath.Extensions в область видимости.

В вашем примере:

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

Ответ 2

Другие полностью разумно предложили использовать "родные" запросы LINQ to XML, чтобы делать то, что вы хотите.

Однако, в интересах предоставления множества альтернатив, рассмотрите XPathSelectElement, XPathSelectElements и XPathEvaluate, чтобы оценить выражения XPath в отношении XNode (все методы расширения на XNode). Вы также можете использовать CreateNavigator, чтобы создать XPathNavigator для XNode.

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

Ответ 3

См., имея дело с 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 Я надеюсь, что это поможет вам.

Ответ 4

Вы можете использовать метод .Element() для связывания элементов для формирования структуры, похожей на XPath.

В вашем примере:

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

Ответ 5

Я попытался придумать структуру LINQesq для генерации xpath. Он позволяет вам описывать xpath, используя выражения С# lambda

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