Reputation: 7649
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
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
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
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
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