Search code examples
c#xmlxpathxelement

I've searched and I cannot seem to get the attribute of an xml element based on the attribute of a sibling xml element in c#


Here is my sample xml:

<customers group="A">
  <customer ID="1234" phone="555-555-0123" name="Golf Clubs International">
    <services>
      <service type="Golf" premise="89645" priority="0" />
    </services>
    <customFields>
      <customField key="address" value="5431 E Golf Way, Altanta, GA, 31111" />
      <customField key="connection" value="CONNECTED" />
    </customFields>
  </customer>

I need to return the customField address value where the service equals 89645. I've tried several different ways using XElement but none of them seem to filter for what I need and even when I get it to filter, I don't know how to re-navigate to get to the sibling element's attribute. Here are some of the things that I've tried to get to filter for the premise attribute. I've used this site for several years and this is the first time I was stumped enough to post a question.

        IEnumerable<XElement> tests =
            from el in cust.Elements("services")
            where (string)el.Elements("service").Attributes("premise").ToString() == ID
            select el;

        var y = cust.Element("customers")
                    .Elements("services")
                    .Where(b => b.Element("service").Value == ID)
                    .SingleOrDefault();

        var x = from a in cust.Elements("service")
                where a.Attribute("premise").Value == ID
                select cust.Elements("customfields").Elements("customfield").Attributes("key");

Solution

  • I like using a dictionary in this case. See code below :

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Xml;
    using System.Xml.Linq;
    
    namespace ConsoleApplication58
    {
        class Program
        {
            const string FILENAME = @"C:\TEMP\TEST.XML";
            static void Main(string[] args)
            {
                XDocument doc = XDocument.Load(FILENAME);
    
                var query = doc.Descendants("customer").Select(x => new{
                    premise = (string)x.Descendants("service").FirstOrDefault().Attribute("premise"),
                    customFields = x.Descendants("customField").GroupBy(y => (string)y.Attribute("key"), z => (string)z.Attribute("value"))
                    .ToDictionary(y => y.Key, z => z.FirstOrDefault())
                }).ToList();
    
                var results = query.Where(x => x.premise == "89645").FirstOrDefault();
    
    
            }
        }
    }
    

    Here is a one statement solution

    XDocument doc = XDocument.Load(FILENAME);

    var query = doc.Descendants("customer").Select(x => new {
        premise = (string)x.Descendants("service").FirstOrDefault().Attribute("premise"),
        customFields = x.Descendants("customField").GroupBy(y => (string)y.Attribute("key"), z => (string)z.Attribute("value"))
        .ToDictionary(y => y.Key, z => z.FirstOrDefault())
    }).Where(x => x.premise == "89645")
    .FirstOrDefault();