WpfBee
WpfBee

Reputation: 2927

XML Deserialization giving structure but not data in C#

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.

Upvotes: 1

Views: 492

Answers (3)

xanatos
xanatos

Reputation: 111940

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.

Upvotes: 1

Lucifer
Lucifer

Reputation: 1600

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

Upvotes: 0

bommelding
bommelding

Reputation: 3037

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.

Upvotes: 2

Related Questions