Linq to XML Document Traversal

I have an XML document like:

<?xml version="1.0" encoding="utf-8" ?>
<demographics>
    <country id="1" value="USA">
        <state id ="1" value="California">
            <city>Long Beach</city>
            <city>Los Angeles</city>
            <city>San Diego</city>
        </state>
        <state id ="2" value="Arizona">
            <city>Tucson</city>
            <city>Phoenix</city>
            <city>Tempe</city>
        </state>
    </country>
    <country id="2" value="Mexico">
        <state id ="1" value="Baja California">
            <city>Tijuana</city>
            <city>Rosarito</city>            
        </state>
    </country>
</demographics> 

      

How do I set up LINQ queries to do things like: 1. Get all countries 2. Get all states in a country 3. Get all cities in a parent country state?

I tried it and I'm a little confused when I use Elements ["NodeName"] and Descendants etc. I know I am not the brightest XML guy. Is the XML file format correct for a simple workaround?

+2


a source to share


3 answers


To load a document from a file:

XDocument document = XDocument.Load("input.xml");

      

To get the names of all countries:

IEnumerable<string> countries = document
    .Descendants("country")
    .Select(element => element.Attribute("value").Value);

      

To get all states that are within the "USA" country:



IEnumerable<string> states = document
    .Descendants("country")
    .Where(element => element.Attribute("value").Value == "USA")
    .Elements("state")
    .Select(element => element.Attribute("value").Value);

      

To get all cities within the US / California:

IEnumerable<string> cities = document
    .Descendants("country")
    .Where(element => element.Attribute("value").Value == "USA")
    .Elements("state")
    .Where(element => element.Attribute("value").Value == "California")
    .Elements("city")
    .Select(element => element.Value);

      

You can also look at XPath queries (you need using System.XML.XPath

):

IEnumerable<string> cities = document
    .XPathSelectElements("/demographics/country[@value='USA']/state[@value='California']/city")
    .Select(element => element.Value);

      

+4


a source


Like this:



var countries = document.Root.Elements("country");
var states    = country.Elements("state");
var cities    = state.Elements("city");

      

+1


a source


var doc = XDocument.Load("myxml.xml");


var countries = doc.Descendants("country")
                   .Attributes("value")
                   .Select(a => a.Value);

var states    = doc.Descendants("country")
                   .Single(country => country.Attribute("value").Value == "USA")
                   .Elements("state")
                   .Attributes("value")
                   .Select(a => a.Value);

var cities    = doc.Descendants("state")
                   .Single(state => state.Attribute("value").Value == "California")
                   .Elements("city")
                   .Select(e => e.Value);

      

The result will be countries

, states

and cities

as a type IEnumerable<string>

.

It's also worth noting that execution (such as parsing) will be deferred until the actual listing of the values ​​in these variables IEnumerable<string>

. This can sometimes lead to unexpected performance problems. For example, if you plan on displaying all the data anyway, and you bind it to some UI control, the UI can get sluggish as it realizes that it needs to parse it after all. (It might even block the UI thread and not the worker thread? Not sure.) To fix this, add .ToList()

to the end so that it is deferred instead List<string>

.

+1


a source







All Articles