使用XmlAnyElementAttribute反序列化对象不起作用

问题描述

具有从svcutil生成的具有anyField属性的类:

[System.CodeDom.Compiler.GeneratedCodeAttribute("svcutil","4.6.1055.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "urn:epcglobal:epcis:xsd:1")]
public partial class ErrorDeclarationExtensionType
{

    private System.Xml.XmlElement[] anyField;

    private System.Xml.XmlAttribute[] anyAttrField;

    /// <remarks/>
    [System.Xml.Serialization.XmlAnyElementAttribute(Namespace = "",Order = 0)]
    public System.Xml.XmlElement[] Any
    {
        get
        {
            return this.anyField;
        }
        set
        {
            this.anyField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlAnyAttributeAttribute()]
    public System.Xml.XmlAttribute[] AnyAttr
    {
        get
        {
            return this.anyAttrField;
        }
        set
        {
            this.anyAttrField = value;
        }
    }
}

创建一个简单的程序,将对象序列化为字符串,然后将该字符串反序列化为对象:

static void Main(string[] args)
{
    var example = new ErrorDeclarationExtensionType();
    var doc = new XmlDocument();
    doc.LoadXml("<testXML2 xmlns=\"urn:testXML2\">anyContents0</testXML2>");
    var test = doc.DocumentElement;
    var array = new XmlElement[]
    {
        test
    };
    example.Any = array;

    var sw = new StringWriter();
    XmlTextWriter tw = null;

    var xmlSerializer = new XmlSerializer(example.GetType());
    tw = new XmlTextWriter(sw);
    xmlSerializer.Serialize(tw,example);

    Console.WriteLine(sw.ToString());
    Console.ReadKey();
    ErrorDeclarationExtensionType errorDeclaration;

    var xmlSer = new XmlSerializer(typeof(ErrorDeclarationExtensionType));

    using (TextReader tr = new StringReader(sw.ToString()))
    {
        errorDeclaration = (ErrorDeclarationExtensionType)xmlSer.Deserialize(tr);
    }
    Console.ReadKey();
}

反序列化后,所有字段的get对象均等于null。猜猜这是XmlAnyElementAttribute的问题,但没有得到任何解决方案。实际上,该类是prod中使用的其他类的属性,但是在这种情况下有相同的错误

解决方法

您的问题是您设置的XmlAnyElementAttribute.Namespace与XML不一致:

[System.Xml.Serialization.XmlAnyElementAttribute(Namespace = "",Order = 0)]
public System.Xml.XmlElement[] Any 
{
    get
    {
        return this.anyField;
    }
    set
    {
        this.anyField = value;
    }
}

通过设置此属性,您表示只有命名空间中不存在的未知元素可以绑定到Any属性。但是,示例XML中的unknown元素位于其他命名空间中,尤其是"urn:testXML2"。如果我将示例XML更改为不包含名称空间,例如

<ErrorDeclarationExtensionType xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <testXML2>anyContents0</testXML2>
</ErrorDeclarationExtensionType>

然后Any成功填充。演示小提琴#1 here

类似地,如果我将元数据属性中的命名空间更改为"urn:testXML2",则将填充Any

[System.Xml.Serialization.XmlAnyElementAttribute(Namespace = "urn:testXML2",Order = 0)]
public System.Xml.XmlElement[] Any

演示小提琴#2 here

如果我删除了XmlAnyElementAttribute.Namespace,那么任何一个都可以成功绑定:

[System.Xml.Serialization.XmlAnyElementAttribute(Order = 0)]
public System.Xml.XmlElement[] Any
{
    get
    {
        return this.anyField;
    }
    set
    {
        this.anyField = value;
    }
}

演示小提琴#3 here

documentation remarks for XmlAnyElementAttribute中对此的解释有些不正确:

序列化时...如果设置Namespace属性值,则还必须设置Name属性,并且XmlElement或XmlNode对象也必须具有相同的名称和命名空间值。

实际上,设置Namespace不使用Name似乎并不会在序列化和反序列化期间导致.NET Core 3.1.5中的错误,并绑定到具有该特定名称空间的所有未知元素。 / p>

注意:

  • 您可能希望将XmlTextWriter的使用替换为XmlWriter,因为从.Net 2.0开始不赞成使用前者:

    var sw = new StringWriter();
    using (var tw = XmlWriter.Create(sw,new XmlWriterSettings { Indent = true /* or false if you prefer*/ }))
    {
        xmlSerializer.Serialize(tw,example);
    }
    
  • 您已设置XmlAnyElementAttribute.Order = 0

    获取或设置元素序列化或反序列化的显式顺序。

    Order属性用于一种类型的一个公共属性或字段之后,必须将其应用于该类型的所有公共属性和字段以及所有继承的类型。

    因此,要成功反序列化任何已知元素,您的未知元素将需要出现-尽管在这种情况下,您的类没有其他元素,并且不需要设置Order