Project Description
Let's make querying data enjoyable for the masses. This library allows you to easily query XML documents using C# instead of embedded XPath strings. The library also contains a very lightweight Object Relational Mapper (ORM) using expression trees to strongly type the querying process. I'll tidy the ORM portion at a later time and upload it here. I've enjoyed using this ORM in the past for projects where the Entity Framework seemed like overkill.

For now, I'll simply introduce you to DynamicXPath...

The Old Way
XmlDocument document = new XmlDocument();
document.Load("contacts.xml");

XmlNodeList contactNameNodes = document.SelectNodes("/Phonebook/Contacts/Contact/Name"); // Hmm, a language within a language
IList<string> contactNames = new List<string>();

foreach (XmlNode contactNameNode in contactNameNodes)
{
    contactNames.Add(contactNameNode.InnerText);    
}


The DynamicXpath Way!
dynamic addressBook = DynamicXpath.Load("contacts.xml");
List<string> contactNames = addressBook.Contacts.Contact.Name;
Or even more concise if that's your cup of tea...
List<string> contactNames = DynamicXpath.Load("contacts.xml").Contacts.Contact.Name;

And some more things that you can do
These are just a few more things you can do with DynamicXpath. DynamicXPath also provides user-friendly ways to retrieve non-string node values (i.e. int, decimal, double, bool).
dynamic addressBook = DynamicXpath.Load("contacts.xml");
                        
// Resolves to: "/*/Contacts/Contact[Name = 'Tony']/Phone[1]/text()"
string tonyPhoneNumber = addressBook.Contacts.Contact[new { Name = "Tony" }].Phone;

// Resolves to: "/*/Contacts/Contact[Name = 'Tony']/Phone[1]/text()"
string tonyPhoneNumber2 = addressBook.Contacts.Contact["Name = 'Tony'"].Phone;

// Resolves to: "/*/Contacts/Contact[(Name = 'Tony' and Phone = '555-111-1111') or Name = 'Sam']/Phone/text()"
List<string> tonyAndSamsPhoneNumbers = addressBook.Contacts.Contact[new { Name = "Tony", Phone = "555-111-1111" }, new { Name = "Sam" }].Phone;

// Resolves to: "/*/Contacts/Contact[Name = 'Steph']/Phone[1]/text()"
string stephPhoneNumber = addressBook.Contacts.Contact[() => p.Name == 'Steph'].Phone;  // Currently not supported by C# 4.0

// Resolves to: "/*/Contacts/Contact[Name = 'Tony' or Name = 'Steph']/Phone[1]/text()"
List<string> tonyAndStephsPhoneNumbers = addressBook.Contacts.Contact[p => p.Name == "Tony" || p.Name == 'Steph'].Phone;  // Currently not supported by C# 4.0

// Resolves to: "/*/Contacts/Contact/Phone"
XmlNodeList allPhoneNumberNodes = addressBook.Contacts.Contact.Phone;

// Resolves to: "/*/Contacts/Contact/Phone/text()"
List<string> allPhoneNumbers = addressBook.Contacts.Contact.Phone;

// Resolves to: "/*/Contacts/Contact[1]"
XmlNode firstContact = addressBook.Contacts.Contact;

// Resolves to: "/*/Contacts/Contact[Name = 'Tony']/Phone[1]/@Tag"
string phoneTag = addressBook.Contacts.Contact["Name = 'Tony'"].Phone.Attribute("Tag");

// Resolves to: "/*/Contacts/Contact/Phone[@Tag = 'mobile']/text()"
List<string> mobilePhoneNumbers = addressBook.Contacts.Contact.Phone[new AttributeExample(new { Tag = "mobile" })];

// Enumerating over the dynamic XPath
foreach (dynamic contact in addressBook.Contacts.Contact)
{
    Console.WriteLine("{0}, {1}", contact.Name, contact.Phone);
}

Enjoy
If you have any comments/suggestions, drop me a note or contribute to the project.

Last edited May 28, 2011 at 11:27 PM by TonyO, version 25