Linq to XML выбор базы узлов по значению атрибута

у меня есть xml-файл, который возвращает набор элементов, уникальных по значению атрибута. Это представляет проблему, так как я не могу выбрать узел по его имени:

<doc>
    <float name="score">1.2873721</float>
    <arr name="2_category">
        <long>3021</long>
    </arr>
    <arr name="ATR_FamilyName">
        <str>Some Cookbook </str>
    </arr>
    <arr name="ATR_IsFamily">
        <str>0</str>
    </arr>
    <arr name="ATR_SellPrice">
        <str>49.95</str>
    </arr>
    <arr name="ATR_VendorId">
        <str>ABC</str>
    </arr>
    <arr name="ATR_VendorName">
        <str>WROX</str>
    </arr>      
</doc> 

Я использую linq для заполнения класса "Продукт". Я могу выбрать элементы по положению, однако это становится проблемой, если узел не существует. Есть ли способ выбрать узел на основе значения его атрибута? В приведенном ниже примере я могу получить узел arr, если атрибут @name = "ATR_FamilyName"? В xpath это было бы:

doc/arr[@name = 'ATR_FamilyName']/str

вот мой запрос linq to xml:

var query = from rt in results
   where (String)rt.Descendants().ElementAt(5).Element("str").Value == "0"
   select new Product.Product
             {
                FamilyName = (String)rt.Descendants().ElementAt(3).Value
                // doc/arr[@name = 'ATR_FamilyName']/str - select Family Name is arr/@name 'ATR_FamilyName'                              
                MorePropertiestoset....                              
              };   

3 ответов


как ответ AS-CII, но без использования выражения запроса (за исключением внешнего) и с приведением для XAttribute и str значение элемента внутри анонимного типа:

select new Product.Product
{
    FamilyName = rt.Descendants("arr")
                   .Where(x => (string) x.Attribute("name") == "ATR_FamilyName")
                   .Select(x => (string) x.Element("str"))
                   .FirstOrDefault(),
    MorePropertiesToSet....                              
}; 

обратите внимание, что использование приведения для результата вызова Attribute("name") означает, что если есть какие-то элементы, которые не имейте атрибут, приведение приведет к нулевой ссылке (которая не равна строковому литералу). Если вы используете Value собственность, вы получите исключение. Иногда исключение может быть лучше-если это указывает на то, что данные принципиально нарушены, и вы хотите узнать об этом, а не просто не соответствовать значению.

(то же самое верно для актеров XElement to string.)


С помощью LINQ вы можете легко выбрать только узлы, которые имеют указанный атрибут, например:

var query = from node in results.Descendants("arr") // I believe you could use results.Elements("arr") here
            where node.Attribute("name").Value == "ATR_FamilyName"
            select new Product
            {
                FamilyName = node.Element("str").Value
            };

использовать XElement такой:

from rt in results.descendants("<node name>")
where rt.attribute(attribute name).value == "specified value"
select rt

извините за ввод с мобильного телефона