BigfootNick
BigfootNick

Reputation: 3

Querying XML attributes using LINQ

I have the settings for my app in a simple XML document, like this:

<Settings>
    <Server>
        <Id>1</Id>
        <Name>SRV123456</Name> 
        <Par Type="Desktop" Region="Western">12</Par>
        <Par Type="Laptop" Region="Western">15</Par>
        <Par Type="Desktop" Region="Eastern">22</Par>
        <Par Type="Laptop" Region="Eastern">25</Par>
        <State>WA</State>
    </Server>
</Settings>

and am trying to query it using C# and LINQ, using this code:

xelement = XElement.Load(startpath + "\\Settings.xml");
var sn = from sl in xelement.Elements("Server")
       where (string)sl.Element("State") == "WA"
       where (string)sl.Element("Par").Attribute("Region") == "Western"
       where (string)sl.Element("Par").Attribute("Type") == "Desktop"
       select sl;

       foreach (XElement xele in sn)
       {
               Console.WriteLine(xele);
               Console.WriteLine(xele.Element("Par").Value);
       }

This works for the first "Par" value, and will return "12". But if I change

   where (string)sl.Element("Par").Attribute("Type") == "Desktop"

to

   where (string)sl.Element("Par").Attribute("Type") == "Laptop"

It doesn't return any results... what am I missing?

Upvotes: 0

Views: 72

Answers (3)

Rubens Farias
Rubens Farias

Reputation: 57936

Maybe you're trying to return the Western/Laptop value = 15?

var state  = "WA";
var region = "Western";
var type   = "Laptop";
var xElement = XElement.Parse(@"<Settings>
    <Server>
        <Id>1</Id>
        <Name>SRV123456</Name> 
        <Par Type='Desktop' Region='Western'>12</Par>
        <Par Type='Laptop' Region='Western'>15</Par>
        <Par Type='Desktop' Region='Eastern'>22</Par>
        <Par Type='Laptop' Region='Eastern'>25</Par>
        <State>WA</State>
    </Server>
</Settings>");

foreach (XElement server in xElement.XPathSelectElements(
            String.Format("//Server[State='{0}']", state)))
{
    Console.WriteLine(server);

    // In your sample the Western/Desktop is the first element
    // If you want a specific Par element, you should query again with that filter
    foreach (XElement par in server.XPathSelectElements(
                String.Format("Par[@Region='{0}' and @Type='{1}']", region, type)))
        Console.WriteLine(par.Value); ;
}

I choose XPath over Linq to filter XML documents, as XPath seems more concise to me.

Upvotes: 0

Sten Petrov
Sten Petrov

Reputation: 11040

Here's a query that works and looks prettier:

var parValue = xdoc.Descendants("Par")
    .Where(par=>par.Parent.Element("State")?.Value == "WA")
    .Where(par=>par.Attribute("Region")?.Value == "Western")
    .Where(par=>par.Attribute("Type")?.Value == "Laptop")
    .Select(par=>par.Value)
    .FirstOrDefault();

Note that the ?. is a CS6 feature, just omit the ? if using CS5, check for null if needed

Upvotes: 1

Bill Ansley
Bill Ansley

Reputation: 61

I am by no means an expert on LINQ

However

    var sn = from sl in xelement.Elements("Server")
           where (string)sl.Element("State") == "WA"
           where (string)sl.Element("Par").Attribute("Region") == "Western"
           where (string)sl.Element("Par").Attribute("Type") == "Desktop"
           select sl;

I believe mean only return element where Attribute("Type") == "Desktop" means only return those where it equals "Desktop"...so when you loop there are none in your resultset

change to

    var sn = from sl in xelement.Elements("Server")
             where (string)sl.Element("State") == "WA"
             where (string)sl.Element("Par").Attribute("Region") == "Western"
              select sl;

and it should return all the types... not just "Desktop"

Upvotes: 0

Related Questions