2012-02-07 2 views
13

У меня есть документ XML, который содержит ряд элементов узлов, которые выглядят следующим образом:Лучший способ запроса XDocument с LINQ?

<data> 
    <item> 
     <label>XYZ</label> 
     <description>lorem ipsum</description> 
     <parameter type="id">123</parameter> 
     <parameter type="name">Adam Savage</parameter> 
     <parameter type="zip">90210</parameter> 
    </item> 
</data> 

, и я хочу Linq его в анонимный тип, как это:

var mydata = 
    (from root in document.Root.Elements("item") 
    select new { 
     label = (string)root.Element("label"), 
     description = (string)root.Element("description"), 
     id = ..., 
     name = ..., 
     zip = ... 
    }); 

Что лучший способ вытащить каждый тип параметра в соответствии со значением его атрибута типа? Поскольку есть много элементов параметров, вы заканчиваете с root.Elements("parameter"), который является коллекцией. Лучший способ, которым я могу это сделать, - это сделать это ниже, но я чувствую, что должен быть лучший способ?

(from c in root.Descendants("parameter") where (string)c.Attribute("type") == "id" 
select c.Value).SingleOrDefault() 

ответ

25

Я хотел бы использовать встроенные методы запроса в LINQ к XML вместо XPath. Ваш запрос выглядит хорошо для меня, кроме этого:

  • Если есть несколько предметов, вам нужно будет найти потомков этого; или просто использовать Element, если вы ищете для прямых потомков элемента
  • Вы можете тянуть все значения сразу и превратить их в словарь
  • Если вы используете различные типы данных для содержимого , вы можете использовать этот элемент вместо .Value
  • Возможно, вы захотите создать метод для возврата соответствующего XElement для заданного типа вместо нескольких запросов.

Лично я не думаю, что даже использовал выражение запроса для этого. Например:

static XElement FindParameter(XElement element, string type) 
{ 
    return element.Elements("parameter") 
        .SingleOrDefault(p => (string) p.Attribute("type") == type); 
} 

Тогда:

var mydata = from item in document.Root.Elements("item") 
      select new { 
       Label = (string) item.Element("label"), 
       Description = (string) item.Element("description"), 
       Id = (int) FindParameter(item, "id"), 
       Name = (string) FindParameter(item, "name"), 
       Zip = (string) FindParameter(item, "zip") 
      }; 

Я подозреваю, вы обнаружите, что это аккуратнее, чем какой-либо альтернативы с помощью XPath, предполагая, что я понял, что вы пытаетесь сделать.

+0

Да, это похоже на хороший подход. Джон ... Другая проблема, с которой мне приходится сталкиваться, заключается в том, что иногда значения представляют собой пустые строки, поэтому у них есть вспомогательный метод для обработки как запроса атрибута, так и грамотно обрабатывающего приведение к правильному типу в событие пустых строк может иметь наибольший смысл, спасибо – snappymcsnap

7

использование XPATH - это очень быстро (за исключением xmlreader - но много из ИФ)

using (var stream = new StringReader(xml)) 
    { 
    XDocument xmlFile = XDocument.Load(stream); 

    var query = (IEnumerable)xmlFile.XPathEvaluate("/data/item/parameter[@type='id']"); 

    foreach (var x in query.Cast<XElement>()) 
    { 
     Console.WriteLine( x.Value); 
    } 

    } 
+7

так xpath быстрее, чем использовать встроенные методы LINQ? – snappymcsnap

+1

Несчастливый вопрос, на который никогда не отвечали! –

Смежные вопросы