-1

I tried to Deserialize an XML to an object using C#, but I am getting some errors.

My XML file is:

<?xml version="1.0" encoding="UTF-8"?>
<ns0:transmission xmlns:ns0="blabla.xsd">
<ns0:DiagnosisErrorResponse>
<ns0:ID>7</ns0:ID>
<ns0:ErrorCode>9</ns0:ErrorCode>
<ns0:ErrorDescription>sometext</ns0:ErrorDescription>
<ns0:ErrorDate>11-12-2018</ns0:ErrorDate>
</ns0:DiagnosisErrorResponse>
</ns0:transmission>

I have an entity like this:

[XmlRoot(Namespace = "blabla.xsd", ElementName = "ns0:transmission", DataType = "string", IsNullable = true)]
public class DiagnosisErrorResponse
{
    [XmlElement("ID")]
    public long ID { get; set; }

    [XmlElement("ErrorCode")]
    public int ErrorCode { get; set; }

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

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

and my error is:

<transmission xmlns='blabla.xsd'> was not expected.

My function is this:

private void ReadXmlFileByPath(string filePath)
{
    string xmlText = string.Empty;
    XmlDocument d = new XmlDocument(); 

    using (XmlTextReader tr = new XmlTextReader(filePath))
    {
        tr.Namespaces = true;
        d.Load(tr);
        xmlText = d.InnerXml;
    }

     XmlSerializer xs = new XmlSerializer(typeof(DiagnosisErrorResponse), "");

    using (TextReader reader = new StringReader(xmlText))
    {
        DiagnosisErrorResponse result = (DiagnosisErrorResponse)xs.Deserialize(reader);
    }
}

Update: I removed the 'ns0:' prefix from the XmlElement attribute at entity but I still get the same error.

dbc
  • 104,963
  • 20
  • 228
  • 340

1 Answers1

0

Your problem is that your c# data model does not match your XML. Specifically:

  1. You have indicated that the element name for DiagnosisErrorResponse should be "ns0:transmission". The namespace prefix ns0: should not be included, it is just a lookup in the XML file to find the actual namespace, which is defined by the xmlns attribute xmlns:ns0="blabla.xsd".

  2. The XML has a level of nesting not accounted for in your data model. The XML in your question is not indented; if I indent it, it looks like:

    <ns0:transmission xmlns:ns0="blabla.xsd">
      <ns0:DiagnosisErrorResponse>
        <ns0:ID>7</ns0:ID>
        <ns0:ErrorCode>9</ns0:ErrorCode>
        <ns0:ErrorDescription>sometext</ns0:ErrorDescription>
        <ns0:ErrorDate>11-12-2018</ns0:ErrorDate>
      </ns0:DiagnosisErrorResponse>
    </ns0:transmission>
    

    As can now be seen, ID and so on are not children of transmission, they are children of DiagnosisErrorResponse which is a child of transmission. This needs to be accounted for in your c# classes.

Combining these two issues, your data model should look like:

[XmlRoot(Namespace = "blabla.xsd", ElementName = "transmission", IsNullable = true)]
public class Transmission
{
    [XmlElement("DiagnosisErrorResponse")]
    public DiagnosisErrorResponse DiagnosisErrorResponse { get; set; }
}

[XmlRoot(Namespace = "blabla.xsd", IsNullable = true)]
public class DiagnosisErrorResponse
{
    [XmlElement("ID")]
    public long ID { get; set; }

    [XmlElement("ErrorCode")]
    public int ErrorCode { get; set; }

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

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

And your deserialization code should look like:

private DiagnosisErrorResponse ReadXmlFileByPath(string filePath)
{
    using (var xmlReader = XmlReader.Create(filePath))
    {
        XmlSerializer xs = new XmlSerializer(typeof(Transmission));
        var result = (Transmission)xs.Deserialize(xmlReader);
        return result.DiagnosisErrorResponse;
    }
}   

Demo fiddle #1 here.

Alternatively, if you were trying to deserialize just the <DiagnosisErrorResponse> element inside the XML file without creating a data model for the root element, you could use XmlReader to scan forward in the XML until the appropriate element is found:

private DiagnosisErrorResponse ReadXmlFileByPath(string filePath)
{
    using (var xmlReader = XmlReader.Create(filePath))
    {
        if (!xmlReader.ReadToDescendant("DiagnosisErrorResponse", "blabla.xsd"))
            return null;
        XmlSerializer xs = new XmlSerializer(typeof(DiagnosisErrorResponse));
        var result = (DiagnosisErrorResponse)xs.Deserialize(xmlReader);
        return result;
    }
}       

Demo fiddle #2 here.

Notes:

  • There is no need to load the XML file into an XmlDocument, re-serialize it as a string, then deserialize the string. The XML can be deserialized directly from a file in one step using an XmlReader or StreamReader.

  • XmlTextReader has been deprecated by Microsoft in its documentation. XmlReader.Create() should be used instead.

  • You can avoid modeling errors such as the ones above by using one of the code generation tools mentioned in Generate C# class from XML.

  • The easiest way to diagnose an error in XML deserialization is to serialize an instance of your root type, then compare the resulting XML with the XML to be deserialized. Inconsistencies are typically easily spotted and indicate where you have problems.

dbc
  • 104,963
  • 20
  • 228
  • 340