Sunday, April 3, 2011

What is wrong with my simple query?

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.

From stackoverflow
  • Try using doc.Root.Decendants("Item")

  • 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?

    BC : Thanks for the tip, thats much easier to read and write.
  • 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);
            }
        }
    }
    
    BC : 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.
    casperOne : @BC: If you put it in the watch window, you get null? Or it says that it throws an exception?
    BC : 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?
    casperOne : @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.
    BC : I can force the evaluation multiple times in the watch using the little recycle icon. Thanks for your help.

0 comments:

Post a Comment