Home > Software design >  Serializing ArrayList outputs ArrayOfAnyType
Serializing ArrayList outputs ArrayOfAnyType

Time:02-03

I do have a problem with serializing a ArrayList. Most propably I use wrong XML Attributes for it since I when I changed them it would not even serialize it and got errors like 'The type may not be used in this context.'

I need to use a non generic ArrayList. On adding [XmlArray("LineDetails")] made this code to run but the output is not correct, it should give me the LineDetails structure. Any idea how to fix this?

This is a part of a whole xml like Document > Header > LineCollection > LineDeatails. The problem is only with this details if I use a standard string field it is ok but the range of the colletion if changing with every document.

[XmlType(TypeName = "LineCollection")]
public class LineCollection
{
    public String LineCount{ get; set; }          
  //  [XmlElement(ElementName = "LineDetails")]
    [XmlArray("LineDetails")]
    public ArrayList LineDetails{ get; set; } 
}
public class LineDetails: ArrayList 
{
    public String LineNum{ get; set; } 
    public String ItemId{ get; set; } 
    public String ItemName{ get; set; } 
    //... only strings
}

public class Utf8StringWriter : StringWriter
{
    public override Encoding Encoding => new UTF8Encoding(false);
}

public string Serialize()
{
    // var xmlserializer = new XmlSerializer(this.GetType());
    var xmlserializer = new XmlSerializer(this.GetType(), new Type[] { typeof(LineDetails) });
    var Utf8StringWriter = new Utf8StringWriter();
    var xns = new XmlSerializerNamespaces();
    xns.Add(string.Empty, string.Empty);
    using (var writer = XmlWriter.Create(Utf8StringWriter))
    {
        xmlserializer.Serialize(writer, this, xns);
        return Utf8StringWriter.ToString();
    }
}

And the incorrect output of this...

<LineColletion>
    <LineDetails>
        <anyType xmlns:p5="http://www.w3.org/2001/XMLSchema-instance" p5:type="ArrayOfAnyType"/>
        <anyType xmlns:p5="http://www.w3.org/2001/XMLSchema-instance" p5:type="ArrayOfAnyType"/>
        <anyType xmlns:p5="http://www.w3.org/2001/XMLSchema-instance" p5:type="ArrayOfAnyType"/>
    </LineDetails>
</LineColletion>

it should be like this

<LineColletion>
    <LineDetails>
        <LineNum>1</LineNum>
        <ItemId>Item_2321</ItemId>
        <ItemName>TheItemName</ItemName>
    </LineDetails>
    <LineDetails>
        <LineNum>2</LineNum>
        <ItemId>Item_232100000</ItemId>
        <ItemName>TheItemName0</ItemName>
    </LineDetails>
    <LineDetails>
        <LineNum>3</LineNum>
        <ItemId>Item_23217777</ItemId>
        <ItemName>TheItemName7</ItemName>
    </LineDetails>
</LineColletion>

Now the wrong xml looks like this...

  <LineDetails>
        <anyType xmlns:p5="http://www.w3.org/2001/XMLSchema-instance" p5:type="LineDetails">
            <LineNum>1</LineNum>
            <ItemId>Item_2321</ItemId>
            <ItemName>TheItemName</ItemName>
        </anyType>
        <anyType xmlns:p5="http://www.w3.org/2001/XMLSchema-instance" p5:type="LineDetails">
            <LineNum>2</LineNum>
            <ItemId>Item_2321</ItemId>
            <ItemName>TheItemName</ItemName>
        </anyType>
    </LineDetails>

CodePudding user response:

You may generate the required XML by modifying your data model as follows:

[XmlType(TypeName = "LineColletion")] // Fixed: TypeName.  But do you want LineColletion (misspelled) or LineCollection (correctly spelled)?  Your XML shows LineColletion but your code used LineCollection.
public class LineCollection 
{
    public String LineCount{ get; set; }          
    [XmlElement("LineDetails", typeof(LineDetails))] // Fixed -- specify type(s) of items in the ArrayList.
    public ArrayList LineDetails{ get; set; } 
}

public class LineDetails // Fixed: removed inheritance from ArrayList.
{
    public String LineNum{ get; set; } 
    public String ItemId{ get; set; } 
    public String ItemName{ get; set; } 
    //... only strings
}

Notes:

  • Your model makes LineDetails inherit from ArrayList. XmlSerializer will never serialize collection properties, it will only serialize collection items. In order to serialize it correctly, I removed the inheritance since you don't seem to be using it anyway.

    If you really need LineDetails to inherit from ArrayList, you will need to implement IXmlSerializable or replace it collection with a DTO.

    Implementing IXmlSerializable is tedious and error-prone. I don't recommend it.

  • Your LineDetails collection is serialized without an outer wrapper element. To make the serializer do this, apply XmlElementAttribute to the property.

  • ArrayList is an untyped collection, so you must inform XmlSerializer of the possible types it might contain. You have two options:

    1. Assigning a specific type to a specific element name by setting XmlElementAttribute.Type (or XmlArrayItemAttribute.Type), OR

    2. Adding xsi:type attributes by informing the serializer of additional included types. You are doing this by passing them into the constructor, which is why you are seeing the p5:type="LineDetails" attribute.

    Since you don't want the attributes, you need to set the element name by setting the type like so:

    [XmlElement("LineDetails", typeof(LineDetails))] 
    
  • The XML element corresponding to your LineCollection is named <LineColletion>. Note that the spelling is inconsistent. You will need to set [XmlType(TypeName = "LineColletion")] to the name you actually want.

Demo fiddle here.

  • Related