反序列化:任何类型的列表

时间:2015-02-16 03:06:16

标签: c# xml deserialization

我有一个由另一个应用程序提供的现有XML文件,看起来类似于:

<Root xmlns="http://someNameSpace">
    <DisplayName>RootName</DisplayName>
    <Groups>
        <Group>
            <Elements>
                <a:anyType i:type="SomeType">
                    <DisplayName>ElementName</DisplayName>
                </a>
            </Elements>
        </Group>
    </Groups>
</Root>

我试图编写一个可以用XmlSerializer反序列化的类,目前看起来像这样:

public class Root
{
    public string DisplayName { get; set; }
    public List<Group> Groups { get; set; }
}

public class Group : SomeType
{
    public List<SomeType> Elements { get; set; }
}

public class SomeType
{
    public string DisplayName { get; set; }
}

使用XmlSerializer的简单反序列化代码:

var serializer = new XmlSerializer(typeof (Root));
using (var streamReader = new StreamReader(somePathToXmlFile))
{
    root = (Root) serializer.Deserialize(streamReader);
}

除了Elements列表外,所有内容都是反序列化的,它总是空的。我已尝试通过以下方式在Elements Group XmlAttributes中装饰[XmlArrayItem(ElementName = "a")]属性:

  1. [XmlArrayItem(ElementName = "a:anyType")]
  2. [XmlArrayItem(ElementName = "a", Type = typeof(SomeType))]
  3. [XmlArrayItem(ElementName = "a:anyType", Type = typeof(SomeType))]
  4. <a:anyType i:type="SomeType">
  5. 到目前为止,没有任何效果。

    有没有人知道将Elements项反序列化到<Root>列表的正确方法?

    修改 我已经意识到我遗漏了我的问题,<Root xmlns="http://someNameSpace">实际上有一个命名空间:{{1}}。见上面的XML。

2 个答案:

答案 0 :(得分:1)

考虑在root上添加名称空间声明的xml

<Root xmlns:a="http://custom/a" xmlns:i="http://custom/i">
<DisplayName>RootName</DisplayName>
<Groups>
    <Group>
        <Elements>
          <a:anyType i:type="SomeType">
            <DisplayName>ElementName</DisplayName>
          </a:anyType>           
        </Elements>
    </Group>
</Groups>
</Root>

我已成功使用以下xml属性对其进行反序列化:

public class Group : SomeType
{

    [XmlArrayItem(typeof(SomeType),ElementName = "anyType", Namespace = "http://custom/a")]
    public List<SomeType> Elements { get; set; }
}

public class SomeType
{
    [XmlElement(typeof(string),ElementName="DisplayName",Namespace="")]
    public string DisplayName { get; set; }
}

或者,如果您不能将命名空间声明添加到xml,请使用XmlNamespaceManager

var serializer = new XmlSerializer(typeof(Root));
        var nameTable = new NameTable();
        var namespaceManager = new XmlNamespaceManager(nameTable);
        namespaceManager.AddNamespace("a", "http://custom/a");
        namespaceManager.AddNamespace("i", "http://custom/i");
        var parserContext = new XmlParserContext(null, namespaceManager, null, XmlSpace.None);
        var settings = new XmlReaderSettings()
        {
            ConformanceLevel = ConformanceLevel.Fragment

        };
        using(var fileStream=File.OpenRead(somePathToXmlFile))
        {
            using(var reader=XmlReader.Create(fileStream,settings,parserContext))
            {
                var root = (Root)serializer.Deserialize(reader);
            }
        }

答案 1 :(得分:0)

经过多次尝试让XmlSerializer工作后,我最终更改为DataContractSerializer,用于首先进行序列化。

实施DataContractSerializer后,我必须提供一个界面ISomeType,并将Elements更新为ISomeType而不是SomeType的列表,以匹配<a:anyType i:type="SomeType"> XML元素

最终的类结构如下:

public namespace Project
{
    [DataContract(Namespace = "http://someNameSpace")]
    public class Root
    {
        [DataMember]
        public string DisplayName { get; set; }

        [DataMember]
        public List<Group> Groups { get; set; }
    }

    [DataContract(Namespace = "http://someNameSpace")]
    public class Group : ISomeType
    {
        [DataMember]
        public List<ISomeType> Elements { get; set; }
    }

    [DataContract(Namespace = "http://someNameSpace")]
    public class SomeType : ISomeType
    {
        [DataMember]
        public string DisplayName { get; set; }
    }

    public interface ISomeType
    {
        string DisplayName { get; set; }
    }
}

反序列化代码:

using (var fileStream = new FileStream(somePathToXmlFile, FileMode.Open))
{
    using (var reader = XmlDictionaryReader.CreateTextReader(fileStream, new XmlDictionaryReaderQuotas()))
    {
        var serializer = new DataContractSerializer(typeof (Root));
        var root = (Root) serializer.ReadObject(reader, true);
    }
}