Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to serialize/deserialize to `Dictionary<int, string>` from custom XML not using XElement?

Tags:

c#

.net

xml

mono

Having empty Dictionary<int, string> how to fill it with keys and values from XML like

<items> <item id='int_goes_here' value='string_goes_here'/> </items> 

and serialize it back into XML not using XElement?

like image 765
myWallJSON Avatar asked Sep 23 '12 16:09

myWallJSON


People also ask

Can we serialize Dictionary C#?

NET objects is made easy by using the various serializer classes that it provides. But serialization of a Dictionary object is not that easy. For this, you have to create a special Dictionary class which is able to serialize itself. The serialization technique might be different in different business cases.

How do you serialize a dictionary in python?

The standard solution for serializing and deserializing a Python dictionary is with the pickle module. The dumps() function serialize a Python object by converting it into a byte stream, and the loads() function do the inverse, i.e., convert the byte stream back into an object.

How do you serialize a dictionary in unity?

A serializable dictionary class for Unity. Unity cannot serialize standard dictionaries. This means that they won't show or be edited in the inspector and they won't be instantiated at startup. A classic workaround is to store the keys and values in separate arrays and construct the dictionary at startup.

What is XML serialization and deserialization?

Serialization is a process by which an object's state is transformed in some serial data format, such as XML or binary format. Deserialization, on the other hand, is used to convert the byte of data, such as XML or binary data, to object type.


2 Answers

With the help of a temporary item class

public class item {     [XmlAttribute]     public int id;     [XmlAttribute]     public string value; } 

Sample Dictionary:

Dictionary<int, string> dict = new Dictionary<int, string>() {     {1,"one"}, {2,"two"} }; 

.

XmlSerializer serializer = new XmlSerializer(typeof(item[]),                                   new XmlRootAttribute() { ElementName = "items" }); 

Serialization

serializer.Serialize(stream,                dict.Select(kv=>new item(){id = kv.Key,value=kv.Value}).ToArray() ); 

Deserialization

var orgDict = ((item[])serializer.Deserialize(stream))                .ToDictionary(i => i.id, i => i.value); 

------------------------------------------------------------------------------

Here is how it can be done using XElement, if you change your mind.

Serialization

XElement xElem = new XElement(                     "items",                     dict.Select(x => new XElement("item",new XAttribute("id", x.Key),new XAttribute("value", x.Value)))                  ); var xml = xElem.ToString(); //xElem.Save(...); 

Deserialization

XElement xElem2 = XElement.Parse(xml); //XElement.Load(...) var newDict = xElem2.Descendants("item")                     .ToDictionary(x => (int)x.Attribute("id"), x => (string)x.Attribute("value")); 
like image 100
L.B Avatar answered Sep 20 '22 02:09

L.B


Paul Welter's ASP.NET blog has a dictionary that is serializeable. But it does not use attributes. I will explain why below the code.

using System; using System.Collections.Generic; using System.Text; using System.Xml.Serialization;  [XmlRoot("dictionary")] public class SerializableDictionary<TKey, TValue>     : Dictionary<TKey, TValue>, IXmlSerializable {     #region IXmlSerializable Members     public System.Xml.Schema.XmlSchema GetSchema()     {         return null;     }      public void ReadXml(System.Xml.XmlReader reader)     {         XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));         XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));          bool wasEmpty = reader.IsEmptyElement;         reader.Read();          if (wasEmpty)             return;          while (reader.NodeType != System.Xml.XmlNodeType.EndElement)         {             reader.ReadStartElement("item");              reader.ReadStartElement("key");             TKey key = (TKey)keySerializer.Deserialize(reader);             reader.ReadEndElement();              reader.ReadStartElement("value");             TValue value = (TValue)valueSerializer.Deserialize(reader);             reader.ReadEndElement();              this.Add(key, value);              reader.ReadEndElement();             reader.MoveToContent();         }         reader.ReadEndElement();     }      public void WriteXml(System.Xml.XmlWriter writer)     {         XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));         XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));          foreach (TKey key in this.Keys)         {             writer.WriteStartElement("item");              writer.WriteStartElement("key");             keySerializer.Serialize(writer, key);             writer.WriteEndElement();              writer.WriteStartElement("value");             TValue value = this[key];             valueSerializer.Serialize(writer, value);             writer.WriteEndElement();              writer.WriteEndElement();         }     }     #endregion } 

First, there is one gotcha with this code. Say you read a dictionary from another source that has this:

<dictionary>   <item>     <key>       <string>key1</string>     </key>     <value>       <string>value1</string>     </value>   </item>   <item>     <key>       <string>key1</string>     </key>     <value>       <string>value2</string>     </value>   </item> </dictionary> 

This will throw a exception on de-seariazation because you can only have one key for a dictionary.


The reason you MUST use a XElement in a seriazed dictionary is dictionary is not defined as Dictionary<String,String>, a dictionary is Dictionary<TKey,TValue>.

To see the problem, ask your self: Lets say we have a TValue that serializes in to something that uses Elements it describes itself as XML (lets say a dictionary of dictionaries Dictionary<int,Dictionary<int,string>> (not that uncommon of a pattern, it's a lookup table)), how would your Attribute only version represent a dictionary entirely inside a attribute?

like image 44
Scott Chamberlain Avatar answered Sep 18 '22 02:09

Scott Chamberlain