# Get a XElement at a given path

I want to traverse a xml tree until I find the first element whose position matches the path. So if I'm looking for Foo/Bar/FooBar I want to get this:

<Root>
<Foo>
<Bar>
<FooBar /> <!-- This one -->
</Bar>
</Foo>
</Root>


However there could be any number of <FooBar />'s in my way and I only want the one at this path. I wrote 2 methods to get this:

private static XElement ElementByName(XElement parent, string name)
{
return parent.Elements().Where(element => element.Name.LocalName == name).First();
}

private static XElement ElementAtPath(XElement root, string path)
{
XElement target = root;
string[] pathArr = path.Split('/');
for (int i = 0; i < pathArr.Length; i ++)
{
target = ElementByName(target, pathArr[i]);
}
return target;
}


Is there a faster / more efficient way I could achieve this?

• There is, look here - you need to use XPath ;-) – t3chb0t Sep 27 '18 at 14:59
• Using (XElement)root.XPathSelectElement(path); doesn't work for me – Peter Sep 27 '18 at 15:36
• Maybe XMLreader and then you stop at the first. – paparazzo Sep 27 '18 at 16:24
• I removed the performance tag because you hadn't provided any benchmarks and sample data and without them no one can actually tell you which approach is or would be faster. – t3chb0t Sep 28 '18 at 5:41

You could try the following which utilizes XPath's XPathSelectElement extension method.

test.xml

<Root>
<Foo>
<FooBar>1</FooBar>
<Bar>
<FooBar>2</FooBar>
</Bar>
</Foo>
</Root>


C#

using System;
using System.Xml.Linq;
using System.Xml.XPath;

...

static void Main(string[] args)
{
XElement element = ElementAtPath(document.Root, "Foo/Bar/FooBar");

Console.WriteLine(element); // Prints <FooBar>2</FooBar>
}

private static XElement ElementAtPath(XElement root, string path)
{
if (root == null)
{
throw new ArgumentNullException(nameof(root));
}

if (string.IsNullOrWhiteSpace(path))
{
throw new ArgumentException("Invalid path.");
}

return root.XPathSelectElement(path);
}


private static XElement ElementByName(XElement parent, string name)
{
// Use FirstOrDefault() or another selector to find the relevant element
return parent.Descendants(name).FirstOrDefault();
}


Usage:

XDocument document = XDocument.Load(@"<path to file>");
var result = ElementByName(document.Root, "FooBar");