【问题标题】:Deserialize object with XmlAnyElementAttribute not working使用 XmlAnyElementAttribute 反序列化对象不起作用
【发布时间】:2021-01-26 15:15:41
【问题描述】:

从 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中使用的其他类的属性,但在这种情况下有同样的错误。

【问题讨论】:

    标签: c# xml serialization deserialization svcutil.exe


    【解决方案1】:

    您的问题是您设置的 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 填充成功。演示小提琴 #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 对象也必须具有相同的名称和命名空间值。

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

    注意事项:

    • 您可能希望将 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。

    【讨论】:

      猜你喜欢
      • 2012-09-18
      • 2023-04-06
      • 1970-01-01
      • 2014-08-11
      • 1970-01-01
      • 2021-07-08
      • 2023-03-31
      • 1970-01-01
      • 2012-07-11
      相关资源
      最近更新 更多