1

Worked with Json until now. Now I get an XML as data source and I would like to Deserialize it into C# objects using the XML attributes. The problem, as I see it is that I would like to serialize the XML only from MSGData - so I set the DOCUMENT as XmlRootAttribute. Currently there is no error - just getting the properties as null.

This is my XML (I need only the C# minimum needed classes with the right attributes) :

<?xml version="1.0" encoding="IBM862"?>
<DOCUMENT>
 <MSGData>
   <ITEMS>
    <ITEM>
      <ID>121</ID>
      <Name>test</Name>
    </ITEM>
    <ITEM>
     <ID>122</ID>
     <Name>test1</Name>
    </ITEM>
    <ITEM>
     <ID>122</ID>
     <Name>test1</Name>
    </ITEM>
  </ITEMS>
 </MSGData>
</DOCUMENT>

This is how my classes looks like (ignore typos errors - this is not copy+paste code - it is free text):

<Xmlroot(ElementName="ITEM")]
public class Item
{
    [XmlElement(ElementName="ID"])
    public int ID {get; set;}
    [XmlElement(ElementName="Name"])
    public string Name {get; set;}
}

[Xmlroot(ElementName="ITEMS")]
public class Items
{
    [XmlElement(ElementName="ITEM"]) //I think that here I should use XmlArray (see below)
    //[XmlArray("ITEMS"]
    IEnumerable<Item> Items {get; set;}
}

[XmlRoot(ElementName="MSGData")]
public class MSGData
{
    [XmlElement(ElementName="ITEMS")]
    public Items itemsInstance {get; set;}
}

when I read the XML I use the XmlRootAttribute to start gather the data inside the DOCUMENT node:

XmlRootAttribute xRoot = new XmlRootAttribute("DOCUMENT");
XmlSerializer xmls = new XmlSerializer(typeof(MSGData), xRoot);
MSGData messageData = (MSGData)xmls.Deserialize(new     
StringReader(response.Content.ReadAsStringAsync().Result));
Guy E
  • 1,775
  • 2
  • 27
  • 55

1 Answers1

0

I pasted your XML into Xml2Csharp.com because I'm too lazy to figure out how to correctly create the classes. It gave me these classes:

public class ITEM
{
    [XmlElement(ElementName = "ID")]
    public string ID { get; set; }
    [XmlElement(ElementName = "Name")]
    public string Name { get; set; }
}

public class ITEMS
{
    [XmlElement(ElementName = "ITEM")]
    public List<ITEM> ITEM { get; set; }
}

public class MSGData
{
    [XmlElement(ElementName = "ITEMS")]
    public ITEMS ITEMS { get; set; }
}

[XmlRoot(ElementName = "DOCUMENT")]
public class DOCUMENT
{
    [XmlElement(ElementName = "MSGData")]
    public MSGData MSGData { get; set; }
}

Then I put your XML in a file and deserialized to type DOCUMENT.

[TestMethod]
public void Deserialize_MsgData()
{
    using var stream = File.OpenText("xmlfile1.xml");
    var serializer = new XmlSerializer(typeof(DOCUMENT));
    var deserialized = (DOCUMENT) serializer.Deserialize(stream);
    Assert.AreEqual(3, deserialized.MSGData.ITEMS.ITEM.Count);
}

That passes.

You can also tweak the property names, but if I only used this for deserialization I might not bother. I'd also document that I used Xml2Csharp to generate the classes so that if the file changes the next person can also use that tool (unless the change is really simple.)

Given these classes, you should be able to change your deserialization to

XmlSerializer xmls = new XmlSerializer(typeof(DOCUMENT), xRoot);
DOCUMENT document = (DOCUMENT)xmls.Deserialize(new     
StringReader(response.Content.ReadAsStringAsync().Result));
MSGData messageData = DOCUMENT.MSGData'

Maybe it's just me but I almost always use tools like that and I'll go out of my way to avoid manually creating classes to deserialize XML.

Scott Hannen
  • 27,588
  • 3
  • 45
  • 62
  • I would like to "skip" the deserialization of the DOCUMENT element - it gives me nothing - I don't need it as object - I would like to start deserialize one level below – Guy E Apr 04 '21 at 05:06