Получить XElement для XML - PullRequest
       20

Получить XElement для XML

4 голосов
/ 01 февраля 2012

Вот мой XML-файл:

<Applications>
   <Application Name="Abc">
     <Section Name="xyz">
        <Template Name="hello">
         ...
         ....
         </Template>
      </Section>
   </Application>
   <Application Name="Abc1">
     <Section Name="xyz1">
        <Template Name="hello">
         ...
         ....
         </Template>
      </Section>
   </Application>

Что мне нужно сделать, так это получить шаблон XElement из заданной структуры на основе атрибута Name тега Template. Проблема в том, что может быть несколько тегов шаблона с одним и тем же атрибутом Name. Отличительным фактором является значение атрибута «Имя приложения» и значение атрибута раздела.

В настоящее время я могу получить XElement, сначала получив Элемент приложения на основе его атрибута, затем Раздел на основе его атрибута и, наконец, шаблон на основе его имени.

Я хотел знать, есть ли способ получить его за один раз.

Ответы [ 4 ]

6 голосов
/ 01 февраля 2012

Я бы использовал тот факт, что вы можете вызвать Elements или существующую последовательность, поэтому:

var template = doc.Descendants("Application")
                  .Where(x => (string) x.Attribute("Name") == applicationName)
                  .Elements("Section")
                  .Where(x => (string) x.Attribute("Name") == sectionName)
                  .Elements("Template")
                  .Where(x => (string) x.Attribute("Name") == templateName)
                  .FirstOrDefault();

Возможно, вы даже захотите добавить метод расширения где-нибудь:

public static IEnumerable<XElement> WithName(this IEnumerable<XElement> elements,
                                             string name)
{
    this elements.Where(x => (string) x.Attribute("Name") == name);
}

Затем вы можете переписать запрос как:

var template = doc.Descendants("Application").WithName(applicationName)
                  .Elements("Section").WithName(sectionName)
                  .Elements("Template").WithName(templateName)
                  .FirstOrDefault();

... что, я думаю, вы согласитесь, вполне читабельно:)

Обратите внимание, что использование приведения XAttribute к string вместо использования свойства Value означает, что любые элементы без атрибута Name просто эффективно игнорируются, а не вызывают NullReferenceException.

1 голос
/ 01 февраля 2012

XPath должен помочь вам.Используйте метод Extensions.XPathSelectElement (XNode, String) :

XDocument xdoc = XDocument.Load("yourfile.xml");
string xPathQuery = string.Format(
    "/Applications/Application[@Name='{0}']/Section[@Name='{1}']/Template[@Name='{2}']",
    "MyApplication",
    "MySection",
    "MyTemplate"
);

XElement template = xdoc.Root.XPathSelectElement(xPathQuery);
1 голос
/ 01 февраля 2012

Следующий код должен помочь:

var template = doc.Descendants("Template")
                  .Where(x => x.Attribute("Name").Value == "hello"
                           && x.Parent.Attribute("Name").Value == "xyz1"
                           && x.Parent.Parent.Attribute("Name").Value == "Abc1");

Обратите внимание, что этот код генерирует исключения, если XML не соответствует спецификации. В частности, будет NullReferenceException, если какой-либо из рассматриваемых тегов не содержит атрибут с именем «Имя». Или, если у тега Template нет двух уровней родителей.

1 голос
/ 01 февраля 2012
    XDocument doc = XDocument.Load("Path of xml");
    var selection =
        doc.Descendants("Section").Select(item => item).Where(
            item => item.Attribute("Name").Value.ToString().Equals("Section Name Value")).ToList();

    if(null != selection)
    {
        var template =
            selection.Descendants("Template").Select(item => item).Where(
            item => item.Attribute("Name").Value.ToString().Equals("Template name value"));
    }
...