Tuesday, 24 July 2012

Parse XML to dynamic object in C#

<?xml version="1.0" encoding="utf-8" ?>
<contacts>
  <contact id='1'>
    <firstName>Michael</firstName>
    <lastName>Jordan</lastName>
    <age>40</age>
    <dob>1965</dob>
    <salary>100.35</salary>
  </contact>
  <contact id='2'>
    <firstName>Scottie</firstName>
    <lastName>Pippen</lastName>
    <age>38</age>
    <dob>1967</dob>
    <salary>55.28</salary>
  </contact>
</contacts>
public class XmlToDynamic
{
  public static void Parse(dynamic parent, XElement node)
  {
    if (node.HasElements)
    {
      if (node.Elements(node.Elements().First().Name.LocalName).Count() > 1)
      {
        //list
        var item = new ExpandoObject();
        var list = new List<dynamic>();
        foreach (var element in node.Elements())
        {            
          Parse(list, element);            
        }
 
        AddProperty(item, node.Elements().First().Name.LocalName, list);
        AddProperty(parent, node.Name.ToString(), item);
      }
      else
      {
        var item = new ExpandoObject();
 
        foreach (var attribute in node.Attributes())
        {
          AddProperty(item, attribute.Name.ToString(), attribute.Value.Trim());
        }
 
        //element
        foreach (var element in node.Elements())
        {
          Parse(item, element);
        }
 
        AddProperty(parent, node.Name.ToString(), item);
      }
    }
    else
    {
      AddProperty(parent, node.Name.ToString(), node.Value.Trim());
    }
  }
 
  private static void AddProperty(dynamic parent, string name, object value)
  {
    if (parent is List<dynamic>)
    {
      (parent as List<dynamic>).Add(value);
    }
    else
    {
      (parent as IDictionary<String, object>)[name] = value;
    }
  }
}
[Test]
public void Test()
{
  //read from text
  //var xDoc = XDocument.Parse(txt);
 
  //read from url
  //var request = WebRequest.Create(@"http://...") as HttpWebRequest;
  //request.Credentials = CredentialCache.DefaultNetworkCredentials;
  //var xDoc = XDocument.Load(request.GetResponse().GetResponseStream());
 
  //read from file
  var xDoc = XDocument.Load(new StreamReader("contacts.xml"));
 
  dynamic root = new ExpandoObject();
 
  XmlToDynamic.Parse(root, xDoc.Elements().First());
 
  Console.WriteLine(root.contacts.contact.Count);
  Console.WriteLine(root.contacts.contact[0].firstName);
  Console.WriteLine(root.contacts.contact[0].id);
}

3 comments:

Anonymous said...

This is the most functional XML to dynamic ExpandoObject code I've seen yet. That said, it does make assumptions that all XML looks like the test XML. (All examples I've seen so far assume all XML looks like their sample XML, though.) For example, in the Parse method:

(node.Elements(node.Elements().First().Name.LocalName).Count() > 1)

The above line assumes that if the first child element is not a list, the remainder of the elements are not lists either. It is completely possible that there is a series of non-list attributes followed by one or more lists (as in the XML I am required to consume from a third party.)

Anonymous said...

A Code Project article updating this code has been posted to the following URL:

http://www.codeproject.com/Articles/461677/Creating-a-dynamic-object-from-XML-using-ExpandoOb

lingmaaki said...

try use xmlreader aalso...C# XML Parser

ling

Post a Comment