How to properly search xml document using LINQ C#

You can use XElement and search using a LINQ query like these:

XElement doc = XElement.Parse(xml);
var result = doc.Elements("Customers")
                .Elements("Client")
                .Where(x => x.Elements("Firstname")
                             .Where(c => c.Attribute("Value").Value == "someguy")
                             .Any())
                .ToList();

So with input:

var xml =
@"<?xml version=""1.0"" encoding=""utf-8""?>
<body>
    <Customers>
    <Client>
        <Firstname Value=""someguy"" />
        <LastName Value=""some last name"" />
        <PhoneNumber Value=""123456"" />
        <Address Value=""some where"" />
        <City Value=""some town"" />
        <State Value=""some state"" />
    </Client>
    <Client>
        <Firstname Value=""someotherguy"" />
        <LastName Value=""some other last name"" />
        <PhoneNumber Value=""123456"" />
        <Address Value=""some other where"" />
        <City Value=""some other town"" />
        <State Value=""some other state"" />
    </Client>
    </Customers>
</body>";

XElement doc = XElement.Parse(xml);
var result = doc.Elements("Customers")
                .Elements("Client")
                .Where(x => x.Elements("Firstname")
                             .Where(c => c.Attribute("Value").Value == "someguy")
                             .Any())
                .ToList();

The result will be:

<Client>
    <Firstname Value=""someguy"" />
    <LastName Value=""some last name"" />
    <PhoneNumber Value=""123456"" />
    <Address Value=""some where"" />
    <City Value=""some town"" />
    <State Value=""some state"" />
</Client>

And you can show values for example:

MessageBox.Show(string.Format("Firstname: {0}\nLastName: {1}\nPhoneNumber: {2}\nAddress: {3}\nCity: {4}\nState: {5}",
                result[0].Element("Firstname").Attribute("Value").Value,
                result[0].Element("LastName").Attribute("Value").Value,
                result[0].Element("PhoneNumber").Attribute("Value").Value,
                result[0].Element("Address").Attribute("Value").Value,
                result[0].Element("City").Attribute("Value").Value,
                result[0].Element("State").Attribute("Value").Value));

Note:

  • If you know the result should contain 0 or 1 elements, you can use FirstOrDefault() instead of ToList();
  • Element names are case sensitive so pay attention to Firstname for example.
  • You can use XElement.Load() to load from file for example XElement doc = XElement.Load(@"d:\file.xml");
  • The query will be more fault tolerant if you select elements this way .Where(c => c.Name.ToString().ToLower() == "Customers".ToLower())
  • The query will be more fault-tolerant if you select attributes this way .Where(c => c.Attributes("Value").Where(a=>a.Value == "someguy").Any())

As an alternative to @Reza Aghaei's solution, XPath is also a solution

var xml =
@"<?xml version=""1.0"" encoding=""utf-8""?>
<body>
    <Customers>
    <Client>
        <Firstname Value=""someguy"" />
        <LastName Value=""some last name"" />
        <PhoneNumber Value=""123456"" />
        <Address Value=""some where"" />
        <City Value=""some town"" />
        <State Value=""some state"" />
    </Client>
    <Client>
        <Firstname Value=""someotherguy"" />
        <LastName Value=""some other last name"" />
        <PhoneNumber Value=""123456"" />
        <Address Value=""some other where"" />
        <City Value=""some other town"" />
        <State Value=""some other state"" />
    </Client>
    <Client>
        <Firstname Value=""someguy"" />
        <LastName Value=""some other last name"" />
        <PhoneNumber Value=""12345634543"" />
        <Address Value=""some other where"" />
        <City Value=""some other town"" />
        <State Value=""some other state"" />
    </Client>
    </Customers>
</body>";
XElement doc = XElement.Parse(xml);

foreach(var client in doc
 .XPathSelectElements("./Customers/Client/Firstname[@Value='someguy']")
 .Select(x => x.Parent))
    Console.WriteLine (client);

If you prefer a Linq To Xml solution :

var results = (from c in doc.Descendants("Client")
            from f in c.Descendants("Firstname")
             where (string)f.Attribute("Value") == "someguy"
             select c).ToList();
foreach(var r in results)
    Console.WriteLine (r);

How to: Write Linq to Xml Queries with Complex Filtering

Tags:

C#

Linq

Xml