XmlSerializer - 序列化没有父元素的列表元素

本文关键字:元素 列表元素 序列化 XmlSerializer | 更新日期: 2023-09-27 18:33:11

我知道他的问题也已经被问过并回答了,但我有一种不同的情况,该解决方案不起作用。我有一个 Web 方法响应 xsd,我需要对其进行序列化/反序列化。下面是该 xsd 中存在问题的片段。

<xs:choice minOccurs="0">
  <xs:element name="Type1" maxOccurs="unbounded">
    <xs:complexType>
      <xs:sequence>
        <xs:element type="xs:string" name="string1"/>
        <xs:element type="xs:string" name="string2"/>
        <xs:element type="xs:boolean" name="boolean1"/>                           
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="Type2">
    <xs:complexType>
      <xs:sequence>
        <xs:element type="xs:float" name="float1"/>
        <xs:element type="xs:float" name="float2"/>
        <xs:element type="xs:float" name="float3"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:choice>

我已经定义了这个选择元素,如下所示:

public class Type1
{
    [XmlElement(IsNullable = true)]
    public string string1 { get; set; }
    [XmlElement(IsNullable = true)]
    public string string2 { get; set; }
    public bool boolean1 { get; set; }
}
public class Type2
{
    public float float1 { get; set; }
    public float float { get; set; }
    public float float3 { get; set; }
}
[XmlElement("Type1", typeof(List<Type1>), IsNullable = true)]
[XmlElement("Type2", typeof(Type2), IsNullable = true)]
public object Type { get; set; }

问题是当我需要序列化 Type1 元素列表时。我明白这个:

<Type1>
  <Type1>
     <string1>6185</string1>
     <string2>VW</string2>
     <boolean1>true</boolean1>
  </Type1>
  <Type1>
     <string1>6186</string1>
     <string2>AUDI</string2>
     <boolean1>true</boolean1>
  </Type1>
  <Type1>
     <string1>6187</string1>
     <string2>OPEL</string2>
     <boolean1>true</boolean1>
  </Type1>
</Type1>

当我根据 XSD 需要得到这个时:

<Type1>
   <string1>6185</string1>
   <string2>VW</string2>
   <boolean1>true</boolean1>
</Type1>
<Type1>
   <string1>6186</string1>
   <string2>AUDI</string2>
   <boolean1>true</boolean1>
</Type1>
<Type1>
   <string1>6187</string1>
   <string2>OPEL</string2>
   <boolean1>true</boolean1>
</Type1>

所以我的问题是,如何摆脱封装所有 Type1 列表元素的父元素"Type1"?

谢谢!

XmlSerializer - 序列化没有父元素的列表元素

为了生成所需的 XML,您可能需要稍微更改数据模型。

XmlSerializer支持单个多态元素或多态元素的集合。 在这两种情况下,它都会查看每个元素的名称,以确定反序列化时的实际类型。 在您的情况下,您希望拥有一种类型的集合或另一种类型的单一实例。 您已经通过指定XmlSerializer有效地将集合视为类型 List<Type1> 的单一实例来实现此设计 - 这将需要列表的外部容器元素。

由于您不希望这样做,因此可以改为指定 Type 属性是每种类型的多态元素的集合:

    [XmlElement("Type1", typeof(Type1), IsNullable = true)]
    [XmlElement("Type2", typeof(Type2), IsNullable = true)]
    public List<object> Type

如果要保留当前数据模型,可以创建一个代理属性,将Type打包到数组中,验证数组是否包含第一种类型的集合或第二种类型的单一实例:

[XmlRoot("Root")]
public class RootObject
{
    [XmlElement("Type1", typeof(Type1), IsNullable = true)]
    [XmlElement("Type2", typeof(Type2), IsNullable = true)]
    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DebuggerBrowsable(DebuggerBrowsableState.Never)]
    public object [] TypeArray
    {
        get
        {
            if (Type == null)
                return null;
            var collection = Type as IEnumerable;
            if (collection != null)
                return collection.Cast<object>().ToArray();
            else
                return new[] { Type };
        }
        set
        {
            if (value == null)
            {
                Type = null;
                return;
            }
            var type1 = value.OfType<Type1>().ToList();
            var type2 = value.Where(t => t == null || t is Type2).Cast<Type2>().ToList();
            if (type2.Count == 1 && type1.Count == 0)
                Type = type2[0];
            else if (type1.Count == value.Length)
                Type = type1;
            else
                throw new InvalidOperationException("invalid value");
        }
    }
    [XmlIgnore]
    public object Type { get; set; }
}

原型小提琴。