1

I am trying to de-serialize an xml file. Getting structure but no data. Kindly help.

Below are the files/classes, I am using:

1. XML file:

<?xml version="1.0" encoding="utf-8"?>
<Model     
  Content="ByBlock">
  <Units>
    <Unit
      UnitCategory="acceleration"
      Units="m/s2,cm/s2,ft/s2,g0" />   
    <Unit
      UnitCategory="angle"
      Units="radians,degrees,grads" />    
  </Units>
  <Modules>
    <Module
      Module="ControlValve">
      <Parameter
        Name="ValveCharacteristic"
        Type="Int">
        <Enumeration
          Tag="Parabolic"
          Value="4" />
        <Enumeration
          Tag="Hyperbolic"
          Value="5" />
      </Parameter>
      <Parameter
        Name="ValveCvOption"
        Type="Int">
        <Enumeration
          Tag="Set manually"
          Value="0" />
        <Enumeration
          Tag="Set from valve type and size"
          Value="1" />
      </Parameter>     
    </Module>
    <Module
      Module="Drum">
      <Parameter
        Name="VesselOrientation"
        Type="Int">
        <Enumeration
          Tag="Horizontal cylinder"
          Value="0" />
        <Enumeration
          Tag="Vertical cylinder"
          Value="1" />       
      </Parameter>
    </Module>
  </Modules>
  <Blocks>
  <Block
    ID="0"       
    Module="Drum">
    <Parameter
      Name="Diameter"         
      Value="1000.000000"/>
    <Parameter
      Name="Length"         
      Value="4000.000000"/>    
  </Block>
  <Block
    ID="0"        
    Module="ContinuousFlowCompressor">
    <Parameter
      Name="NominalSpeed"         
      Value="8950.000000"/>
    <Parameter
      Name="NominalFlow"         
      Value="2.783039" />   
  </Block>  
</Blocks>
  </Model>

2: Classes:

a. Model class:

[XmlRoot("Model")]
public class Model
{     
    [XmlAttribute(AttributeName = "Content")]
    public string Content { get; set; }

    [XmlArray("Units")]
    [XmlArrayItem("Unit")]
    public List<Unit> Units { get; set; }

    [XmlArray("Modules")]
    [XmlArrayItem("Module")]
    public List<Module> Modules { get; set; }

    [XmlArray("Blocks")]
    [XmlArrayItem("Block")]
    public List<Block> Blocks { get; set; }
}

b. Unit class:

[XmlRoot(ElementName = "Unit")]
public class Unit
{
    [XmlAttribute(AttributeName =  "UnitCategory")]
    public string UnitCategory { get; set; }
    [XmlAttribute(AttributeName =  "Units")]
    public string Units { get; set; }       
}

c. Module class:

[XmlRoot(ElementName = "Module")]
public class Module
{
    [XmlAttribute(AttributeName = "Module")]
    public string Modul { get; set; }

    [XmlArrayItem("Parameter")]
    public List<ModuleParameter> Parameters { get; set; }        
}

d. ModuleParameter class:

[XmlRoot(ElementName = "Parameter")]
public class ModuleParameter
{
    [XmlAttribute(AttributeName =  "Name")]
    public string Name { get; set; }

    [XmlAttribute(AttributeName =  "Type")]

    public string Type { get; set; }
    [XmlArrayItem("Enumeration")]
    public List<Enumeration> Enumerations { get; set; }        
}

e. Enumeration class:

[XmlRoot(ElementName = "Enumeration")]
public class Enumeration
{
    [XmlAttribute(AttributeName = "Tag")]
    public string Tag { get; set; }

    [XmlAttribute(AttributeName =  "Value")]
    public string Value { get; set; }       
}

f. Block class:

[XmlRoot(ElementName = "Block")]
public class Block
{
    [XmlAttribute(AttributeName =  "ID")]
    public string ID { get; set; }       

    [XmlAttribute(AttributeName =  "Module")]
    public string Module { get; set; }

    [XmlArrayItem("Parameter")]
    public List<BlockParameter> Parameters { get; set; }       
}

g. BlockParameter class:

[XmlRoot(ElementName = "Parameter")]
public class BlockParameter
{
    [XmlAttribute(AttributeName =  "Name")]
    public string Name { get; set; }

    [XmlAttribute(AttributeName =  "Value")]
    public string Value { get; set; }        
}

I am using below code to deserialize the xml file:

var serializer = new XmlSerializer(typeof(Model));
using (FileStream fs = File.OpenRead(file))
{
    var xmlClass = (Model)serializer.Deserialize(fs);
}

PS: 1. Please note, I have to use two Parameter classes: One in Module & another in Block class. 2. I have modified my XmlElement to XmlAttribute for suggested properties like Content, UnitCategory, Units etc.

WpfBee
  • 2,837
  • 6
  • 23
  • 29
  • Best way of debugging is to fill classes with sample data and then serialize. Then compare serialized data with xml. The first obvious issue is content is an attribute and not an element. – jdweng May 23 '18 at 06:07
  • Is this xml being serialized or just a sample 1 ? – Lucifer May 23 '18 at 06:11
  • take a look at this https://stackoverflow.com/a/19613934/6947385 – Lucifer May 23 '18 at 06:16
  • Thanks @jdweng, I have corrected that part. But yet to get data in Parameter list. – WpfBee May 23 '18 at 06:34

3 Answers3

2

One correction, an Attribute is not an Element.
You can find the other occurrences

[XmlRoot("Model")]
public class Model
{       
    //[XmlElement(ElementName = "Content")]
    [XmlAttribute(AttributeName = "Content")]
    public string Content { get; set; }

You can also add an empty C# file and select Edit | Paste special | XML as classes. Not the prettiest code but at least it will be valid. Useful for comparison.

bommelding
  • 2,969
  • 9
  • 14
  • @bommlding: Thanks, I have updated the elements by attributes. Now I am getting attribute values in my de-serialized object.. But Parameter class does not get anything yet. – WpfBee May 23 '18 at 06:33
  • Didn't know of *Paste special* Thanks a lot! :-) – xanatos May 23 '18 at 06:36
  • @WpfBee - I'm not sure, but your classes have multiple issues... There should be only one XmlRoot for instance. Use the Paste-special trick to replace your code or to compare with it very thoroughly. – bommelding May 23 '18 at 06:44
  • @bommelding - I think it's correct. I have marked Model class only as root rest as root - element. I have used it earlier too as it was working fine. – WpfBee May 23 '18 at 06:49
1

It should be this:

[XmlRoot("Model")]
public class Model
{
    [XmlAttribute(AttributeName = "Content")]
    public string Content { get; set; }

    [XmlArray("Units")]
    [XmlArrayItem("Unit")]
    public List<Unit> Units { get; set; }

    [XmlArray("Modules")]
    [XmlArrayItem("Module")]
    public List<Module> Modules { get; set; }

    [XmlArray("Blocks")]
    [XmlArrayItem("Block")]
    public List<Block> Blocks { get; set; }
}

[XmlRoot(ElementName = "Unit")]
public class Unit
{
    [XmlAttribute(AttributeName = "UnitCategory")]
    public string UnitCategory { get; set; }

    [XmlAttribute(AttributeName = "Units")]
    public string Units { get; set; }
}


[XmlRoot(ElementName = "Module")]
public class Module
{
    [XmlAttribute(AttributeName = "Module")]
    public string Modul { get; set; }

    [XmlElement("Parameter")]
    public List<ModuleParameter> Parameters { get; set; }
}

[XmlRoot(ElementName = "Parameter")]
public class ModuleParameter
{
    [XmlAttribute(AttributeName = "Name")]
    public string Name { get; set; }

    [XmlAttribute(AttributeName = "Type")]
    public string Type { get; set; }

    [XmlElement("Enumeration")]
    public List<Enumeration> Enumerations { get; set; }
}

[XmlRoot(ElementName = "Enumeration")]
public class Enumeration
{
    [XmlAttribute(AttributeName = "Tag")]
    public string Tag { get; set; }

    [XmlAttribute(AttributeName = "Value")]
    public string Value { get; set; }
}

[XmlRoot(ElementName = "Block")]
public class Block
{
    [XmlAttribute(AttributeName = "ID")]
    public string ID { get; set; }

    [XmlAttribute(AttributeName = "Module")]
    public string Module { get; set; }

    [XmlElement("Parameter")]
    public List<BlockParameter> Parameters { get; set; }
}

[XmlRoot(ElementName = "Parameter")]
public class BlockParameter
{
    [XmlAttribute(AttributeName = "Name")]
    public string Name { get; set; }

    [XmlAttribute(AttributeName = "Value")]
    public string Value { get; set; }
}

Explanation: arrays/Lists without "containers" must be marked as XmlElement. To give an example: <Module> has as a container <Modules>, while <Parameter> doesn't have a container. It is directly added to the parent element.

Note: as noted by @bommelding, you can remove all the [XmlRoot(...)] attributes. They aren't needed. The only one needed would be the one on the Model class, but that class already has the name of the root element.

xanatos
  • 109,618
  • 12
  • 197
  • 280
  • @wpfbee This answer should be accepted ,perfect answer – Lucifer May 23 '18 at 06:51
  • xanatos: Why did you keep all those XmlRoots ? Is there any use to that? – bommelding May 23 '18 at 06:57
  • @bommelding No... But the OP put them in, and so I left them in... Perhaps he has other Xml that are only sub-parts of the main xml. They can all be removed, even the one on `Model`, because the class has the same name as the root element. – xanatos May 23 '18 at 06:57
  • @xanatos - Thanks a lot. This really worked for me. I am getting the items in Parameter list now. – WpfBee May 23 '18 at 07:08
  • @xanatos - Thanks a lot. This really worked for me. I am getting the items in Parameter list now. 2 things: a. Posted XML is the original file :) b. ModuleParameter & BlockParameter classes, both are Parameter class with some common attributes. Should I use a single Parameter class for Module as well as for Block? If I use a single class then ModelParameter class gets additional attributes with null values(that is not required). If I need to use 2 different classes then kindly suggest how to do that? – WpfBee May 23 '18 at 07:14
  • @Lucifer - Kindly wait. I will certainly accept the answer once everything gets perfectly working :) – WpfBee May 23 '18 at 07:16
0

To get the attribute values of the tag change the the "XML Element" to "XML Attribute"

EG:

[XmlElement(ElementName = "UnitCategory")]
public string UnitCategory { get; set; }

to

[XmlAttribute(AttributeName = "UnitCategory")]
public string UnitCategory { get; set; }

Other fields which req. change are tag,name,type etc.

if you are creating the XMl by serializing then read this

Lucifer
  • 1,594
  • 2
  • 18
  • 32
  • Thanks, I have updated the elements by attributes. Now I am getting attribute values in my de-serialized object.. But Parameter class does not get anything yet. – WpfBee May 23 '18 at 06:33