XDocument get XML element by the value of its name attribute

kbaccouche picture kbaccouche · Jan 24, 2013 · Viewed 41.2k times · Source

I have an XML result like this

<response>
  <lst name="responseHeader">
    <int name="status">0</int>
    <int name="QTime">16</int>
  </lst>
  <result name="response" numFound="3" start="0" maxScore="1.0">
    <doc>
      <str name="ContaFirstname">
        firstname1                                                   
      </str>
      <str name="ContaId">6557</str>
      <str name="ContaJobTitle">Manager</str>
      <str name="ContaSurname">surname1
      </str>
    </doc>
    <doc>
      <str name="ContaFirstname">firstname2</str>
      <str name="ContaId">6203</str>
      <str name="ContaJobTitle">Director</str>
      <str name="ContaSurname">surname2</str>
    </doc>
  </result>
</response>

I want to get a list of objects, and every object will contain the value of ContaFirstname, ContaId, ContaJobTitle and ContaSurname

I tried something like this, but that's not right because I get them all NULL

var test = from c in xml.Descendants("doc")
                    select new 
                    {
                        firstname = c.Element("ContaFirstname"),
                        surnmane = c.Element("ContaSurname")
                    }; 

So how can access these elements by name?

Answer

Jon Skeet picture Jon Skeet · Jan 24, 2013

You don't want to access the elements by name as most people would interpret that statement. You want to access the elements by the value of their name attribute:

firstname = (string) c.Elements("str")
                      .First(x => x.Attribute("name").Value == "ContaFirstname");
//etc

You may well want to abstract that into a separate method, as it's going to be a pain to do it multiple times. For example:

public static XElement ElementByNameAttribute(this XContainer container,
                                              string name)
{
    return container.Elements("str")
                    .First(x => x.Attribute("name").Value == name);
}

Then:

var test = from c in xml.Descendants("doc")
           select new 
           { 
               firstname = c.ElementByNameAttribute("ContaFirstname").Value,
               surnmane = c.ElementByNameAttribute("ContaSurname").Value
           }; 

If you have any chance to give your document a more sensible structure, that would be preferable...