Question37255149 IXmlSerializable rate list

CSharp · Console

/Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Serialization;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Schema;
using System.IO;
using System.Diagnostics;


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

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

        [XmlElement("zTestValue")]
        public string ZTestValue { get; set; }
    }

    public class TestClass
    {
        public static void Test()
        {
            Test(new Main { ZTestValue = "test value", Rates = new Rates(new[] { new Rate { RateValue = "101" }, null, new Rate(), new Rate { RateValue = "" }, new Rate { RateValue = "202" }, null }) });
            Test(new Main { ZTestValue = "test value", Rates = new Rates() });
            Test(new Main { ZTestValue = "test value", Rates = new Rates(new [] { new Rate { RateValue = "101" }, new Rate(), new Rate { RateValue = "" }, new Rate { RateValue = "202" } } )});
        }

        static void Test(Main main)
        {
            var xml = main.GetXml();
            ConsoleAndDebug.WriteLine(xml);

            var main2 = xml.LoadFromXML<Main>();

            if (!(main.Rates.Select(r => r == null ? "" : r.RateValue ?? "").SequenceEqual(main2.Rates.Select(r => r == null ? "" : r.RateValue ?? ""))))
            {
                throw new InvalidOperationException("!(main.Rates.Select(r => r.Rate).SequenceEqual(main2.Rates.Select(r => r.Rate)))");
            }
            else
            {
                ConsoleAndDebug.WriteLine("Original and deserialized Main are identical.");
            }

            var xml2 = main2.GetXml();

            if (!XNode.DeepEquals(XElement.Parse(xml), XElement.Parse(xml2)))
            {
                throw new InvalidOperationException("!(main.Rates.Select(r => r.Rate).SequenceEqual(main2.Rates.Select(r => r.Rate)))");
            }
            else
            {
                ConsoleAndDebug.WriteLine("Serialized and re-serialized XML are identical.");
            }
			ConsoleAndDebug.WriteLine("");
        }
    }

	public class Program
	{
		public static void Main()
		{
			TestClass.Test();
		}
	}

    public static class XmlSerializationHelper
    {
        public static T LoadFromXML<T>(this string xmlString)
        {
            using (StringReader reader = new StringReader(xmlString))
            {
                return (T)new XmlSerializer(typeof(T)).Deserialize(reader);
            }
        }

        public static string GetXml<T>(this T obj, bool omitStandardNamespaces = false)
        {
            XmlSerializerNamespaces ns = null;
            if (omitStandardNamespaces)
            {
                ns = new XmlSerializerNamespaces();
                ns.Add("", ""); // Disable the xmlns:xsi and xmlns:xsd lines.
            }			
            using (var textWriter = new StringWriter())
            {
                var settings = new XmlWriterSettings() { Indent = true, IndentChars = "    " }; // For cosmetic purposes.
                using (var xmlWriter = XmlWriter.Create(textWriter, settings))
                    new XmlSerializer(obj.GetType()).Serialize(xmlWriter, obj, ns);
                return textWriter.ToString();
            }
        }
    }

    public static class ConsoleAndDebug
    {
        public static void WriteLine(object s)
        {
            Console.WriteLine(s);
            Debug.WriteLine(s);
        }
    }
;