jsturtevant
jsturtevant

Reputation: 2610

Generic serialization of lists in C#

I am trying to serialize several lists of objects to xml. The lists are of different types but they all need to have some the same attributes on the top list object.

What I am trying to get is a 'count' on the top level and the name of the object for all the items in the list:

 <JobResult Count="2">
       <Job>
           <Id>1</Id>
       </Job>
       <Job>
           <Id>2</Id>
       </Job>
    </JobResult>

Then for another list:

 <PersonResult Count="1">
       <Person>
           <Id>1</Id>
       </Person>
 </PersonResult>

The code I am using is:

[XmlRoot()]
    public class Result<T>
    {
        [XmlElement()]
        public List<T> Items { get; set; }

        public Result()
        {
            this.Items = new List<T>();
        }

        [XmlAttribute("Count")]
        public int ItemCount
        {
            get
            {
                return this.Items.Count;
            }
            set
            {

            }
        }
    }
var jobs= new Result<Job>();
var persons= new Result<Person>();

What I am getting is:

<ResultOfJob Count="2">
       <Item>
           <Id>1</Id>
       </Item>
       <Item>
           <Id>2</Id>
       </Item>
    </ResultOfJob >

I have tried the attribute naming like this but get <_x007B_0_x007D_> instead of item.

[XmlElement({0})]
 public List<T> Items { get; set; }

What is the best way to handle naming the items dynamically?

Upvotes: 3

Views: 2152

Answers (2)

jsturtevant
jsturtevant

Reputation: 2610

The way I ended up solving this is creating the result class in a similar fashion:

public abstract class Result<T> 
{
    [XmlIgnore]
    public abstract List<T> Items {get;set;}

    [XmlAttribute]
    public int ResultCount
    {
        get
        {
            return this.Items.Count;
        }
        set { }
    }


    public Result()
    {
        this.Items = new List<T>();
    }

And then I Inherit this class for any object that I need to have the common ResultCount as an attribute. If I need to add any other common attributes to all of the results objects I can do it through the above Result class.

Here Is an example inherited class:

public class ChallengesResult : Result<ChallengeResource>
{
    public ChallengesResult()
        : base()
    {
    }


    [XmlElement("Challenge")]
    public override List<ChallengeResource> Items { get; set; }
}

The [XmlIgnore] on the List in the Result class allows me to specify the name of the list items in the derived class with the [XmlElement] attribute.

Upvotes: 3

Cinchoo
Cinchoo

Reputation: 6326

Here is how you can achieve it for a Job / Person types defined as below

public class Job
{
    [XmlElement]
    public int Id;
}

public class Person
{
    [XmlElement]
    public int Id;
}

To product JobResult Xml,

private static string GetJobResultXml()
{
    var jobs = new Result<Job>();
    jobs.Items.Add(new Job() { Id = 1 });
    jobs.Items.Add(new Job() { Id = 2 });

    XmlSerializerNamespaces xmlnsEmpty = new XmlSerializerNamespaces();
    xmlnsEmpty.Add("", "");

    XmlWriterSettings xws = new XmlWriterSettings();
    xws.OmitXmlDeclaration = true;
    xws.ConformanceLevel = ConformanceLevel.Auto;
    xws.Indent = true;

    XmlAttributeOverrides overrides = new XmlAttributeOverrides();
    XmlAttributes attr = new XmlAttributes();
    attr.XmlRoot = new XmlRootAttribute("JobResult");
    overrides.Add(jobs.GetType(), attr);

    XmlAttributes attr1 = new XmlAttributes();
    attr1.XmlElements.Add(new XmlElementAttribute("Job", typeof(Job)));
    overrides.Add(jobs.GetType(), "Items", attr1);

    StringBuilder xmlString = new StringBuilder();
    using (XmlWriter xtw = XmlTextWriter.Create(xmlString, xws))
    {
        XmlSerializer serializer = new XmlSerializer(jobs.GetType(), overrides);
        serializer.Serialize(xtw, jobs, xmlnsEmpty);

        xtw.Flush();
    }

    return xmlString.ToString();
}

In order to produce PersonResult xml, you will have to do modify the above method slightly to get the expected result as below

private static string GetPersonResultXml()
{
    var jobs = new Result<Person>();
    jobs.Items.Add(new Person() { Id = 1 });
    jobs.Items.Add(new Person() { Id = 2 });

    XmlSerializerNamespaces xmlnsEmpty = new XmlSerializerNamespaces();
    xmlnsEmpty.Add("", "");

    XmlWriterSettings xws = new XmlWriterSettings();
    xws.OmitXmlDeclaration = true;
    xws.ConformanceLevel = ConformanceLevel.Auto;
    xws.Indent = true;

    XmlAttributeOverrides overrides = new XmlAttributeOverrides();
    XmlAttributes attr = new XmlAttributes();
    attr.XmlRoot = new XmlRootAttribute("PersonResult");
    overrides.Add(jobs.GetType(), attr);

    XmlAttributes attr1 = new XmlAttributes();
    attr1.XmlElements.Add(new XmlElementAttribute("Person", typeof(Person)));
    overrides.Add(jobs.GetType(), "Items", attr1);

    StringBuilder xmlString = new StringBuilder();
    using (XmlWriter xtw = XmlTextWriter.Create(xmlString, xws))
    {
        XmlSerializer serializer = new XmlSerializer(jobs.GetType(), overrides);
        serializer.Serialize(xtw, jobs, xmlnsEmpty);

        xtw.Flush();
    }

    return xmlString.ToString();
}

I hope this helps.

For more information on using XmlAttributes class, please follow this link

http://msdn.microsoft.com/en-us/library/sx1a4zea(v=vs.80).aspx

Upvotes: 0

Related Questions