Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Missing child nodes when deserializing XML to object

Tags:

c#

.net

xml

I have requirement to process certain xml, having trouble deserializing a list of objects from it. Following is the xml:

<catalog>
<item>
    <id>18338517</id>
    <note label="Name ">Gear xyz</note>
    <note label="Size ">10</note>       
    <note label="Source">Store xyz</note>
    <relation weight="100">
        <type>External</type>
        <id>123</id>
        <name>Mcday</name>          
    </relation>
    <relation weight="99">
        <type>Internal</type>
        <id>234</id>
        <name>Mcnight</name>
    </relation>
</item>
    <item> ..... </item></catalog>

Following is my class

[XmlRoot("catalog")]
public class Catalog
{
    [XmlArray("item")]
    [XmlArrayItem("item", typeof(Item))]
    public Item[] item{ get; set; }
}

[XmlRoot("item")]
public class Item
{
    [XmlElement("id")]
    public string id { get; set; }

    [XmlArrayItem("note", typeof(Note))]
    public Note[] note { get; set; }

    [XmlArrayItem("relation", typeof(Relation))]
    public Relation[] relation { get; set; }
}

[Serializable]
public class Note
{
    [XmlAttribute("label")]
    public string label { get; set; }

    [XmlText]
    public string Value { get; set; }
}

[Serializable]
public class Relation
{
    [XmlAttribute("weight")]
    public string weight { get; set; }

    [XmlText]
    public string Value { get; set; }

    [XmlElement("id")]
    public string id { get; set; }

    [XmlElement("type")]
    public string type { get; set; }

    [XmlElement("name")]
    public string name { get; set; }
}

And finally, calling to deserialize

Catalog catalog = null;
XmlSerializer mySerializer = new XmlSerializer(typeof(Catalog));
using (TextReader reader = new StreamReader(@"D:\TEMP\deserialize xml\catalog.xml"))
{
    catalog = (Catalog)mySerializer.Deserialize(reader);
}

It doesn't return any errors, just empty item in the catalog object.

like image 650
Cornelis Tjendra Avatar asked Apr 01 '14 09:04

Cornelis Tjendra


2 Answers

To use the XmlArray and XmlArrayItem attributes, like you do here:

[XmlArray("term")]
[XmlArrayItem("term", typeof(Item))]
public Item[] item{ get; set; }

your XML has to actually provide the correct collection element. So your class should look like

[XmlRoot("catalog")]
public class Catalog
{
    [XmlArray("items")] // note that I corrected 'term' to 'items'/'item'
    [XmlArrayItem("item", typeof(Item))]
    public Item[] item{ get; set; }
}

and your XML should look like

<catalog>
  <items>
    <item>
      <id>18338517</id>
       ...

Note the <items> element which corresponds to [XmlArray("items")], and the children elements <item> which corresponds to [XmlArrayItem("item", typeof(Item))].

If you don't want/can't change your XML format, use can simply use the XmlElement attribute instead of the XmlArrayItem attribute. So your final code should look like:

[XmlRoot("catalog")]
public class Catalog
{
     [XmlElement("item")] // no XmlArray/XmlArrayItem, just XmlElement
     public Item[] Items { get; set; }
}

[XmlType("item")]
public class Item
{
    [XmlElement("id")]
    public string id { get; set; }

    [XmlElement("note", typeof(Note))] // no XmlArray/XmlArrayItem, just XmlElement
    public Note[] note { get; set; }

    [XmlElement("relation", typeof(Relation))] // no XmlArray/XmlArrayItem, just XmlElement
    public Relation[] relation { get; set; }
}

[Serializable]
public class Note
{
    [XmlAttribute("label")]
    public string label { get; set; }

    [XmlText]
    public string Value { get; set; }
}

[Serializable]
public class Relation
{
    [XmlAttribute("weight")]
    public string weight { get; set; }

    [XmlText]
    public string Value { get; set; }

    [XmlElement("id")]
    public string id { get; set; }

    [XmlElement("type")]
    public string type { get; set; }

    [XmlElement("name")]
    public string name { get; set; }
}
like image 118
sloth Avatar answered Nov 17 '22 02:11

sloth


Your attributes are wrong:

public class Catalog
{
    [XmlArray("term")]
    [XmlArrayItem("term", typeof(Item))]

Try this instead:

public class Catalog
{
    [XmlArray("items")]
    [XmlArrayItem("item", typeof(Item))]

EDIT: For the further development of your project, you should consider creating an XML schema and generate the code using XSD.exe for example, see this question: deserializing-xml-to-objects-in-c-sharp

EDIT2: Looking into MSDN, the XmlArrayAttribute constructor is defined as:

public XmlArrayAttribute(
    string elementName
)

Where the parameters are documented as:

elementName Type: System.String

The name of the XML element that the XmlSerializer generates.
like image 37
helb Avatar answered Nov 17 '22 02:11

helb