Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you deserialize XML with dynamic element names?

My XML looks like follows:

<rates>
    <rate1>1250.00</rate1>
    <rate2>1900.00</rate2>
</rates>

This is in my Serializable class:

[XmlRoot("main")]
public class Main
{
    [XmlArray("rates"), XmlAnyElement]
    public Rates Rates { get; set; }
}

public class Rates : List<Rate> { }

public class Rate
{
    [XmlAnyElement]
    public string Rate;
}

How can I deserialize the XML so that I can access it using:

var rate1 = Main.Rates[0].Rate;
var rate2 = Main.Rates[1].Rate;
like image 296
Pierre Nortje Avatar asked Dec 04 '25 13:12

Pierre Nortje


1 Answers

You can do this by having your Rates collection implement IXmlSerializable:

public class Rates : List<Rate>, IXmlSerializable
{
    public Rates() : base() { }
    public Rates(IEnumerable<Rate> collection) : base(collection) { }

    #region IXmlSerializable Members

    XmlSchema IXmlSerializable.GetSchema()
    {
        return null;
    }

    void IXmlSerializable.ReadXml(XmlReader reader)
    {
        // for the `decodeName` delegate, you could check that the node name matches the pattern "rateN" for some integer N, if you want.
        XmlKeyValueListHelper.ReadXml(reader, this, null, s => new Rate { RateValue = s });
    }

    void IXmlSerializable.WriteXml(XmlWriter writer)
    {
        XmlKeyValueListHelper.WriteXml(writer, this, (i, rate) => "rate" + XmlConvert.ToString(i), r => r.RateValue);
    }

    #endregion
}

public class Rate
{
    public string RateValue;
}

public static class XmlKeyValueListHelper
{
    const string XsiNamespace = @"http://www.w3.org/2001/XMLSchema-instance";
    const string XsiNil = "nil";

    public static void WriteXml<T>(XmlWriter writer, IEnumerable<T> collection, Func<int, T, string> encodeName, Func<T, string> encodeValue)
    {
        int i = 0;
        foreach (var item in collection)
        {
            writer.WriteStartElement(XmlConvert.EncodeLocalName(encodeName(i, item)));
            if (item == null)
            {
                writer.WriteAttributeString(XsiNil, XsiNamespace, XmlConvert.ToString(true));
            }
            else
            {
                writer.WriteValue(encodeValue(item) ?? "");
            }
            writer.WriteEndElement();
            i++;
        }
    }

    public static void ReadXml<T>(XmlReader reader, ICollection<T> collection, Func<int, string, bool> decodeName, Func<string, T> decodeValue)
    {
        if (reader.IsEmptyElement)
        {
            reader.Read();
            return;
        }

        int i = 0;
        reader.ReadStartElement(); // Advance to the first sub element of the list element.
        while (reader.NodeType == XmlNodeType.Element)
        {
            var key = XmlConvert.DecodeName(reader.Name);
            if (decodeName == null || decodeName(i, key))
            {
                var nilValue = reader[XsiNil, XsiNamespace];
                if (!string.IsNullOrEmpty(nilValue) && XmlConvert.ToBoolean(nilValue))
                {
                    collection.Add(default(T));
                    reader.Skip();
                }
                else
                {
                    string value;
                    if (reader.IsEmptyElement)
                    {
                        value = string.Empty;
                        // Move past the end of item element
                        reader.Read();
                    }
                    else
                    {
                        // Read content and move past the end of item element
                        value = reader.ReadElementContentAsString();
                    }
                    collection.Add(decodeValue(value));
                }
            }
            else
            {
                reader.Skip();
            }
            i++;
        }
        // Move past the end of the list element
        reader.ReadEndElement();
    }
}

Example fiddle.

like image 181
dbc Avatar answered Dec 07 '25 04:12

dbc



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!