Как использовать 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?


ОБНОВИТЬ:

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

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

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


person Paul Fryer    schedule 04.09.2010    source источник
comment
Не используйте FirstOfDefault () в этом случае, потому что, если хеш не найден, вы получите исключение NullReferenceException. Вместо этого используйте First (), вы получите более наглядное исключение.   -  person kaalus    schedule 03.03.2012
comment
Используйте First (), если вы ожидаете, что хеш существует всегда. В противном случае с FirstOrDefault () все в порядке, если вы проверяете значение null перед доступом к свойству Value.   -  person an phu    schedule 17.03.2016


Ответы (5)


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

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

var value = (string)xml.XPathEvaluate("/response/data/hash");
person Richard    schedule 04.09.2010
comment
ОК, похоже, ближе всего к исходному вопросу - person Henk Holterman; 04.09.2010
comment
Собственно, это (сейчас?) В System.Xml.XPath. - person Dan Friedman; 08.05.2015
comment
@DanFriedman, он не сдвинулся с места. Ссылка на заметку - на документы класса, чуть раньше я даю пространство имен (без ссылки). - person Richard; 08.05.2015
comment
Также обратите внимание, что вам необходимо добавить сборку через NuGet для приложений UWP: ссылка < / а> - person Matt__C; 17.09.2016
comment
Мне проще использовать метод XPathSelectElement и получить обратно XElement вместо объекта. - person user3042674; 11.10.2018

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

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

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

person Jon Skeet    schedule 04.09.2010

Посмотрите, почему при работе с 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 Я надеюсь, что это поможет вам.

person abhishek    schedule 04.09.2010
comment
@adhishek +1 за объяснение значения разделения элемента на его собственную переменную, чтобы вы могли делать другие вещи, например, получать атрибуты и т. д. - person Paul Fryer; 04.09.2010
comment
Одна из причин использования XPath заключается в том, что вы теряете все то, что XPath может делать, а Linq - нет. Первое, что приходит на ум, - это выполнить запрос, который определяется во время выполнения (скажем, выражение, прочитанное из конфигурации или что-то еще). - person Marco Mp; 23.05.2013

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

Для вашего примера:

XElement xml = XElement.Parse(@"...your xml...");
XElement hash = xml.Element("data").Element("hash");
person panpawel    schedule 23.10.2013
comment
Я думаю, что это лучший ответ, потому что он выполняет свою работу, продолжая использовать LINQ to XML (что рекомендуется) вместо использования XPath с запросом LINQ to XML (что не рекомендуется). - person Girish Jain; 01.10.2015
comment
Использование XPath более лаконично, особенно если вы ищете каких-либо внуков или не только. - person an phu; 17.03.2016
comment
Element () может возвращать значение null, поэтому это небезопасно. - person Simon Morgan; 24.11.2018

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

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

person TGH    schedule 02.02.2014