1

I have a weird XML setup here: I need to interface with a third-party and their XML layout that they're using is beyond my control - no chance to changing anything...

In the scope of a larger XML, I find myself needing to serialize (and later also deserialize) a list of items (for a mobile device) which are defined as having a Type and a Number property (both strings). So this would be something like:

public class SerialNumber
{
    public string Type { get; set; }
    public string Number { get; set; }
}

And this would normally serialize a List<SerialNumber> SerialNumbers as

<SerialNumbers>
    <SerialNumber>
        <Type>SN</Type>
        <Number>CBS583ABC123</Number>
    </SerialNumber>
    <SerialNumber>
        <Type>IMEI</Type>
        <Number>35-924106-659945-4</Number>
    </SerialNumber>
</SerialNumbers>        

However, in my case, I need to send this XML:

<SerialNumbers>
    <Type>SN</Type>
    <Number>CBS583ABC123</Number>
    <Type>IMEI</Type>
    <Number>35-924106-659945-4</Number>
</SerialNumbers>        

So basically, the list elements need to be omitted - I just need a container <SerialNumbers> and then for each entry in the list, I only need to serialize out the Type and Number subelements.

How can I do this easily in .NET with the XmlSerializer ?

I tried to use

[XmlRoot(ElementName="")]
public class SerialNumber

or

[XmlArray]
[XmlArrayItem(ElementName = "")]
public List<SerialNumber> SerialNumbers { get; set; }

but neither of these worked - I still get my full serialization with the <SerialNumber> elements inside the <SerialNumbers> container...

Is there an easy trick to achieve what I'm looking for? I'd much rather not go low-level and start concetanating together my XML manually....

Thanks!

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
  • There's one solution here: [Xml Sequence deserialization with RestSharp](http://stackoverflow.com/a/32885108/3744182). The question is for restsharp but the answer uses `XmlSerializer`. – dbc Dec 02 '16 at 08:16

2 Answers2

3

You could use custom serialization with IXmlSerializable.

public class SerialNumbers : List<SerialNumber>, IXmlSerializable
{
    public XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(XmlReader reader)
    {
        Clear();
        reader.ReadStartElement();
        while (reader.NodeType != XmlNodeType.EndElement)
        {
            var serialNumber = new SerialNumber
            {
                Type = reader.ReadElementContentAsString("Type", ""),
                Number = reader.ReadElementContentAsString("Number", "")
            };
            Add(serialNumber);
        }
        reader.ReadEndElement();
    }

    public void WriteXml(XmlWriter writer)
    {
        foreach (var serialNumber in this)
        {
            writer.WriteElementString("Type", serialNumber.Type);
            writer.WriteElementString("Number", serialNumber.Number);
        }
    }
}

public class SerialNumber
{
    public string Type { get; set; }
    public string Number { get; set; }
}

Example:

var ser = new XmlSerializer(typeof(SerialNumbers));

var reader = new StringReader(@"
    <SerialNumbers>
        <Type>SN</Type>
        <Number>CBS583ABC123</Number>
        <Type>IMEI</Type>
        <Number>35-924106-659945-4</Number>
    </SerialNumbers>
".Trim());
var result = (SerialNumbers) ser.Deserialize(reader);

var writer = new StringWriter();
ser.Serialize(writer, result);

Result:

<?xml version="1.0" encoding="utf-16"?>
<SerialNumbers>
  <Type>SN</Type>
  <Number>CBS583ABC123</Number>
  <Type>IMEI</Type>
  <Number>35-924106-659945-4</Number>
</SerialNumbers>
Peter Csala
  • 17,736
  • 16
  • 35
  • 75
Markus Jarderot
  • 86,735
  • 21
  • 136
  • 138
0

This might do the trick for you

[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class SerialNumbers
{
    private string[] itemsField;
    private ItemsChoiceType[] itemsElementNameField;
    [System.Xml.Serialization.XmlElementAttribute("Number", typeof(string))]
    [System.Xml.Serialization.XmlElementAttribute("Type", typeof(string))]
    [System.Xml.Serialization.XmlChoiceIdentifierAttribute("ItemsElementName")]
    public string[] Items
    {
        get
        {
            return this.itemsField;
        }
        set
        {
            this.itemsField = value;
        }
    }

    [System.Xml.Serialization.XmlElementAttribute("ItemsElementName")]
    [System.Xml.Serialization.XmlIgnoreAttribute()]
    public ItemsChoiceType[] ItemsElementName
    {
        get
        {
            return this.itemsElementNameField;
        }
        set
        {
            this.itemsElementNameField = value;
        }
    }
}

[System.Xml.Serialization.XmlTypeAttribute(IncludeInSchema = false)]
public enum ItemsChoiceType
{
    Number,
    Type,
}
Mohit S
  • 13,723
  • 6
  • 34
  • 69
  • Sorry, no this doesn't work at all - I keep getting "Reflection errors" when trying to serialize this...... – marc_s Dec 02 '16 at 08:31