gizgok
gizgok

Reputation: 7649

Get the XElement for the XML

Here's my XML File:

<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>

What I need to do is get the Template XElement from the given structure based upon the Name attribute of Template tag. The problem is there can be multiple template tags with same attribute Name. The Distinguishing factor is Application Name attribute value and section attribute value.

Currently I'm able to get the XElement by first getting Application Element based upon it's attribute, then Section based upon it's attribute and then finally template based upon it' name.

I wanted to know if there is a way to get it in one go.

Upvotes: 4

Views: 1077

Answers (4)

Steve B
Steve B

Reputation: 37660

XPath should help you. Use the Extensions.XPathSelectElement Method (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);

Upvotes: 1

Jon Skeet
Jon Skeet

Reputation: 1500515

I would use the fact that you can call Elements or an existing sequence, so:

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();

You might even want to add an extension method somewhere:

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

Then you can rewrite the query as:

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

... which I think you'll agree is quite readable :)

Note that the use of casting XAttribute to string instead of using the Value property means that any elements without the Name attribute are just effectively ignored rather than causing a NullReferenceException.

Upvotes: 6

Daniel Hilgarth
Daniel Hilgarth

Reputation: 174309

The following code should do the trick:

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");

Please note that this code throws exceptions if the XML doesn't conform to the specification. Specifically, there will be a NullReferenceException if any of the tags in question don't contain an attribute named "Name". Or if the Template tag doesn't have two levels of parents.

Upvotes: 1

Haris Hasan
Haris Hasan

Reputation: 30097

    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"));
    }

Upvotes: 1

Related Questions