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

Deserialize object with XmlAnyElementAttribute not working

使用 anyField class 从 svcutil 生成 属性:

[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 对象。猜猜这是 XmlAnyElementAttribute 的问题,但没有得到任何解决方案。实际上这个 class 是 prod 中使用的其他 class 的 属性,但在这种情况下有同样的错误。

您的问题是您设置的 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 中的未知元素位于其他一些命名空间中,特别是 "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填充成功。演示 fiddle #1 here.

同样,如果我将元数据属性中的名称空间更改为 "urn:testXML2",则填充 Any

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

演示 fiddle #2 here.

如果我删除 XmlAnyElementAttribute.Namespace 那么两者都可以成功绑定:

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

演示 fiddle #3 here.

这在 documentation remarks for XmlAnyElementAttribute 中的解释有些不正确:

When serialized... if you set the Namespace property value, you must set the Name property as well, and the XmlElement or XmlNode objects must also have the same name and namespace values.

事实上,设置 Namespace 没有 Name 似乎不会在序列化期间在 .NET Core 3.1.5 中导致错误,并且在反序列化期间,绑定到具有该特定命名空间的所有未知元素.

备注:

  • 您可能想要替换 XmlTextWriter with 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:

    Gets or sets the explicit order in which the elements are serialized or deserialized.

    Once the Order property has been used on one public property or field in a type, it must be applied to all public properties and fields for that type and all inherited types.

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