0

I have an XDocument called doc which consists of:

<bar>
  <foo>
    <item address="123">CCC</item>
  </foo>
  <definitions>
    <item address="123">AAA</item>
    <item address="456">BBB</item>
  </definitions>
</bar>

I'd like a simple linq query (preferably with lambda expression) that given 123 the expression will return AAA

I suspect I want to use doc.Descendants("definitions"), but I'm not sure how to implement the lambda clause. Actually, it would be nice to see both lambda and a where clause just to compare the two.

keenthinker
  • 7,645
  • 2
  • 35
  • 45
WhiskerBiscuit
  • 4,795
  • 8
  • 62
  • 100

2 Answers2

2
IEnumerable<string> childList =
    from el in doc.Element("bar").Element("definitions").Elements()
    where el.Attribute("address").Value == "123"
    select el.Value;

If you need to extract values from within elements of different names, I suggest you to use XMLReader rather than XDocument. Performance wise XMLReader is better as it doesn't parse the complete document unlike XDocument.

List<string> values = new List<string>();
using (StringReader sr = new StringReader(stringXML))
using (XmlReader xr = XmlReader.Create(sr))
{
    while (xr.Read())
    {
        if (xr.NodeType == XmlNodeType.Element && xr.Name == "item" && xr.GetAttribute("address") == "123" )
        {
            values.Add(xr.GetAttribute("address"));     
        }
    }
}
Rohit Minni
  • 250
  • 1
  • 3
  • 8
1

You need to use also the XElement.Attribute property. I would create an extension method that looks like this:

public static class ProjectExtensions
{
    public static String GetValue(this XDocument source, String name, String value)
    {
        //          return source
        //                      .Root
        //                      .Element(name)
        //                      .Elements("item")
        //                      .Where (f => f.Attribute("address").Value == value)
        //                      .FirstOrDefault()
        //                      .Value;
        // or alternative
        var result = (from e in source.Root.Element(name).Elements("item")
                    where e.Attribute("address").Value == value
                    select e.Value).FirstOrDefault();
        return result;
    }
}

Then the usage looks like this:

var xml = @"<?xml version=""1.0"" encoding=""utf-16""?>
<bar>
    <foo>
        <item address=""123"">AAA foo</item>
    </foo>
    <definitions>
        <item address=""123"">AAA definition</item>
        <item address=""456"">BBB</item>
    </definitions>
</bar>";

try
{
    var document = XDocument.Parse(xml);
    Console.WriteLine(document.GetValue("foo", "123"));
    Console.WriteLine(document.GetValue("definitions", "123"));
}
catch (Exception exception)
{
    Console.WriteLine(exception.Message);
}

The output is:

AAA foo
AAA definition

Consider adding exception handling and checks to prevent errors. The LINQ fluent and query syntax are in this case (almost) identical.

Community
  • 1
  • 1
keenthinker
  • 7,645
  • 2
  • 35
  • 45