LINQ to XML and XPath


An XML needs to be parsed – I was told the other day. My first questions from experience, how big the XML is going to be? Do we know the schema? The answer : It’s never going to be bigger than few lines, as we use it to store our application’s menu – which may or may not have child(ren). And yes we know the XML schema. Enough said. Now I needed just one more ingredient, a sample XML. I was not thinking to have an extra schema class, the schema was unlikely to change as we controlled it ( if not, I would definitely have re-thought the approach depending on the answers to my questions above )

It looked something like below :

<?xml version='1.0' encoding='utf-8' ?>
<Menu>
    <Group>
        <Item Label='Menu1' Href='/Menu1/Dashboard'>
            <Group>
                <Item Label='Menu 1 Screen1' Href='/Menu1/Screen1' />
            </Group>
        </Item>
        <Item Label='Menu2' Href='/Menu2'>
            <Group>
                <Item Label='Menu 2 Screen 1' Href='/Menu2/Screen1' />
                <Item Label='Menu 2 Screen 2' Href='/Menu2/Screen2' />
            </Group>
        </Item>
        <Item Label='Menu3' Href='/Menu3'>
            <Group>
                <Item Label='Service 1' Href='http://service1.asmx'/>
                <Item Label='Menu 3 Screen 1' Href='/Menu3/Screen1' />
                <Item Label='Menu 3 Screen 2' Href='/Menu3/Screen2' />
            </Group>
        </Item>
        <Item Label='Menu 3 w/o child' Href='/Menu3' />
    </Group>
</Menu>

Alright, for my first prototype I need a list of menu labels and their corresponding child(ren). I know I can use LINQ to XML and blend it with some XPath query for quick and easy solution, I know the XML is pretty small, so I do not have to worry about a fast, read-only cache for XML document processing by using XSLT by using the XPathNavigator interface. I just needed something short and sweet. So I know that the parent elements could be accessed using /Menu/Group/Item. And then I would iterate through each, and within each such node, /Group/Item would give me the child(ren) elements, if any. Simple plan of attack.

Next thing, I fire up my LINQ-pad and start writing the code and ended up with following ( I have replaced the LINQ-pad’s Dump() with Console.WriteLine() if you still have not fallen for LINQ-pad or have been living in a cave and wondering what it is )

// using System;
// using System.Collections.Generic;
// using System.Linq;
// using System.Xml.Linq;
// using System.Xml.XPath;

XDocument xDocument = XDocument.Parse(xml);
string[] childLabelAttributeValues = null;
IEnumerable<XElement> childElements = null;
XAttribute labelAttribute = null;

var rootElements = xDocument.XPathSelectElements("./Menu/Group/Item");

foreach (var rootElement in rootElements)
{
    childElements = rootElement.XPathSelectElements("./Group/Item");
    labelAttribute = rootElement.Attributes("Label").FirstOrDefault();

    if (labelAttribute != null)
    {
        Console.WriteLine(labelAttribute.Value);
    }

    // drill for any child element
    if (childElements != null && childElements.Count() > 0)
    {
        //Console.WriteLine(string.Format("\tHas {0} child(ren)", childElements.Count()));

        childLabelAttributeValues = childElements.Select(e => e.Attributes("Label").FirstOrDefault().Value).ToArray<string>();
        Console.WriteLine("\t" + string.Join(", ", childLabelAttributeValues));
    }
}

Just a quick post. So I kept it simple. In reality this code should somehow spit out some data-structure (if using any 3rd party controls) or if I was to use this XML directly in the front end w/o much complexity, I would not even bother writing the code above in C# since you could also do XPath in JavaScript !

Either way, C# or JavaScript but one thing I would definitely make sure to have is a recursive check for children ( keep drilling )

Advertisements

Published by

Aarsh Talati

Software Developer

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s