Question

I am attempting to deserialize a hierarchical xml file with following method

    public static T Deserialize<T>(this string serializedObj) where T : class
    {
        XmlSerializer xs = new XmlSerializer(typeof(T));
        T result;

        using (TextReader reader = new StringReader(serializedObj))
            result = xs.Deserialize(reader) as T;

        return result;
    }

But he keeps falling over the fact that there is a reference to the schema in the xml file and I have no clue what is wrong. I tried to deserialize into an object and even there he keeps on failing.

The function that tries to deserialize the xml is the following

    public static void RecieveAndSaveXml(string fullPath, string basePath, string fileName)
    {
        if (File.Exists(fullPath))
        {
            StreamReader reader = new StreamReader(fullPath);
            string xmlString = reader.ReadToEnd();
            Material material = xmlString.Deserialize<Material>();

            //Conversion to dataobject goes here

            reader.Close();
        }
    }

The class that I am trying to deserialize to

[Serializable]
[XmlRoot("Material")]
public class Material
{
    public Material() { }

    [XmlAttribute("MatNr")]
    public string MatNr { get; set; }
    [XmlAttribute("MatDescrEN")]
    public string MatDescrEN { get; set; }
    [XmlAttribute("MatDescrNL")]
    public string MatDescrNL { get; set; }
    [XmlAttribute("MatDescrFR")]
    public string MatDescrFR { get; set; }
    [XmlAttribute("OldMatNr")]
    public string OldMatNr { get; set; }
    [XmlAttribute("UoM")]
    public string UoM { get; set; }
    [XmlAttribute("MatGroupCode")]
    public string MatGroupCode { get; set; }
    [XmlAttribute("Extract")]
    public decimal Extract { get; set; }
    [XmlArray("AdditionalData"), XmlArrayItem(ElementName = "AddDataRecord", Type = typeof(AddDataRecord))]
    public AddDataRecord[] AdditionalData { get; set; }
    [XmlArray("PlantData"), XmlArrayItem(ElementName = "PlantDataRecord", Type = typeof(PlantDataRecord))]
    public PlantDataRecord[] PlantData { get; set; }
}

[Serializable]
[XmlRoot("AddDataRecord")]
public class AddDataRecord
{
    [XmlAttribute("UoMDenom")]
    public int UoMDenom { get; set; }
    [XmlAttribute("UoMAlt")]
    public string UoMAlt { get; set; }
    [XmlAttribute("UoMNum")]
    public int UoMNum { get; set; }
    [XmlAttribute("UoMBase")]
    public string UoMBase { get; set; }
}

[Serializable]
[XmlRoot("PlantDataRecord")]
public class PlantDataRecord
{
    [XmlAttribute("Plant")]
    public string Plant { get; set; }
    [XmlAttribute("Recipient")]
    public string Recipient { get; set; }
    [XmlAttribute("Status")]
    public string Status { get; set; }
}

}

And the xml

<?xml version="1.0" encoding="UTF-8"?>
<ns0:Materials xmlns:ns0="www.foo.be/foo/">
<Material>
    <MatNr>000000000050165478</MatNr>
    <MatDescrEN>KEG CAP GREEN PR JUP NA 1/2008</MatDescrEN>
    <MatDescrNL></MatDescrNL>
    <MatDescrFR></MatDescrFR>
    <OldMatNr>000000000000216505</OldMatNr>
    <UoM>PCE</UoM>
    <MatGroupCode>020506</MatGroupCode>
    <Extract></Extract>
    <AdditionalData>
        <AddDataRecord>
            <UoMDenom>1</UoMDenom>
            <UoMAlt>PCE</UoMAlt>
            <UoMNum>1</UoMNum>
            <UoMBase>PCE</UoMBase>
        </AddDataRecord>
    </AdditionalData>
    <PlantData>
        <PlantDataRecord>
            <Plant>BE01</Plant>
            <Recipient></Recipient>
            <Status>99</Status>
        </PlantDataRecord>
    </PlantData>
</Material>
</ns0:Materials>

So what I have tried is

  • Putting the nested classes in comment
  • Deserializing to object
  • Changing the list types
  • Changed annotations from XmlAttribute to XmlArray with XmlArrayItem
  • Added XmlRootItems

So I have no idea what to try next so thats why I'm posting here. Thanks in advance

Was it helpful?

Solution

There are a few problems with your classes when compared to the XML file provided:

  • All properties are elements in the sample xml, yet they have XmlAttribute in your C# classes
  • You have a non-nullable decimal value (Extract), for which the corresponding xml element is empty. If this is a valid case, you need to handle this somehow.
  • Your xml indicates a collection of Materials, but you're trying to deserialize it as a single instance of Material.

Updated code:

[Serializable]
[XmlRoot("Material")]
public class Material
{
    public Material() { }

    [XmlElement("MatNr")]
    public string MatNr { get; set; }
    [XmlElement("MatDescrEN")]
    public string MatDescrEN { get; set; }
    [XmlElement("MatDescrNL")]
    public string MatDescrNL { get; set; }
    [XmlElement("MatDescrFR")]
    public string MatDescrFR { get; set; }
    [XmlElement("OldMatNr")]
    public string OldMatNr { get; set; }
    [XmlElement("UoM")]
    public string UoM { get; set; }
    [XmlElement("MatGroupCode")]
    public string MatGroupCode { get; set; }
    [XmlElement("Extract")]
    public String ExtractString { get; set; }
    [XmlIgnore]
    public decimal Extract
    {
        get { return String.IsNullOrWhiteSpace(this.ExtractString) ? 0M : decimal.Parse(this.ExtractString); }
        set { this.ExtractString = this.Extract.ToString(CultureInfo.InvariantCulture); }
    }
    [XmlArray("AdditionalData"), XmlArrayItem(ElementName = "AddDataRecord", Type = typeof(AddDataRecord))]
    public AddDataRecord[] AdditionalData { get; set; }
    [XmlArray("PlantData"), XmlArrayItem(ElementName = "PlantDataRecord", Type = typeof(PlantDataRecord))]
    public PlantDataRecord[] PlantData { get; set; }
}

[Serializable]
[XmlRoot("AddDataRecord")]
public class AddDataRecord
{
    [XmlElement("UoMDenom")]
    public int UoMDenom { get; set; }
    [XmlElement("UoMAlt")]
    public string UoMAlt { get; set; }
    [XmlElement("UoMNum")]
    public int UoMNum { get; set; }
    [XmlElement("UoMBase")]
    public string UoMBase { get; set; }
}

[Serializable]
[XmlRoot("PlantDataRecord")]
public class PlantDataRecord
{
    [XmlElement("Plant")]
    public string Plant { get; set; }
    [XmlElement("Recipient")]
    public string Recipient { get; set; }
    [XmlElement("Status")]
    public string Status { get; set; }
}

[XmlRoot("Materials", Namespace = "www.foo.be/foo/")]
[Serializable]
public class MaterialCollection
{
   [XmlElement("Material", Namespace="")]
   public List<Material> Materials { get; set; }
}

You'd then need to use

MaterialCollection materials = xmlString.Deserialize<MaterialCollection>();

OTHER TIPS

an alternative to writing the class(es) manually would be to generate the class file using the xsd.exe tool.

The latest versions of Visual Studio don't include it anymore however, so you'll have to get it here.

Assuming your xml file is under c:\ and you can call xsd.exe from there, you can generate a materials.cs file in the following manner:

c:\>xsd materials.xml

followed by

c:\>xsd materials.xsd /classes
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top