类中包含数组的XML反序列化

3

我正在尝试反序列化一串XML数据的字符串。但是我在反序列化函数返回的对象中没有得到任何数据。

这里是类的定义:

[XmlType("STATE-COUNTY-RECORDS")]
public class StateCountyRecords
{
    [XmlElement("TOTAL")]
    public int Total { get; set; }

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

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

    [XmlArray("STATE-COUNTY-ARRAY"), XmlArrayItem("STATE-COUNTY")]
    public StateCounty[] StateCountyArray { get; set; }

    public StateCountyRecords() {}

    public StateCountyRecords(int total, int limit, int offset, int[] id, string[] fips_code, string[] state, string[] name)
    {
        Total = total;
        Limit = limit;
        Offset = offset;

        var count = id.Length;
        StateCountyArray = new StateCounty[count];
        for (int i = 0; i < count; i++)
        {
            StateCountyArray[i] = new StateCounty(id[i], fips_code[i], state[i], name[i]);
        }
    }
}

public class StateCounty
{
    [XmlElement("ID")]
    public int Id { get; set; }

    [XmlElement("FIPS-CODE")]
    public string Fips_Code { get; set; }

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

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

    public StateCounty(int id, string fips_code, string state, string name)
    {
        Id = id;
        Fips_Code = fips_code;
        State = state;
        Name = name;
    }

    public StateCounty() { }
}

这里是XML字符串数据:

<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<STATE-COUNTY-FILE xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">
<STATE-COUNTY-RECORDS>
    <TOTAL>3314</TOTAL>
    <LIMIT>10</LIMIT>
    <OFFSET>0</OFFSET>
    <STATE-COUNTY-ARRAY>
    <STATE-COUNTY>
        <ID>1</ID>
        <FIPS-CODE>01000</FIPS-CODE>
        <STATE>AL</STATE>
        <NAME>Alabama</NAME>
    </STATE-COUNTY>
    <STATE-COUNTY>
        <ID>2</ID>
        <FIPS-CODE>01001</FIPS-CODE>
        <STATE>AL</STATE>
        <NAME>Autauga</NAME>
    </STATE-COUNTY>
    <STATE-COUNTY>
        <ID>3</ID>
        <FIPS-CODE>01003</FIPS-CODE>
        <STATE>AL</STATE>
        <NAME>Baldwin</NAME>
    </STATE-COUNTY>
    </STATE-COUNTY-ARRAY>
</STATE-COUNTY-RECORDS>
</STATE-COUNTY-FILE>

这里是反序列化xml字符串的函数:
    public static StateCountyRecords DeserializeStateCountyData(string xmlString)
    {
        XmlSerializer mySerializer = new XmlSerializer(typeof(StateCountyRecords), new XmlRootAttribute("STATE-COUNTY-FILE"));
        using (XmlReader myXmlReader = XmlReader.Create(new StringReader(xmlString)))
        {
            StateCountyRecords rslt;
            rslt = (StateCountyRecords)mySerializer.Deserialize(myXmlReader);
        }
    }
}

我收到的结果中没有包含任何总数、限制和偏移量为0以及StateCountyArray为空的数据。我没有遇到任何错误。我确保XML有效性的方法如下:
if (myXmlReader.CanResolveEntity && myXmlReader.CanReadValueChunk && myXmlReader.CanReadBinaryContent)
                rslt = (StateCountyRecords)mySerializer.Deserialize(myXmlReader);

我想知道我的类定义的XmlElement和XML文件之间是否存在不匹配。


你的问题是什么? - Athena
你的StateCounty类没有XmlType注解。我期望看到类似[XmlType("STATE-COUNTY")]的东西。如果你编写一些序列化代码从你的结构体输出一些样本XML,使用一个填充了所有内容的测试对象,那么通过将其与当前的XML进行比较,你可能会发现这里出了什么问题。 - ManoDestra
1个回答

1
你的问题在于XML中有一个外部元素未在你的数据模型中考虑到,即 <STATE-COUNTY-FILE> 元素:
<STATE-COUNTY-FILE xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <STATE-COUNTY-RECORDS>
    <!-- Various elements under StateCountyRecords -->
  </STATE-COUNTY-RECORDS>
</STATE-COUNTY-FILE>

由于您的数据模型的根是 StateCountyRecords,因此没有与此最外层元素相对应的内容。您尝试通过使用 new XmlRootAttribute("STATE-COUNTY-FILE") 来解决这个问题,但这只会重命名外部元素,而不会添加额外的嵌套级别。
相反,您需要引入一个外部容器 POCO 来实现这个目的:
[XmlType("STATE-COUNTY-FILE")]
public class StateCountyFile
{
    [XmlElement("STATE-COUNTY-RECORDS")]
    public StateCountyRecords StateCountyRecords { get; set; }
}

并按以下方式反序列化:
    public static StateCountyRecords DeserializeStateCountyData(string xmlString)
    {
        var mySerializer = new XmlSerializer(typeof(StateCountyFile));
        using (var myXmlReader = XmlReader.Create(new StringReader(xmlString)))
        {
            var rslt = (StateCountyFile)mySerializer.Deserialize(myXmlReader);
            return rslt.StateCountyRecords;
        }
    }

或者,您可以手动推进 XmlReader 直到遇到名称为 <STATE-COUNTY-RECORDS> 的元素,并对其进行反序列化:

    public static StateCountyRecords DeserializeStateCountyData(string xmlString)
    {
        return XmlTypeExtensions.DeserializeNestedElement<StateCountyRecords>(xmlString);
    }

使用扩展方法:
public static class XmlTypeExtensions
{
    public static T DeserializeNestedElement<T>(string xmlString)
    {
        var mySerializer = new XmlSerializer(typeof(T));
        var typeName = typeof(T).XmlTypeName();
        var typeNamespace = typeof(T).XmlTypeNamespace();

        using (var myXmlReader = XmlReader.Create(new StringReader(xmlString)))
        {
            while (myXmlReader.Read())
                if (myXmlReader.NodeType == XmlNodeType.Element && myXmlReader.Name == typeName && myXmlReader.NamespaceURI == typeNamespace)
                {
                    return (T)mySerializer.Deserialize(myXmlReader);
                }
            return default(T);
        }
    }

    public static string XmlTypeName(this Type type)
    {
        var xmlType = type.GetCustomAttribute<XmlTypeAttribute>();
        if (xmlType != null && !string.IsNullOrEmpty(xmlType.TypeName))
            return xmlType.TypeName;
        return type.Name;
    }

    public static string XmlTypeNamespace(this Type type)
    {
        var xmlType = type.GetCustomAttribute<XmlTypeAttribute>();
        if (xmlType != null && !string.IsNullOrEmpty(xmlType.Namespace))
            return xmlType.Namespace;
        return string.Empty;
    }
}

顺便提一下,像这样的反序列化问题可以通过在内存中创建类的实例、对其进行序列化,然后将生成的 XML 与输入的 XML 进行比较来轻松诊断。通常问题很明显。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接