反序列化XML文件以在C#中进行对象

时间:2018-12-17 11:06:09

标签: c# xml xml-parsing

我尝试使用C#将XML反序列化为对象,但出现一些错误。

我的XML文件是:

<?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>

我有一个这样的实体:

[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; }
}

我的错误是:

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

我的功能是这样:

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);
    }
}

更新:我从实体的XmlElement属性中删除了“ ns0:”前缀,但仍然遇到相同的错误。

1 个答案:

答案 0 :(得分:0)

您的问题是您的c#数据模型与XML不匹配。具体来说:

  1. 您已指出DiagnosisErrorResponse的元素名称应为"ns0:transmission"。应当包括名称空间前缀ns0:,它只是在XML文件中查找以查找实际的名称空间,该名称空间由xmlns属性{{1}定义}。

  2. XML的嵌套级别未在您的数据模型中说明。您问题中的XML没有缩进;如果我缩进,它看起来像:

    xmlns:ns0="blabla.xsd"

    现在可以看到,<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> 等不是ID的子代,它们是transmission的子代,而DiagnosisErrorResponsetransmission的子代。这需要在您的c#类中解决。

结合这两个问题,您的数据模型应类似于:

[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; }
}

您的反序列化代码应类似于:

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;
    }
}   

演示小提琴#1 here

或者,如果您尝试仅反序列化XML文件中的<DiagnosisErrorResponse>元素而不为根元素创建数据模型,则可以使用XmlReader在XML中向前扫描,直到合适为止。找到元素:

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;
    }
}       

演示小提琴#2 here

注意:

  • 无需将XML文件加载到XmlDocument中,将其重新序列化为字符串,然后反序列化该字符串。可以使用XmlReaderStreamReader在一个步骤中直接从文件中反序列化XML。

  • XmlTextReader已被Microsoft在其documentation中弃用。应该使用XmlReader.Create()

  • 您可以使用Generate C# class from XML中提到的一种代码生成工具来避免建模错误,例如上述错误。

  • 诊断XML反序列化中的错误的最简单方法是序列化您根类型的实例,然后将生成的XML与要反序列化的XML进行比较。通常会很容易发现不一致之处,并指出您的问题所在。