Recursively traverse an XML document using the Action delegate in C#

I was lucky enough to be able to develop a relatively complicated recursive process twice. They didn’t do exactly the same same and were different enough that I was not able to reuse the first implementation completely.

What I had to do was build a treeview from a hierarchy of data and reflection objects, capture the results, process them and perform the business specific requirement.

With the first go round I found myself using a lot of IF statements and adding some new properties to my class to store information I used within my IF statements. In the end it worked, it was not difficult to understand and read, plus the recursive part work to infinity…

When I began the second go round, I didn’t have my class anymore to carry the required information I used for my IF statements. Plus, I wasn’t looking forward to writing them all again. So I looked around for other ways to perform a recursive method and I found the Action delegate.

Now that I completed the second go round, I believe this is the way to go. Using this delegate makes my code even more clear and I used at least 70% fewer IF statements.

The first example I show here simply reads through all the elements and access the first attribute within the element. If you needed to get the element element value or other attribute values, you would need to modify the code a little. But not much.

public static void Process(XElement element, int depth = 0)
{
   if (!element.HasElements)
   {
     Console.WriteLine(string.Format("{0}{1}",
                       "".PadLeft(depth, '\t'),
                       element.FirstAttribute.Value));
   }
   else
   {
     Console.WriteLine("".PadLeft(depth, '\t') +
                       element.FirstAttribute.Value);
  
     foreach (XElement child in element.Elements())
     {
       Process(child, depth + 1);
     }
   }
}

It is pretty straight forward and there is nothing special about it really. However, what I needed was the ability to know where I was in the hierarchy of the file and I needed to perform different actions when I exited an element. So the above method did not provide that capability.

The solution to this problem was to use the Action Delegate.

XDocument.Load("C:\\orders.xml").Root.RecursiveProcess
(
   new Action<XElement, int>((child, depth) =>
   {
     Console.WriteLine(string.Format("{0}{1}",
                       "".PadLeft(depth, '\t'),
                       child.FirstAttribute.Value));
   }),
   new Action<XElement, int>((parent, depth) =>
   {
     Console.WriteLine(string.Format("{0}{1}",
                       "".PadLeft(depth, '\t'),
                       parent.FirstAttribute.Value));
   }),
   new Action<XElement, int>((parent, depth) =>
   {
     Console.WriteLine(string.Format("{0}{1}",
                       "".PadLeft(depth, '\t'),
                       parent.FirstAttribute.Value));
   })
);

I created the 3 delegates above. One for when we reach the deepest element if the XML file, on that path, one for when we open a new parent and the last one for when we exit that parent element. The code within the open bracket “{” and the close bracket “}” is what will be executed when I call the method from the RecursiveProcess method.

private static void RecursiveProcess
(
     this XElement element,
     Action<XElement, int> childMethod,
     Action<XElement, int> parentOpenMethod,
     Action<XElement, int> parentCloseMethod,
     int depth = 0)
{
   if (parentOpenMethod != null)
   {
     parentOpenMethod(element, depth + 1);
   }
}

The 3 Action delegates which I created (which are methods) are passed as parameters to the RecursiveProcess method.

I liked the opportunity I had to go back and make an already world class program even better. Iteration is a good thing and we should do it every chance we get.

Download the source