【问题标题】:Deserialize an XML file to object in C#在 C# 中将 XML 文件反序列化为对象
【发布时间】:2018-12-17 11:06:08
【问题描述】:

我尝试使用 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:”前缀,但仍然出现同样的错误。

【问题讨论】:

  • 命名空间前缀ns0 不在元素名称中。命名空间前缀可以不同。
  • 并且XML中的命名空间(xmlns:ns0)和XmlRoot属性应该是一样的
  • @KlausGütter 那么要改变什么?
  • 正如@Ben 所写:从.cs 中删除ns0,即[XmlRoot(Namespace = "blabla.xsd", ElementName = "transmission", DataType = "string", IsNullable = true)]、[XmlElement("ID")] 等
  • @KlausGütter 我做了.. 但同样的错误呢

标签: c# xml xml-parsing


【解决方案1】:

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

  1. 您已指出DiagnosisErrorResponse 的元素名称应为"ns0:transmission"。命名空间前缀ns0: 应该不包含在内,它只是在XML 文件中查找实际命名空间,由xmlns 属性xmlns:ns0="blabla.xsd" 定义。

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

    <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 的子代,它们是DiagnosisErrorResponse 的子代,transmission 的子代。这需要在您的 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 文件中的 &lt;DiagnosisErrorResponse&gt; 元素而不为根元素创建数据模型,则可以使用 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 中,将其重新序列化为字符串,然后反序列化该字符串。可以使用XmlReader 或StreamReader 一步直接从文件反序列化XML。

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

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

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

【讨论】:

    猜你喜欢
    • 2010-09-18
    • 1970-01-01
    • 2014-11-30
    • 1970-01-01
    • 1970-01-01
    • 2018-07-17
    • 2023-03-29
    • 1970-01-01
    相关资源
    最近更新 更多