6

I need inputs in converting an dynamic xml to defined c# object model

My sample xml is as below :

<?xml version="1.0" encoding="utf-8" ?>
  <Persons>
    <Person>
      <Id>10</Id>
      <FirstName> Dino </FirstName>
      <LastName> Esposito </LastName>
      <Addresses>
        <Address>
          <AddressType>BillTo</AddressType>
          <Street1></Street1>
          <Street2></Street2>
          <Street3></Street3>
          <City>Moscow</City>
        </Address>
        <Address>
          <AddressType>ShipTo</AddressType>
          <Street1></Street1>
          <Street2></Street2>
          <Street3></Street3>
          <City>Moscow</City>
        </Address>
        <Address>
          <AddressType>Contact</AddressType>
          <Street1></Street1>
          <Street2></Street2>
          <Street3></Street3>
          <City>Moscow</City>
        </Address>
      </Addresses>
    </Person>
  </Persons>

I am expecting the values of this xml to be converted to C# object at run time. I would want an object similar to the following to be defined: My Expected class object C# is as below:

public class Person
{
    public int Id { get; set; }
    public String FirstName { get; set; }
    public String LastName { get; set; }
    public IList<Address> Addresses { get; set; }
}

public class Address
{
    public string AddressType { get; set; }
    public string Street1 { get; set; }
    public string Street2 { get; set; }
    public string Street3 { get; set; }
    public string City { get; set; }
}

I went through dynamic and ExpandoObject in C# 4.0, this approach is allowing me to get values dynamically by using keys. I dont know how i can populate these to my datamodel.

Note: I dont want to define this class model structure, this keeps changing over period of time. I am looking for a solution which allows me to get values like DynamicObject.Addresses.Address[0].City.

Kindly give your inputs.

KRP
  • 131
  • 1
  • 3
  • 15
  • 2
    What is "dynamic xml"? Did you try e.g. LinqToXml? – mipe34 May 20 '13 at 12:35
  • I dont want to keep tab on xml content,this keeps on changing. my datamodel should also change dynamically based on input xml on runtime. – KRP May 20 '13 at 12:41
  • I have tried linq to Xml, i am not able to work with array of element. ex: addresses – KRP May 20 '13 at 12:44
  • Why don't you query(LINQ) your XML using XPath? http://msdn.microsoft.com/en-us/library/bb387057.aspx – Adolfo Perez May 20 '13 at 13:09
  • How do you intend your data model to change without recompiling? i.e. if a Person starts to include a DateOfBirth your Person class is out of date. – Liam May 20 '13 at 13:18
  • 1
    I personally can't see how it is any better to work with dynamic objects than to define some classes. If/when the data source changes you are going to have to refactor the code anyway. It's much easier to do that with refactoring tools if you have classes. But that's just my 2 cents. – BlakeH May 20 '13 at 13:20
  • @KPR It looks like you are going to have to give a more concrete use case for this approach. Please explain more about why you even want to use this approach. – Gerard Sexton May 20 '13 at 13:31

3 Answers3

6

A solution using LINQ2XML can look like this (no classes needed):

var xml = XDocument.Parse(xmlSrc); // from XML string, e.g.: <xml ...><Persons><Person>...
//var xml = XDocument.Load(xmlFile); // from XML file, e.g.: c:\temp\persons.xml

var persons = xml.Root.Elements("Person").ToList();
var p1Addresses = persons[0].Elements("Addresses").ToList();
foreach (var address in p1Addresses.Elements("Address"))
{
    var elementAddress = address.Element("AddressType");
    var elementCity = address.Element("City");
    System.Console.WriteLine(string.Format("{0} - {1}", elementAddress.Value, elementCity.Value));
}

The output is:

BillTo - Moscow
ShipTo - Moscow
Contact - Moscow
keenthinker
  • 7,645
  • 2
  • 35
  • 45
2

Check this example:

        string xml =
            @"<?xml version='1.0' encoding='utf-8' ?>
              <Persons>
               <Person>
                <Id>10</Id>
                <FirstName> Dino </FirstName>
                <LastName> Esposito </LastName>
                <Addresses>
                  <Address>
                   <AddressType>BillTo</AddressType>
                   <Street1></Street1>
                   <Street2></Street2>
                   <Street3></Street3>
                   <City>Moscow</City>
                </Address>
                <Address>
                 <AddressType>ShipTo</AddressType>
                 <Street1></Street1>
                 <Street2></Street2>
                 <Street3></Street3>
                 <City>Moscow</City>
                </Address>
                <Address>
                  <AddressType>Contact</AddressType>
                  <Street1></Street1>
                  <Street2></Street2>
                  <Street3></Street3>
                  <City>Moscow</City>
                </Address>
             </Addresses>
            </Person>
           </Persons>";

        XElement root = XElement.Parse(xml);

        IEnumerable<XElement> list = root.XPathSelectElements("./Person/Addresses/Address[2]/City");
        foreach (XElement el in list)
            Console.WriteLine(el);
        Console.ReadLine();

You will get: <City>Moscow</City>

Or look at this solution using DynamicObject:

    XElement root = XElement.Parse(xml);
    dynamic persons = DynamicXml.Parse(xml);
    Console.WriteLine(persons.Person.Addresses.Address[1].City);

Deserialize XML To Object using Dynamic

Community
  • 1
  • 1
Adolfo Perez
  • 2,834
  • 4
  • 41
  • 61
0

I've created a project specifically for this purpose, as I was dissatisfied with the alternatives (such as the CodeProject article linked to in other answers).

I've posted it on Github: https://github.com/jonathanconway/XmlToDynamic.

I would rather not post the source code here, as it's too big, but here's the usage:

var xmlString =
    @"<addressBook>
       <contacts>
         <contact>
           <name>Jonathan</name>
         </contact>
       </contacts>
     </addressBook>";
var dynamicXml = XElement.Parse(xmlString).ToDynamic();
var firstPersonsName = dynamicXml.contacts[0].name.Value;
// firstPersonsName will be 'Jonathan'
Jonathan
  • 32,202
  • 38
  • 137
  • 208