Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing IXmlSerializable on a collection object

I have an xml file looking somewhat like this:

<xml>
  <A>value</A>
  <B>value</B>
  <listitems>
    <item>
      <C>value</C>
      <D>value</D> 
    </item>
  </listitems>
</xml>

And I have a two objects representing this xml:

class XmlObject
{
  public string A { get; set; }
  public string B { get; set; }
  List<Item> listitems { get; set; }
}

class Item : IXmlSerializable
{
  public string C { get; set; }
  public string D { get; set; }

  //Implemented IXmlSerializeable read/write
  public void ReadXml(System.Xml.XmlReader reader)
  {
    this.C = reader.ReadElementString();
    this.D = reader.ReadElementString();
  }
  public void WriteXml(System.Xml.XmlWriter writer)
  {
    writer.WriteElementString("C", this.C);
    writer.WriteElementString("D", this.D);
  }
}

I use the XmlSerializer to serialize/deserialize the XmlObject to file.

The problem is that when I implemented the custom IXmlSerializable functions on my "sub-object" Item I always only get one item(the first) in my XmlObject.listitems collection when deserializing the file. If I remove the : IXmlSerializable everything works as expected.

What do I do wrong?

Edit: I have have implemented IXmlSerializable.GetSchema and I need to use IXmlSerializable on my "child-object" for doing some custom value transformation.

like image 424
Jesper Palm Avatar asked Oct 27 '22 02:10

Jesper Palm


2 Answers

Modify your code like this:

    public void ReadXml(System.Xml.XmlReader reader)
    {
        reader.Read();
        this.C = reader.ReadElementString();
        this.D = reader.ReadElementString();
        reader.Read();
    }

First you skip the start of the Item node, read the two strings, then read past the end node so the reader is at the correct place. This will read all nodes in the array.

You need to pay attention when modifying xml yourself :)

like image 116
Mikael Svenson Avatar answered Oct 29 '22 13:10

Mikael Svenson


You don't need to use IXmlSerializable. But if you want you should implement GetShema() method. After some modification code that works looks like that:

    [XmlRoot("XmlObject")]
public class XmlObject
{
    [XmlElement("A")]
    public string A { get; set; }
    [XmlElement("B")]
    public string B { get; set; }
    [XmlElement("listitems")]
    public List<Item> listitems { get; set; }
}

public class Item : IXmlSerializable
{
    [XmlElement("C")]
    public string C { get; set; }
    [XmlElement("D")]
    public string D { get; set; }

    #region IXmlSerializable Members

    public System.Xml.Schema.XmlSchema GetSchema()
    {
        throw new NotImplementedException();
    }

    public void ReadXml(System.Xml.XmlReader reader)
    {
        this.C = reader.ReadElementString();
        this.D = reader.ReadElementString();
    }

    public void WriteXml(System.Xml.XmlWriter writer)
    {
        writer.WriteElementString("C", this.C);
        writer.WriteElementString("D", this.D);
    }

    #endregion
}

Results for 2 items in itemlist will look like that:

<?xml version="1.0" encoding="utf-8"?>
<XmlObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <A>value</A>
  <B>value</B>
  <listitems>
    <C>value0</C>
    <D>value0</D>
  </listitems>
  <listitems>
    <C>value1</C>
    <D>value1</D>
  </listitems>
</XmlObject>
like image 22
kyrisu Avatar answered Oct 29 '22 15:10

kyrisu