反序列化 a:anyType 的列表

Deserializing a List of a:anyType

我有一个由另一个应用程序提供的现有 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 反序列化的 class,目前看起来像这样:

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 列表 - 它始终为空。我尝试通过以下方式用 XmlAttributes 装饰 Group 中的 Elements 属性:

  1. [XmlArrayItem(ElementName = "a")]
  2. [XmlArrayItem(ElementName = "a:anyType")]
  3. [XmlArrayItem(ElementName = "a", Type = typeof(SomeType))]
  4. [XmlArrayItem(ElementName = "a:anyType", Type = typeof(SomeType))]

到目前为止,没有任何效果。

有人知道将 <a:anyType i:type="SomeType"> 项反序列化到 Elements 列表中的正确方法吗?

编辑 从那以后我意识到我遗漏了我的问题是 <Root> 实际上有一个命名空间:<Root xmlns="http://someNameSpace">。参见上文 XML。

考虑到您 xml 在 Root 上添加了名称空间声明

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

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

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

最终的 class 结构如下所示:

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