简体   繁体   中英

XmlSerializer - Serialize list elements without parent element

I know that his question has already been asked and answered also, but I have kind of a different situation on which that solution isn't working. I've got an web method response xsd which I need to serialize/deserialize. Below is the snippet from that xsd which is problematic.

<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>

I've defined this choice element as shown below:

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

The problem is when I need to serialize list of Type1 elements. I get this:

<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>

when I, according to the xsd, need to get this:

<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>

So my question is, how can I get rid of that parent element "Type1" that is encapsulating all the Type1 list elements?

Thank you!

In order to generate the XML you desire, you may need to change your data model somewhat.

XmlSerializer supports either a single polymorphic element, or a collection of polymorphic elements. In both cases it looks at each element's name to determine the actual type when deserializing. In your case, you want to have a collection of one type or a singleton of a second type. You have implemented this design by specifying that XmlSerializer effectively treat the collection as a singleton of type List<Type1> -- which is going to require an outer container element for the list.

Since you don't want that, you can instead specify that your Type property is a collection of polymorphic elements of each type:

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

If you want to retain your current data model, you can create a proxy property that packages Type into an array, validating that the array contains either a collection of the first type or a singleton of the second:

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

Prototype fiddle .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM