C# – Search XML for elements, values, and attributes

The simplest way to search XML is to use the Linq-to-XML API in .NET (in System.Xml.Linq). This parses XML and allows you to perform Linq queries on it.

Here’s an example:

using System.Xml.Linq; using System.Linq; var xmlString = @" <Movies> <Movie>Office Space</Movie> <Movie>John Wick</Movie> <Movie>The Big Short</Movie> </Movies>"; var moviesXElement = XElement.Parse(xmlString); var movieCount = moviesXElement.Elements("Movie").Count(); Console.WriteLine($"There are {movieCount} movies");
Code language: C# (cs)

This outputs:

There are 3 movies
Code language: plaintext (plaintext)

XElement is the main class. You use it in combination with Linq methods to perform searches. In this article, I’ll how to use this to search XML by element name, values, and attributes.

Note: To use this functionality, you have to reference System.Xml.Linq and System.Linq. For brevity, I’m leaving the using statements out of the rest of the code examples.

Loading and parsing XML to make it searchable

Use XElement methods to load / parse XML into an XElement object to make it searchable.

Let’s say you have the following XML:

<Movie> <Name>Office Space</Name> <YearReleased>1999</YearReleased> </Movie>
Code language: HTML, XML (xml)

If you have this XML as a string, use XElement.Parse():

var xElement = XElement.Parse(xmlString);
Code language: C# (cs)

If you’re loading this XML from a file, use XElement.Load():

var xElement = XElement.Load("movies.xml");
Code language: C# (cs)

If you need to treat this like an XML Document, use the equivalent XDocument methods. For example:

var xDoc = XDocument.Load("movies.xml");
Code language: C# (cs)

For brevity, I’ll exclude this loading/parsing step in the rest of the examples in this article.

Search elements by name

There are two main methods for searching for elements by name:

  • XElement.Elements(name): Searches all child elements.
  • XElement.Descendants(name): Searches all descendants at all levels below the current element.

Both of these do a case-sensitive search by default.

I’ll use the following movies XML to show examples of searching by name:

<Movies> <Movie> <Name>Office Space</Name> <YearReleased>1999</YearReleased> </Movie> <Movie> <Name>John Wick</Name> <YearReleased>2014</YearReleased> </Movie> <Movie> <Name>The Big Short</Name> <YearReleased>2015</YearReleased> </Movie> </Movies>
Code language: HTML, XML (xml)

Get a list of all movie names

Here’s an example of calling Elements(name) multiple times to traverse the XML hierarchy. This fetches the movie names from the <Name> element:

var movieNames = moviesXElement.Elements("Movie").Elements("Name").Select(e => e.Value); foreach(var name in movieNames) { Console.WriteLine(name); }
Code language: C# (cs)

This outputs:

Office Space John Wick The Big Short
Code language: plaintext (plaintext)

Count the number of <Movie> elements

You can use the Linq aggregation methods, like Count(). The following returns the count of <Movie> elements:

var movieCount = moviesXElement.Elements("Movie").Count(); Console.WriteLine($"There are {movieCount} movie(s)");
Code language: C# (cs)

This outputs:

There are 3 movie(s)
Code language: plaintext (plaintext)

Get all movie <YearReleased> elements

XElement.Descendants(name) allows you to search all child elements at any depth in the hierarchy.

Here’s an example of fetching the <YearReleased> elements:

var movieYearElements = moviesXElement.Descendants("YearReleased"); foreach(var movieYearElement in movieYearElements) { Console.WriteLine(movieYearElement); }
Code language: C# (cs)

This returns the following:

<YearReleased>1999</YearReleased> <YearReleased>2014</YearReleased> <YearReleased>2015</YearReleased>
Code language: plaintext (plaintext)

Note: You can return elements or their values. When you call .ToString() on an XElement, it outputs the XML like this.

This saves you from having to traverse the XML hierarchy with multiple .Elements(name) calls. Be careful though. This returns a flattened list of all matching elements.

Case-insensitive search

The XElement methods do case-sensitive searches by default. So if you called Elements(“movie”), it wouldn’t return the <Movie> elements.

You can do a case-insensitive by using the following extension methods:

public static IEnumerable<XElement> ElementsIgnoreCase(this IEnumerable<XElement> xElementList, string name) { return xElementList.Elements().Where(e => name.Equals(e.Name.ToString(), StringComparison.OrdinalIgnoreCase)); } public static IEnumerable<XElement> ElementsIgnoreCase(this XElement xElement, string name) { return xElement.Elements().Where(e => name.Equals(e.Name.ToString(), StringComparison.OrdinalIgnoreCase)); }
Code language: C# (cs)

Here’s an example. This is using “movie” to count the number of <Movie> elements:

var movieCount = moviesXElement.ElementsIgnoreCase("movie").Count(); Console.WriteLine($"There are {movieCount} movies");
Code language: JavaScript (javascript)

This outputs:

There are 3 movies
Code language: plaintext (plaintext)

The following example shows how the extension methods simplify the call chain. It’s getting the movie <Name> elements:

var movieNameElements = moviesXElement.ElementsIgnoreCase("movie").ElementsIgnoreCase("name"); foreach (var movieNameElement in movieNameElements) { Console.WriteLine(movieNameElement); }
Code language: C# (cs)

This outputs the following:

<Name>Office Space</Name> <Name>John Wick</Name> <Name>The Big Short</Name>
Code language: plaintext (plaintext)

Get the first <Movie> element

The XElement.Element(name) returns the first element with the specified name:

var firstMovieElement = moviesXElement.Element("Movie"); Console.WriteLine(firstMovieElement);
Code language: C# (cs)

This outputs the following:

<Movie> <Name>Office Space</Name> <YearReleased>1999</YearReleased> </Movie>
Code language: plaintext (plaintext)

Search elements by value

There are no methods in XElement that allow you to search for elements based on their primitive values. Instead, you can use XElement to fetch elements and then filter them with Linq methods (like Where() or FirstOrDefault()).

To retrieve an element’s primitive value, you can cast the XElement object to the value’s primitive type. If the primitive type is a string, use XElement.Value.

I’ll use the following movies XML to show examples of searching by value.

<Movies> <Movie> <Name>Office Space</Name> <YearReleased>1999</YearReleased> </Movie> <Movie> <Name>John Wick</Name> <YearReleased>2014</YearReleased> </Movie> <Movie> <Name>The Big Short</Name> <YearReleased>2015</YearReleased> </Movie> </Movies>
Code language: HTML, XML (xml)

Get the movie called John Wick

This shows how to get an element where a child element contains a specific value. It’s looking for the <Movie> element that contains a <Name> element with John Wick as the value.

var johnWick = moviesXElement.Elements("Movie").FirstOrDefault(m => m.Element("Name").Value == "John Wick"); Console.WriteLine(johnWick);
Code language: C# (cs)

This outputs the following:

<Movie> <Name>John Wick</Name> <YearReleased>2014</YearReleased> </Movie>
Code language: plaintext (plaintext)

Get all movies released after 2000

Here’s an example of getting multiple elements based on search conditions using Where(). It’s getting all <Movie> elements that contain a <YearReleased> value greater than 2000:

var movies = moviesXElement.Elements("Movie").Where(m => (int)m.Element("YearReleased") > 2000); Console.WriteLine("Movies released after 2000:"); foreach(var movie in movies) { Console.WriteLine($"\t{movie.Element("Name").Value} was released in {(int)movie.Element("YearReleased")}"); }
Code language: C# (cs)

Note: This also shows an example of how you can cast an XElement object to its primitive value type. In this case, it’s casting to an integer.

This outputs:

Movies made after 2000: John Wick was made in 2014 The Big Short was made in 2015
Code language: plaintext (plaintext)

Search elements by attribute

XElement doesn’t have any methods that allow you to directly search for elements with a specific attribute value. Instead, you can use XElement to fetch elements and filter them with Linq methods by looking at the attribute value.

First, you can fetch an element’s attribute by using XElement.Attribute(name). Then you can look at its value by using the .Value property.

I’ll use the following movies XML to show examples of how to search by attribute.

<Movies> <Movie id="123"> <Name>Office Space</Name> <YearReleased>1999</YearReleased> </Movie> <Movie id="456"> <Name>John Wick</Name> <YearReleased>2014</YearReleased> </Movie> <Movie id="789"> <Name>The Big Short</Name> <YearReleased>2015</YearReleased> </Movie> </Movies>
Code language: HTML, XML (xml)

Get the movie with id 123

This shows how to get an element with a specific attribute value. It’s searching for <Movie id=”123″>.

var movie = moviesXElement.Elements("Movie").FirstOrDefault(movie => movie.Attribute("id").Value == "123"); Console.WriteLine(movie);
Code language: C# (cs)

This outputs:

<Movie id="123"> <Name>Office Space</Name> <YearReleased>1999</YearReleased> </Movie>
Code language: HTML, XML (xml)

Get a list of all movie ID’s

You can call XElement.Attributes(name) to get a list of XAttribute objects for all of the selected elements. This is getting a list of the <Movie> element id attributes.

var movieIdAttributes = moviesXElement.Elements("Movie").Attributes("id"); foreach (var idAttribute in movieIdAttributes) { Console.WriteLine(idAttribute.Value); }
Code language: C# (cs)

This outputs:

123 456 789
Code language: plaintext (plaintext)

Leave a Comment