views:

70

answers:

5

I have the following XML which needs deserializing/serializing:

<instance>
<dog>
    <items>
        <item>
            <label>Spaniel</label>
        </item>
    </items>
</dog>
<cat>
    <items>
        <item>
            <label>Tabby</label>
        </item>
    </items>
</cat>
</instance>

I cannot change the XML structure.

I need to map this to the following class:

[Serializable, XmlRoot("instance")]
public class AnimalInstance
{
    public string Dog { get; set; }
    public string Cat { get; set; }
}

I'm not really sure where to start on this one without manually parsing the XML. I'd like to keep the code as brief as possible. Any ideas? (and no, my project doesn't actually involve cats and dogs).

A: 

well you may do custom serialization via IXmlSerializable Interface to get structure as you want

Arseny
Indeed - but I'm hoping there might be a better way without writing custom code to parse the XML.
David Neale
+6  A: 

A simple working example (skipping the cat for brevity) using System.Xml.Serialization:

using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;

[XmlRoot("instance")]
public class AnimalInstance {
    [XmlElement("dog")]
    public Dog Dog { get; set; }
}

public class Dog {
    [XmlArray("items")]
    [XmlArrayItem("item")]
    public List<Item> Items = new List<Item>();
}

public class Item {
    [XmlElement("label")]
    public string Label { get; set; }
}

class Program {
    static void Main(params string[] args) {
        string xml = @"<instance>
<dog>
    <items>
        <item>
            <label>Spaniel</label>
        </item>
    </items>
</dog>
</instance>";

        XmlSerializer xmlSerializer = new XmlSerializer(typeof(AnimalInstance));
        AnimalInstance instance = (AnimalInstance)xmlSerializer.Deserialize(new StringReader(xml));
    }
}
Paolo Tedesco
Good suggestion. I ended up using pretty much that but I nested all of the classes inside `AnimalInstance` so they don't get obviously exposed.
David Neale
@David Neale: if you don't want your classes to be public you can create a serialization assembly and use the InternalsVisibleToAttribute on that: check this question http://stackoverflow.com/questions/2262957/serialize-list-of-classes-declared-with-internal-modifier
Paolo Tedesco
+2  A: 

why is it such a problem to write custom parsing code? for your simple example it may actually involve less code to use an XDocument:

XDocument xdoc = XDocument.Parse(xml);
AnimalInstance animal = new AnimalInstance()
{
    Dog = xdoc.XPathSelectElement("instance/dog/items/item/label").Value,
    Cat = xdoc.XPathSelectElement("instance/cat/items/item/label").Value
};
Mark Heath
Serialization would require a little more work; +1 from me, by the way :)
Paolo Tedesco
Good suggestion. I'll go for Paolo's answer this time as I need to serialize as well as deserialize.
David Neale
A: 

You may also transform the XML document using an XSL to a structure you like and deserialize the output of this transformation. But for such an easy structure, you should use another solution like the one provided by Paolo Tedesco.

Scoregraphic
+1  A: 

When in doubt with creating your xml serialization classes, i find the easiest way to solve the problem is to:

  • dump all your dummy data into an XML file
  • run xsd.exe to create a .xsd schema file
  • run xsd.exe on your schema file to create a class file

i wrote a quick tutorial on it in a blog post a while ago: http://www.diaryofaninja.com/blog/2010/05/07/make-your-xml-stronglytyped-because-you-can-and-its-easy

it takes less than a minute and you can then easily tweak things from there. XSD.exe is your friend

Doug
Very good point. +1
David Neale