tags:

views:

325

answers:

3

I'm new to Linq to Xml. I have a very simple xml file like this:

<Items>
    <Item>
       <Stuff>Strings</Stuff>
    </Item>
    <Item>
       <Stuff>Strings</Stuff>
    </Item>
</Items>

And I'm trying to query it like this:

XDocument doc = XDocument.Load(myStream)
from node in doc.Descendants(XName.Get("Item"))
    select new { Stuff = node.Element(XName.Get("Stuff")).Value }

But doc.Descendents(XName.Get("Item")) returns null. Something is wrong with my understanding here.

A: 

Try using doc.Root.Decendants("Item")

palehorse
A: 

There's an implicit conversion from System.String to XName, so the more usual form is

...doc.Descendants("Item")

and

...node.Element("Stuff").Value

Besides that, I suggest doc.Root.Descendants() as in the previous answer. The document is still at the "top" of the hierarchy when it's loaded. I was under the impression that Descendants() was recursive, but who knows, right?

mquander
Thanks for the tip, thats much easier to read and write.
BC
+1  A: 

Your code actually works:

static void Main(string[] args)
{
    string xml = @"
                <Items>
                    <Item>
                        <Stuff>Strings</Stuff>
                    </Item>
                    <Item>
                        <Stuff>Strings</Stuff>
                    </Item>
                </Items>";

    using (StringReader myStream = new StringReader(xml))
    {
        XDocument doc = XDocument.Load(myStream);

        var query = from node in doc.Descendants(XName.Get("Item"))
                    select new { Stuff = 
                        node.Element(XName.Get("Stuff")).Value };

        foreach (var item in query)
        {
            Console.WriteLine("Stuff: {0}", item.Stuff);
        }
    }

It should be noted that if the elements are not qualified with namespaces, then you don't really need XName:

static void Main(string[] args)
{
    string xml = @"
                <Items>
                    <Item>
                        <Stuff>Strings</Stuff>
                    </Item>
                    <Item>
                        <Stuff>Strings</Stuff>
                    </Item>
                </Items>";

    using (StringReader myStream = new StringReader(xml))
    {
        XDocument doc = XDocument.Load(myStream);

        var query = from node in doc.Descendants("Item")
                    select new { Stuff = node.Element("Stuff").Value };

        foreach (var item in query)
        {
            Console.WriteLine("Stuff: {0}", item.Stuff);
        }
    }
}
casperOne
You're right. It does work. But when I break with the debugger and start examining the object model with the command window, it does not work. I never actually tried executing it without stepping through. Do you have any insight into this?
BC
I broke on the line containing the linq query and executed"? doc.Descendants("Item")"in the command window.
BC
@BC: If you put it in the watch window, you get null? Or it says that it throws an exception?
casperOne
If I put doc.Descendants("Item") in the watch, the value before and after the query is "This expression causes side effects and will not be evaluated."
BC
Maybe it can it only be evaluated once?
BC
@BC: No, you should be able to evaluate it multiple times. You need to post a complete code example, and detail where you set the break, as well as what you are trying to observe.
casperOne
I can force the evaluation multiple times in the watch using the little recycle icon. Thanks for your help.
BC