如何XML序列化字典

问题描述 投票:19回答:4

我已经能够以这种方式序列化IEnumerable:

[XmlArray("TRANSACTIONS")]
[XmlArrayItem("TRANSACTION", typeof(Record))]
public IEnumerable<BudgetRecord> Records
{
    get 
    {
        foreach(Record br in _budget)
        {
            yield return br;
        }
    }
}

但是,我意识到现在我需要一个包含集合Dictionary<string, RecordCollection>的字典(RecordCollection实现IEnumerable)。

我怎样才能做到这一点?

c# .net xml-serialization xmlserializer
4个回答
12
投票

看看以下博客文章

这个(不是英文,但代码很有用)


代码示例来自:http://web.archive.org/web/20100703052446/http://blogs.msdn.com/b/psheill/archive/2005/04/09/406823.aspx

using System.Collections.Generic;
using System.Collections;
using System.IO;
using System.Xml.Serialization;
using System.Xml;
using System;
public static void Serialize(TextWriter writer, IDictionary dictionary)
{
    List<Entry> entries = new List<Entry>(dictionary.Count);
    foreach (object key in dictionary.Keys)
    {
        entries.Add(new Entry(key, dictionary[key]));
    }
    XmlSerializer serializer = new XmlSerializer(typeof(List<Entry>));
    serializer.Serialize(writer, entries);
}
public static void Deserialize(TextReader reader, IDictionary dictionary)
{
    dictionary.Clear();
    XmlSerializer serializer = new XmlSerializer(typeof(List<Entry>));
    List<Entry> list = (List<Entry>)serializer.Deserialize(reader);
    foreach (Entry entry in list)
    {
        dictionary[entry.Key] = entry.Value;
    }
}
public class Entry
{
    public object Key;
    public object Value;
    public Entry()
    {
    }

    public Entry(object key, object value)
    {
        Key = key;
        Value = value;
    }
}

当键和值是字符串时,它会生成如下输出。

<?xml version="1.0" encoding="utf-8"?>
<ArrayOfEntry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Entry>
    <Key xsi:type="xsd:string">MyKey</Key>
    <Value xsi:type="xsd:string">MyValue</Value>  
  </Entry>
  <Entry>    
    <Key xsi:type="xsd:string">MyOtherKey</Key>    
    <Value xsi:type="xsd:string">MyOtherValue</Value>  
  </Entry>
</ArrayOfEntry>

9
投票

我已经使用了以下一段时间了。它最初来自here

namespace SerializeDictionary
{
    using System;
    using System.Collections.Generic;
    using System.Runtime.Serialization;
    using System.Xml;
    using System.Xml.Schema;
    using System.Xml.Serialization;

    /// <summary>
    /// Represents an XML serializable collection of keys and values.
    /// </summary>
    /// <typeparam name="TKey">The type of the keys in the dictionary.</typeparam>
    /// <typeparam name="TValue">The type of the values in the dictionary.</typeparam>
    [Serializable]
    [XmlRoot("dictionary")]
    public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable
    {
        /// <summary>
        /// The default XML tag name for an item.
        /// </summary>
        private const string DefaultItemTag = "item";

        /// <summary>
        /// The default XML tag name for a key.
        /// </summary>
        private const string DefaultKeyTag = "key";

        /// <summary>
        /// The default XML tag name for a value.
        /// </summary>
        private const string DefaultValueTag = "value";

        /// <summary>
        /// The XML serializer for the key type.
        /// </summary>
        private static readonly XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));

        /// <summary>
        /// The XML serializer for the value type.
        /// </summary>
        private static readonly XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));

        /// <summary>
        /// Initializes a new instance of the
        /// <see cref="SerializableDictionary&lt;TKey, TValue&gt;"/> class.
        /// </summary>
        public SerializableDictionary()
        {
        }

        /// <summary>
        /// Initializes a new instance of the
        /// <see cref="SerializableDictionary&lt;TKey, TValue&gt;"/> class.
        /// </summary>
        /// <param name="info">A
        /// <see cref="T:System.Runtime.Serialization.SerializationInfo"/> object
        /// containing the information required to serialize the
        /// <see cref="T:System.Collections.Generic.Dictionary`2"/>.
        /// </param>
        /// <param name="context">A
        /// <see cref="T:System.Runtime.Serialization.StreamingContext"/> structure
        /// containing the source and destination of the serialized stream
        /// associated with the
        /// <see cref="T:System.Collections.Generic.Dictionary`2"/>.
        /// </param>
        protected SerializableDictionary(SerializationInfo info, StreamingContext context) : base(info, context)
        {
        }

        /// <summary>
        /// Gets the XML tag name for an item.
        /// </summary>
        protected virtual string ItemTagName
        {
            get
            {
                return DefaultItemTag;
            }
        }

        /// <summary>
        /// Gets the XML tag name for a key.
        /// </summary>
        protected virtual string KeyTagName
        {
            get
            {
                return DefaultKeyTag;
            }
        }

        /// <summary>
        /// Gets the XML tag name for a value.
        /// </summary>
        protected virtual string ValueTagName
        {
            get
            {
                return DefaultValueTag;
            }
        }

        /// <summary>
        /// Gets the XML schema for the XML serialization.
        /// </summary>
        /// <returns>An XML schema for the serialized object.</returns>
        public XmlSchema GetSchema()
        {
            return null;
        }

        /// <summary>
        /// Deserializes the object from XML.
        /// </summary>
        /// <param name="reader">The XML representation of the object.</param>
        public void ReadXml(XmlReader reader)
        {
            var wasEmpty = reader.IsEmptyElement;

            reader.Read();
            if (wasEmpty)
            {
                return;
            }

            try
            {
                while (reader.NodeType != XmlNodeType.EndElement)
                {
                    this.ReadItem(reader);
                    reader.MoveToContent();
                }
            }
            finally
            {
                reader.ReadEndElement();
            }
        }

        /// <summary>
        /// Serializes this instance to XML.
        /// </summary>
        /// <param name="writer">The XML writer to serialize to.</param>
        public void WriteXml(XmlWriter writer)
        {
            foreach (var keyValuePair in this)
            {
                this.WriteItem(writer, keyValuePair);
            }
        }

        /// <summary>
        /// Deserializes the dictionary item.
        /// </summary>
        /// <param name="reader">The XML representation of the object.</param>
        private void ReadItem(XmlReader reader)
        {
            reader.ReadStartElement(this.ItemTagName);
            try
            {
                this.Add(this.ReadKey(reader), this.ReadValue(reader));
            }
            finally
            {
                reader.ReadEndElement();
            }
        }

        /// <summary>
        /// Deserializes the dictionary item's key.
        /// </summary>
        /// <param name="reader">The XML representation of the object.</param>
        /// <returns>The dictionary item's key.</returns>
        private TKey ReadKey(XmlReader reader)
        {
            reader.ReadStartElement(this.KeyTagName);
            try
            {
                return (TKey)keySerializer.Deserialize(reader);
            }
            finally
            {
                reader.ReadEndElement();
            }
        }

        /// <summary>
        /// Deserializes the dictionary item's value.
        /// </summary>
        /// <param name="reader">The XML representation of the object.</param>
        /// <returns>The dictionary item's value.</returns>
        private TValue ReadValue(XmlReader reader)
        {
            reader.ReadStartElement(this.ValueTagName);
            try
            {
                return (TValue)valueSerializer.Deserialize(reader);
            }
            finally
            {
                reader.ReadEndElement();
            }
        }

        /// <summary>
        /// Serializes the dictionary item.
        /// </summary>
        /// <param name="writer">The XML writer to serialize to.</param>
        /// <param name="keyValuePair">The key/value pair.</param>
        private void WriteItem(XmlWriter writer, KeyValuePair<TKey, TValue> keyValuePair)
        {
            writer.WriteStartElement(this.ItemTagName);
            try
            {
                this.WriteKey(writer, keyValuePair.Key);
                this.WriteValue(writer, keyValuePair.Value);
            }
            finally
            {
                writer.WriteEndElement();
            }
        }

        /// <summary>
        /// Serializes the dictionary item's key.
        /// </summary>
        /// <param name="writer">The XML writer to serialize to.</param>
        /// <param name="key">The dictionary item's key.</param>
        private void WriteKey(XmlWriter writer, TKey key)
        {
            writer.WriteStartElement(this.KeyTagName);
            try
            {
                keySerializer.Serialize(writer, key);
            }
            finally
            {
                writer.WriteEndElement();
            }
        }

        /// <summary>
        /// Serializes the dictionary item's value.
        /// </summary>
        /// <param name="writer">The XML writer to serialize to.</param>
        /// <param name="value">The dictionary item's value.</param>
        private void WriteValue(XmlWriter writer, TValue value)
        {
            writer.WriteStartElement(this.ValueTagName);
            try
            {
                valueSerializer.Serialize(writer, value);
            }
            finally
            {
                writer.WriteEndElement();
            }
        }
    }
}

6
投票

请尝试这种替代方法:

void Main()
{
    var source=
        new TestClass() 
        { 
            GroupTestTyped=
                new Dictionary<string, int> { {"A", 23}, {"B", 40} }
        };
    using (var writer = XmlWriter.Create("c:\\test1.xml"))
        (new XmlSerializer(typeof(TestClass))).Serialize(writer, source);
}
[Serializable]
public class DemoElementClass
{
    public string Key { get; set; }
    public int Value { get; set; }  
}
[Serializable]
public class TestClass
{
   public TestClass() { }

   [XmlArray]
   [XmlArrayItem(ElementName = "ElementTest")]
   public List<DemoElementClass> GroupTest { get; set; }

   [XmlIgnore]
   public Dictionary<string, int> GroupTestTyped 
   {
       get { return GroupTest.ToDictionary(x=> x.Key, x => x.Value); }
       set { GroupTest = value.Select(x => new DemoElementClass {Key = x.Key, Value = x.Value}).ToList(); }
   }
}

这里的xml结果:

<?xml version="1.0" encoding="utf-8"?>
<TestClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <GroupTest>
        <ElementTest>
            <Key>A</Key>
            <Value>23</Value>
        </ElementTest>
        <ElementTest>
            <Key>B</Key>
            <Value>40</Value>
        </ElementTest>
    </GroupTest>
</TestClass>

5
投票

这是基于Gildors答案的更短版本:

[XmlElement("Dictionary")]
public List<KeyValuePair<string, string>> XMLDictionaryProxy
{
    get
    {
        return new List<KeyValuePair<string, string>>(this.Dictionary);
    }
    set
    {
        this.Dictionary = new Dictionary<string, string>();
        foreach (var pair in value)
            this.Dictionary[pair.Key] = pair.Value;
    }
}

[XmlIgnore]
public Dictionary<string, string> Dictionary
{
    get; set;
}

请享用。

© www.soinside.com 2019 - 2024. All rights reserved.