Derek Lakin

Determining the Relative Path in XLinq with Extension Methods

Introduction

In Titan, I’m edging closer and closer to releasing a beta 1 for public consumption and one of the tasks that I’m working on to get me there is a lazy-loading folder browser dialog box that enables you to browse through the folder structure of a particular service without having to load the whole folder structure in one go. This is used specifically for specifying new service configurations and is of particular concern for the local file system provider. Have you ever tried to retrieve your whole hard disk structure in one go!?

My service methods were already using some XLinq to parse the XML response from the Box.net service call and the local file system provider, but for the Box.net service provider I needed a way of finding a particular folder based on it’s relative path. The contents of a fictitious Box.net folder structure could look like the following XML example.

folder id="0" name="" shared="0">tags>tags>files>files>folders>folder id="4384" name="Incoming" shared="0">tags>tag id="34" />tags>files>file id="68736" filename="cows.w3g" keyword="" shared="0" size="232386" created="1129537520" updated="1129537520">tags>tags>file>file id="68737" filename="silver.html" keyword="" shared="0" size="15805" created="1129537520" updated="1129537520">tags>tag id="35" />tags>file>files>folders>folder id="1234" name="Test" shared="0">folders>folder id="2345" name="wibble" shared="0">folders />folder>folder id="5432" name="wobble" shared="0">folders />folder>folders>folder>folder id="4321" name="Test2" shared="0">folders />folder>folders>folder>folders>folder>

The Problem

So, if I want to retrieve the folder contents of the folder named Test, which has a relative path of “IncomingTest”, how do I find that in XLinq? Well, I looked at all kinds of different approaches using the Descendants and Ancestors methods, but none of them managed to produce the goods, because I needed a single string that I could compare against.

The Solution

To solve the problem I decided to use an extension method to produce a single string from a collection. The results of an XLinq query are IEnumerable, where T depends on the exact nature of the query. In my case, I was pulling out the name attribute, so I had IEnumerable. The extension method shown in the following code example uses a StringBuilder to build up the single string.

///

/// Converts the IEnumerableto a single string. /// /// The source IEnumerable. /// A single string that represents the contents of the IEnumberablepublic static string ToOneString(this IEnumerablestring> source) { StringBuilder builder = new StringBuilder(); // Add each item. foreach (string item in source) { if (item.Length > 0) { builder.Append(item); } } return builder.ToString(); }

This didn’t quite solve the problem, because for my scenario described above, this produces a single string of “IncomingTest”, which isn’t quite a relative path. So, I added an overload for the method that accepts a string separator to produce the following.

///

/// Converts the IEnumerableto a single string. /// /// The source IEnumerable. /// A single string that represents the contents of the IEnumberablepublic static string ToOneString(this IEnumerablestring> source) { return source.ToOneString(string.Empty); } /// /// Converts the IEnumerableto a single string. /// /// The source IEnumerable. /// A separator to be placed between each item in the string. /// A single string that represents the contents of the IEnumberablepublic static string ToOneString(this IEnumerablestring> source, string separator) { StringBuilder builder = new StringBuilder(); // Add each item and the separator. foreach (string item in source) { if (item.Length > 0) { builder.Append(item); builder.Append(separator); } } // Remove the final separator. if (builder.Length >= separator.Length) { builder.Remove(builder.Length - separator.Length, separator.Length); } return builder.ToString(); }

In my reusable library, I’ve also created a version of ToOneString for IEnumerable, which simply appends item.ToString() to the StringBuilder.

And Finally

So, my final XLinq query that builds up the relative path and returns me the folders for a specific relative path looks like the following code example, where relativePath is a string parameter to the method that specifies the relative path to the folder that I want to retrieve the child folders.

var query = (from d in xRoot.DescendantsAndSelf("folder") where "" + (from a in d.AncestorsAndSelf("folder") select a.Attribute("name").Value).Reverse().ToOneString("") == relativePath select d.Element("folders").Elements("folder")).First();

If there are any folders in the specified folder, then I can enumerate the resulting XElement collection and build up instances of my File class.

This work is licensed under a [Creative Commons Attribution By license.](http://creativecommons.org/licenses/by/3.0/)
[![](http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http://cloudstore.blogspot.com/2008/07/determining-relative-path-in-xlinq-with.html&bgcolor=0080C0&fgcolor=FFFFFF&border=000000&cbgcolor=D4E1ED&cfgcolor=000000)](http://www.dotnetkicks.com/kick/?url=http://cloudstore.blogspot.com/2008/07/determining-relative-path-in-xlinq-with.html)