We help IT Professionals succeed at work.

Using Yield to extract XML nodes

I have never used Yield before but need it or something like it.

I am iterating through an entire XML document for a defined set ot tags or arrays of tags. I want to retrieve every tag in the XML document.

How do I do this with Yield? I imagined the function would iterate through them all and return one, the resume at the next node when the function's called again.

Please let me know...

Thanks.
Comment
Watch Question

Most Valuable Expert 2012
Top Expert 2008
Commented:
I would normally assume that you know what the yield keyword does, but just in case:

yield
http://msdn.microsoft.com/en-us/library/9k7k7cf0.aspx

If you have 3.5 or higher, you can use LINQ-to-XML to extract data, and then you wouldn't need an iterator, and the yield return statement.


public class PowersOf2
{
    public static System.Collections.IEnumerable Power(int number, int exponent)
    {
        int counter = 0;
        int result = 1;
        while (counter++ < exponent)
        {
            result = result * number;
            yield return result;
        }
    }

    static void Main()
    {
        // Display powers of 2 up to the exponent 8:
        foreach (int i in Power(2, 8))
        {
            Console.Write("{0} ", i);
        }
    }
}
/*
Output:
2 4 8 16 32 64 128 256 
*/

Open in new window

Most Valuable Expert 2011
Top Expert 2015
Commented:
The yield keyword is used in the context of iterating over some collection or data structure. For instance, under the hood, something like the following could use yield:

foreach (XmlNode node in someNode.ChildNodes)
{

}

Open in new window


If you already have a collection or array, then there wouldn't be much call to use the yield keyword--unless you wanted to ensure the nodes were returned in some specific order.

Can you elaborate on the overall requirement and why you think you might need to use yield?
curiouswebsterSoftware Engineer

Author

Commented:
LINQ to XML sound like it could be the missing link (no pun intended :)

I thought yield since that woudl allow me to write a fucntion that iterates the XmlDocument until done, returning one node at a time. That could work nicely I think. But maybe as kaufmed suggested, using the ChildNodes property in conjunction with a recursive function could also work.

I guess it really doesn't matter to me. I just want all the nodes, one by one.

List<XmlNode> could also work if you can fill it. There are child nodes, so that would be the trick, not needing to know the structure ahead of time.

The order does not matter, I just want all the nodes. And a function that returns them one at a time is okay too.

How can I code this?
Most Valuable Expert 2012
Top Expert 2008
Commented:
What does your XML look like?  What do you need to extract?
curiouswebsterSoftware Engineer

Author

Commented:
everything. I should not need to describe it. There are messages at the root level and messages inside of widgets, which are at the root level.

I want a fucntion that's smart enough to get everything without knowing anything about the doc.

That seems like it shoud not be that hard to do...
curiouswebsterSoftware Engineer

Author

Commented:
I would use recursion if I wanted to construct the search string for this kind of xPath call:

XmlNode node = xmlDoc.SelectSingleNode("/content-item/messages");

I could extract the names "content-item", "messages" and "message" from the XmlDocument and the node(s) found.
Most Valuable Expert 2011
Top Expert 2015
Commented:
The thing to be mindful of when using ChildNodes is that nodes have types (e.g. Element, Text, CData, etc.). You can see the various types in the XmlNodeType enumeration. If you iterate over every node in the document, you are going to get all of these types of nodes. Even a simple node like:

<node>Hello World!</node>

Open in new window


has more than just one node--the text is considered a node as well. You may have to do some additional checking/filtering on the nodes in order to ensure you get the node types you are interested in.
curiouswebsterSoftware Engineer

Author

Commented:
Sorry, I am new to XML. I only need the CDATA nodes, for every elemtn in the xDoc.
curiouswebsterSoftware Engineer

Author

Commented:
yield does not work:

The body of 'ViewValidator.Validator.GetNode(System.Xml.XmlNode)' cannot be an iterator block because 'System.Xml.XmlNode' is not an iterator interface type      

curiouswebsterSoftware Engineer

Author

Commented:
Here's what I have so far...

I am ading each CDATA node to the list, and doing it recursively.

What kind of test should I put in to be sure I only add CDATA nodes?


private List<XmlNode> AddUniqueNode(XmlNode node, List<XmlNode> nodeList)
        {
            if (node != null)
            {
                if (node.HasChildNodes)
                {
                    foreach (XmlNode childNode in node.ChildNodes)
                    {
                        if (!childNode.HasChildNodes)
                        {
                            nodeList.Add(childNode);
                        }

                        XmlNode result = AddUniqueNode(childNode, nodeList);                       
                    }
                }
            }

            return nodeList;
        }

Open in new window

curiouswebsterSoftware Engineer

Author

Commented:
I mean what shal I add to this line?

if (!childNode.HasChildNodes)

so I only get CDATA?
curiouswebsterSoftware Engineer

Author

Commented:
This should be changed to:

nodeList = AddUniqueNode(childNode, nodeList);    
curiouswebsterSoftware Engineer

Author

Commented:
I found it:

if (node.NodeType == XmlNodeType.CDATA)
curiouswebsterSoftware Engineer

Author

Commented:
Thanks.
Most Valuable Expert 2012
Top Expert 2008

Commented:
Would you like to think about LINQ-to-XML?
curiouswebsterSoftware Engineer

Author

Commented:
In the future. I would love to learn that, no question. When I have questions I will ask.

Where's a good place to read up on it?

Thanks.
Most Valuable Expert 2012
Top Expert 2008

Commented:
So many resources, so little time...there really isn't one definitive source...I find that MSDN has good examples, but you need to dig to find them...

Understanding C#: Simple LINQ to XML examples (tutorial)
http://broadcast.oreilly.com/2010/10/understanding-c-simple-linq-to.html

I really love the power of LINQ-to-XML, because it lets you query your XML like it was a database.

Example:


var data = from item in doc.Descendants("person")
                 select new
                 {
                      drink = item.Element("favoriteDrink").Value,
                      moneySpent = item.Element("moneySpent").Value,
                      zipCode = item.Element("personalInfo").Element("zip").Value
                  }

Open in new window

curiouswebsterSoftware Engineer

Author

Commented:
thanks.