Предотвращение доступа к дублирующему элементу при чтении XML с использованием LINQ - PullRequest
2 голосов
/ 21 августа 2011

Я получил XML, который я пытаюсь проанализировать с помощью LINQ to XML и преобразовать в анонимный список объектов.Для этого я придумываю следующий фрагмент кода:

var res = doc
            .Root
            .Elements("Record")
            .Elements("Term")
            .Select(term => new
            {
                LanguageCode = term.Attribute("languageCode").Value,
                ConceptNumber = Convert.ToInt32(term.Attribute("conceptNumber").Value),
                IsHidden = Convert.ToBoolean(term.Attribute("hidden").Value),
                Label = term.Value,

                InputDate = DateTime.Parse(term.Parent.Element("InputDate").Value),
                LastUpdate = DateTime.Parse(term.Parent.Element("LastUpdated").Value)
            }).ToList();

Обратите внимание на раздел InputDate & LastUpdate.Как вы видите, мне нужно получить доступ к родительскому узлу (скажем, term.Parent), чтобы я мог получить доступ к этим 2 элементам, и это выглядит мне беспорядочно.Есть ли способ объявить term.Parent один раз и использовать его снова и снова для извлечения этих свойств?

Вот выдержка из XML, которую я пытаюсь прочитать:

<Record>
  <Term  languageCode="Prs" conceptNumber="10" hidden="False">Whatever</Term>
  <Status>Approved</Status>
  <Frequency>0</Frequency>
  <InputDate>12/30/1899</InputDate>
  <LastUpdate>10/25/2009</LastUpdate>
</Record>

Спасибо

Ответы [ 2 ]

6 голосов
/ 21 августа 2011

Вам необходимо использовать let предложение .Он создает новую переменную внутри запроса и позволяет использовать ее несколько раз.

В вашем случае это будет

var res = (from term in doc.Root.Elements("Record").Elements("Term")
           let parent = term.Parent
           select new
           {
               LanguageCode = term.Attribute("languageCode").Value,
               ConceptNumber = Convert.ToInt32(term.Attribute("conceptNumber").Value),
               IsHidden = Convert.ToBoolean(term.Attribute("hidden").Value),
               Label = term.Value,
               InputDate = parent.Element("InputDate").Value,
               LastUpdate = parent.Element("LastUpdated").Value
           }).ToList();

Обратите внимание, что это код с чистым синтаксисом LINQ, который позволяетвыражать идеи намного яснее, чем использовать методы расширения, как в вашем вопросе.

1 голос
/ 21 августа 2011

Вы можете ввести анонимный класс в проекцию (это похоже на то, что let делает под капотом), а затем использовать SelectMany(), чтобы сгладить, используя дополнительные свойства:

var results = doc.Elements("Record")
                 .Select( x => new 
                  {
                    Terms = x.Elements("Term"),
                    InputDate = DateTime.Parse(x.Element("InputDate").Value),
                    LastUpdate = DateTime.Parse(x.Element("LastUpdate").Value)
                  }) 
                 .SelectMany(x => x.Terms, (record,term) => new
                 {
                    LanguageCode = term.Attribute("languageCode").Value,
                    ..
                    InputDate = record.InputDate,
                    LastUpdate = record.LastUpdate
                 });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...