Expanding upon my earlier problem, I've decided to (de)serialize my config file class which worked great.
I now want to store an associative array of drive letters to map (key is the drive letter, value is the network path) and have tried using Dictionary
, HybridDictionary
, and Hashtable
for this but I always get the following error when calling ConfigFile.Load()
or ConfigFile.Save()
:
There was an error reflecting type 'App.ConfigFile'. [snip] System.NotSupportedException: Cannot serialize member App.Configfile.mappedDrives [snip]
From what I've read Dictionaries and HashTables can be serialized, so what am I doing wrong?
[XmlRoot(ElementName="Config")]
public class ConfigFile
{
public String guiPath { get; set; }
public string configPath { get; set; }
public Dictionary<string, string> mappedDrives = new Dictionary<string, string>();
public Boolean Save(String filename)
{
using(var filestream = File.Open(filename, FileMode.OpenOrCreate,FileAccess.ReadWrite))
{
try
{
var serializer = new XmlSerializer(typeof(ConfigFile));
serializer.Serialize(filestream, this);
return true;
} catch(Exception e) {
MessageBox.Show(e.Message);
return false;
}
}
}
public void addDrive(string drvLetter, string path)
{
this.mappedDrives.Add(drvLetter, path);
}
public static ConfigFile Load(string filename)
{
using (var filestream = File.Open(filename, FileMode.Open, FileAccess.Read))
{
try
{
var serializer = new XmlSerializer(typeof(ConfigFile));
return (ConfigFile)serializer.Deserialize(filestream);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + ex.ToString());
return new ConfigFile();
}
}
}
}
This question is related to
c#
.net
serialization
dictionary
Instead of using XmlSerializer
you can use a System.Runtime.Serialization.DataContractSerializer
. This can serialize dictionaries and interfaces no sweat.
Here is a link to a full example, http://theburningmonk.com/2010/05/net-tips-xml-serialize-or-deserialize-dictionary-in-csharp/
the Dictionary class implements ISerializable. The definition of Class Dictionary given below.
[DebuggerTypeProxy(typeof(Mscorlib_DictionaryDebugView<,>))]
[DebuggerDisplay("Count = {Count}")]
[Serializable]
[System.Runtime.InteropServices.ComVisible(false)]
public class Dictionary<TKey,TValue>: IDictionary<TKey,TValue>, IDictionary, IReadOnlyDictionary<TKey, TValue>, ISerializable, IDeserializationCallback
I don't think that is the problem. refer to the below link, which says that if you are having any other data type which is not serializable then Dictionary will not be serialized. http://forums.asp.net/t/1734187.aspx?Is+Dictionary+serializable+
Dictionaries and Hashtables are not serializable with XmlSerializer
. Therefore you cannot use them directly. A workaround would be to use the XmlIgnore
attribute to hide those properties from the serializer and expose them via a list of serializable key-value pairs.
PS: constructing an XmlSerializer
is very expensive, so always cache it if there is a chance of being able to re-use it.
There is a solution at Paul Welter's Weblog - XML Serializable Generic Dictionary
For some reason, the generic Dictionary in .net 2.0 is not XML serializable. The following code snippet is a xml serializable generic dictionary. The dictionary is serialzable by implementing the IXmlSerializable interface.
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
[XmlRoot("dictionary")]
public class SerializableDictionary<TKey, TValue>
: Dictionary<TKey, TValue>, IXmlSerializable
{
public SerializableDictionary() { }
public SerializableDictionary(IDictionary<TKey, TValue> dictionary) : base(dictionary) { }
public SerializableDictionary(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer) : base(dictionary, comparer) { }
public SerializableDictionary(IEqualityComparer<TKey> comparer) : base(comparer) { }
public SerializableDictionary(int capacity) : base(capacity) { }
public SerializableDictionary(int capacity, IEqualityComparer<TKey> comparer) : base(capacity, comparer) { }
#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
}
I wanted a SerializableDictionary class that used xml attributes for key/value so I've adapted Paul Welter's class.
This produces xml like:
<Dictionary>
<Item Key="Grass" Value="Green" />
<Item Key="Snow" Value="White" />
<Item Key="Sky" Value="Blue" />
</Dictionary>"
Code:
using System.Collections.Generic;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;
namespace DataTypes {
[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(XmlReader reader) {
XDocument doc = null;
using (XmlReader subtreeReader = reader.ReadSubtree()) {
doc = XDocument.Load(subtreeReader);
}
XmlSerializer serializer = new XmlSerializer(typeof(SerializableKeyValuePair<TKey, TValue>));
foreach (XElement item in doc.Descendants(XName.Get("Item"))) {
using(XmlReader itemReader = item.CreateReader()) {
var kvp = serializer.Deserialize(itemReader) as SerializableKeyValuePair<TKey, TValue>;
this.Add(kvp.Key, kvp.Value);
}
}
reader.ReadEndElement();
}
public void WriteXml(System.Xml.XmlWriter writer) {
XmlSerializer serializer = new XmlSerializer(typeof(SerializableKeyValuePair<TKey, TValue>));
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "");
foreach (TKey key in this.Keys) {
TValue value = this[key];
var kvp = new SerializableKeyValuePair<TKey, TValue>(key, value);
serializer.Serialize(writer, kvp, ns);
}
}
#endregion
[XmlRoot("Item")]
public class SerializableKeyValuePair<TKey, TValue> {
[XmlAttribute("Key")]
public TKey Key;
[XmlAttribute("Value")]
public TValue Value;
/// <summary>
/// Default constructor
/// </summary>
public SerializableKeyValuePair() { }
public SerializableKeyValuePair (TKey key, TValue value) {
Key = key;
Value = value;
}
}
}
}
Unit Tests:
using System.IO;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace DataTypes {
[TestClass]
public class SerializableDictionaryTests {
[TestMethod]
public void TestStringStringDict() {
var dict = new SerializableDictionary<string, string>();
dict.Add("Grass", "Green");
dict.Add("Snow", "White");
dict.Add("Sky", "Blue");
dict.Add("Tomato", "Red");
dict.Add("Coal", "Black");
dict.Add("Mud", "Brown");
var serializer = new System.Xml.Serialization.XmlSerializer(dict.GetType());
using (var stream = new MemoryStream()) {
// Load memory stream with this objects xml representation
XmlWriter xmlWriter = null;
try {
xmlWriter = XmlWriter.Create(stream);
serializer.Serialize(xmlWriter, dict);
} finally {
xmlWriter.Close();
}
// Rewind
stream.Seek(0, SeekOrigin.Begin);
XDocument doc = XDocument.Load(stream);
Assert.AreEqual("Dictionary", doc.Root.Name);
Assert.AreEqual(dict.Count, doc.Root.Descendants().Count());
// Rewind
stream.Seek(0, SeekOrigin.Begin);
var outDict = serializer.Deserialize(stream) as SerializableDictionary<string, string>;
Assert.AreEqual(dict["Grass"], outDict["Grass"]);
Assert.AreEqual(dict["Snow"], outDict["Snow"]);
Assert.AreEqual(dict["Sky"], outDict["Sky"]);
}
}
[TestMethod]
public void TestIntIntDict() {
var dict = new SerializableDictionary<int, int>();
dict.Add(4, 7);
dict.Add(5, 9);
dict.Add(7, 8);
var serializer = new System.Xml.Serialization.XmlSerializer(dict.GetType());
using (var stream = new MemoryStream()) {
// Load memory stream with this objects xml representation
XmlWriter xmlWriter = null;
try {
xmlWriter = XmlWriter.Create(stream);
serializer.Serialize(xmlWriter, dict);
} finally {
xmlWriter.Close();
}
// Rewind
stream.Seek(0, SeekOrigin.Begin);
XDocument doc = XDocument.Load(stream);
Assert.AreEqual("Dictionary", doc.Root.Name);
Assert.AreEqual(3, doc.Root.Descendants().Count());
// Rewind
stream.Seek(0, SeekOrigin.Begin);
var outDict = serializer.Deserialize(stream) as SerializableDictionary<int, int>;
Assert.AreEqual(dict[4], outDict[4]);
Assert.AreEqual(dict[5], outDict[5]);
Assert.AreEqual(dict[7], outDict[7]);
}
}
}
}
This article explains exactly how to handle this: How do I... Serialize a hash table in C# when the application requires it?
I hope this is helpful
I wanted a SerializableDictionary class that used xml attributes for key/value so I've adapted Paul Welter's class.
This produces xml like:
<Dictionary>
<Item Key="Grass" Value="Green" />
<Item Key="Snow" Value="White" />
<Item Key="Sky" Value="Blue" />
</Dictionary>"
Code:
using System.Collections.Generic;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;
namespace DataTypes {
[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(XmlReader reader) {
XDocument doc = null;
using (XmlReader subtreeReader = reader.ReadSubtree()) {
doc = XDocument.Load(subtreeReader);
}
XmlSerializer serializer = new XmlSerializer(typeof(SerializableKeyValuePair<TKey, TValue>));
foreach (XElement item in doc.Descendants(XName.Get("Item"))) {
using(XmlReader itemReader = item.CreateReader()) {
var kvp = serializer.Deserialize(itemReader) as SerializableKeyValuePair<TKey, TValue>;
this.Add(kvp.Key, kvp.Value);
}
}
reader.ReadEndElement();
}
public void WriteXml(System.Xml.XmlWriter writer) {
XmlSerializer serializer = new XmlSerializer(typeof(SerializableKeyValuePair<TKey, TValue>));
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "");
foreach (TKey key in this.Keys) {
TValue value = this[key];
var kvp = new SerializableKeyValuePair<TKey, TValue>(key, value);
serializer.Serialize(writer, kvp, ns);
}
}
#endregion
[XmlRoot("Item")]
public class SerializableKeyValuePair<TKey, TValue> {
[XmlAttribute("Key")]
public TKey Key;
[XmlAttribute("Value")]
public TValue Value;
/// <summary>
/// Default constructor
/// </summary>
public SerializableKeyValuePair() { }
public SerializableKeyValuePair (TKey key, TValue value) {
Key = key;
Value = value;
}
}
}
}
Unit Tests:
using System.IO;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace DataTypes {
[TestClass]
public class SerializableDictionaryTests {
[TestMethod]
public void TestStringStringDict() {
var dict = new SerializableDictionary<string, string>();
dict.Add("Grass", "Green");
dict.Add("Snow", "White");
dict.Add("Sky", "Blue");
dict.Add("Tomato", "Red");
dict.Add("Coal", "Black");
dict.Add("Mud", "Brown");
var serializer = new System.Xml.Serialization.XmlSerializer(dict.GetType());
using (var stream = new MemoryStream()) {
// Load memory stream with this objects xml representation
XmlWriter xmlWriter = null;
try {
xmlWriter = XmlWriter.Create(stream);
serializer.Serialize(xmlWriter, dict);
} finally {
xmlWriter.Close();
}
// Rewind
stream.Seek(0, SeekOrigin.Begin);
XDocument doc = XDocument.Load(stream);
Assert.AreEqual("Dictionary", doc.Root.Name);
Assert.AreEqual(dict.Count, doc.Root.Descendants().Count());
// Rewind
stream.Seek(0, SeekOrigin.Begin);
var outDict = serializer.Deserialize(stream) as SerializableDictionary<string, string>;
Assert.AreEqual(dict["Grass"], outDict["Grass"]);
Assert.AreEqual(dict["Snow"], outDict["Snow"]);
Assert.AreEqual(dict["Sky"], outDict["Sky"]);
}
}
[TestMethod]
public void TestIntIntDict() {
var dict = new SerializableDictionary<int, int>();
dict.Add(4, 7);
dict.Add(5, 9);
dict.Add(7, 8);
var serializer = new System.Xml.Serialization.XmlSerializer(dict.GetType());
using (var stream = new MemoryStream()) {
// Load memory stream with this objects xml representation
XmlWriter xmlWriter = null;
try {
xmlWriter = XmlWriter.Create(stream);
serializer.Serialize(xmlWriter, dict);
} finally {
xmlWriter.Close();
}
// Rewind
stream.Seek(0, SeekOrigin.Begin);
XDocument doc = XDocument.Load(stream);
Assert.AreEqual("Dictionary", doc.Root.Name);
Assert.AreEqual(3, doc.Root.Descendants().Count());
// Rewind
stream.Seek(0, SeekOrigin.Begin);
var outDict = serializer.Deserialize(stream) as SerializableDictionary<int, int>;
Assert.AreEqual(dict[4], outDict[4]);
Assert.AreEqual(dict[5], outDict[5]);
Assert.AreEqual(dict[7], outDict[7]);
}
}
}
}
There is a solution at Paul Welter's Weblog - XML Serializable Generic Dictionary
For some reason, the generic Dictionary in .net 2.0 is not XML serializable. The following code snippet is a xml serializable generic dictionary. The dictionary is serialzable by implementing the IXmlSerializable interface.
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
[XmlRoot("dictionary")]
public class SerializableDictionary<TKey, TValue>
: Dictionary<TKey, TValue>, IXmlSerializable
{
public SerializableDictionary() { }
public SerializableDictionary(IDictionary<TKey, TValue> dictionary) : base(dictionary) { }
public SerializableDictionary(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer) : base(dictionary, comparer) { }
public SerializableDictionary(IEqualityComparer<TKey> comparer) : base(comparer) { }
public SerializableDictionary(int capacity) : base(capacity) { }
public SerializableDictionary(int capacity, IEqualityComparer<TKey> comparer) : base(capacity, comparer) { }
#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
}
Dictionaries and Hashtables are not serializable with XmlSerializer
. Therefore you cannot use them directly. A workaround would be to use the XmlIgnore
attribute to hide those properties from the serializer and expose them via a list of serializable key-value pairs.
PS: constructing an XmlSerializer
is very expensive, so always cache it if there is a chance of being able to re-use it.
You can use ExtendedXmlSerializer. If you have a class:
public class ConfigFile
{
public String guiPath { get; set; }
public string configPath { get; set; }
public Dictionary<string, string> mappedDrives {get;set;}
public ConfigFile()
{
mappedDrives = new Dictionary<string, string>();
}
}
and create instance of this class:
ConfigFile config = new ConfigFile();
config.guiPath = "guiPath";
config.configPath = "configPath";
config.mappedDrives.Add("Mouse", "Logitech MX Master");
config.mappedDrives.Add("keyboard", "Microsoft Natural Ergonomic Keyboard 4000");
You can serialize this object using ExtendedXmlSerializer:
ExtendedXmlSerializer serializer = new ExtendedXmlSerializer();
var xml = serializer.Serialize(config);
Output xml will look like:
<?xml version="1.0" encoding="utf-8"?>
<ConfigFile type="Program+ConfigFile">
<guiPath>guiPath</guiPath>
<configPath>configPath</configPath>
<mappedDrives>
<Item>
<Key>Mouse</Key>
<Value>Logitech MX Master</Value>
</Item>
<Item>
<Key>keyboard</Key>
<Value>Microsoft Natural Ergonomic Keyboard 4000</Value>
</Item>
</mappedDrives>
</ConfigFile>
You can install ExtendedXmlSerializer from nuget or run the following command:
Install-Package ExtendedXmlSerializer
Here is online example
This article explains exactly how to handle this: How do I... Serialize a hash table in C# when the application requires it?
I hope this is helpful
Create a serialization surrogate.
Example, you have a class with public property of type Dictionary.
To support Xml serialization of this type, create a generic key-value class:
public class SerializeableKeyValue<T1,T2>
{
public T1 Key { get; set; }
public T2 Value { get; set; }
}
Add an XmlIgnore attribute to your original property:
[XmlIgnore]
public Dictionary<int, string> SearchCategories { get; set; }
Expose a public property of array type, that holds an array of SerializableKeyValue instances, which are used to serialize and deserialize into the SearchCategories property:
public SerializeableKeyValue<int, string>[] SearchCategoriesSerializable
{
get
{
var list = new List<SerializeableKeyValue<int, string>>();
if (SearchCategories != null)
{
list.AddRange(SearchCategories.Keys.Select(key => new SerializeableKeyValue<int, string>() {Key = key, Value = SearchCategories[key]}));
}
return list.ToArray();
}
set
{
SearchCategories = new Dictionary<int, string>();
foreach (var item in value)
{
SearchCategories.Add( item.Key, item.Value );
}
}
}
Dictionaries and Hashtables are not serializable with XmlSerializer
. Therefore you cannot use them directly. A workaround would be to use the XmlIgnore
attribute to hide those properties from the serializer and expose them via a list of serializable key-value pairs.
PS: constructing an XmlSerializer
is very expensive, so always cache it if there is a chance of being able to re-use it.
Instead of using XmlSerializer
you can use a System.Runtime.Serialization.DataContractSerializer
. This can serialize dictionaries and interfaces no sweat.
Here is a link to a full example, http://theburningmonk.com/2010/05/net-tips-xml-serialize-or-deserialize-dictionary-in-csharp/
Dictionaries and Hashtables are not serializable with XmlSerializer
. Therefore you cannot use them directly. A workaround would be to use the XmlIgnore
attribute to hide those properties from the serializer and expose them via a list of serializable key-value pairs.
PS: constructing an XmlSerializer
is very expensive, so always cache it if there is a chance of being able to re-use it.
You should explore Json.Net, quite easy to use and allows Json objects to be deserialized in Dictionary directly.
example:
string json = @"{""key1"":""value1"",""key2"":""value2""}";
Dictionary<string, string> values = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
Console.WriteLine(values.Count);
// 2
Console.WriteLine(values["key1"]);
// value1
Create a serialization surrogate.
Example, you have a class with public property of type Dictionary.
To support Xml serialization of this type, create a generic key-value class:
public class SerializeableKeyValue<T1,T2>
{
public T1 Key { get; set; }
public T2 Value { get; set; }
}
Add an XmlIgnore attribute to your original property:
[XmlIgnore]
public Dictionary<int, string> SearchCategories { get; set; }
Expose a public property of array type, that holds an array of SerializableKeyValue instances, which are used to serialize and deserialize into the SearchCategories property:
public SerializeableKeyValue<int, string>[] SearchCategoriesSerializable
{
get
{
var list = new List<SerializeableKeyValue<int, string>>();
if (SearchCategories != null)
{
list.AddRange(SearchCategories.Keys.Select(key => new SerializeableKeyValue<int, string>() {Key = key, Value = SearchCategories[key]}));
}
return list.ToArray();
}
set
{
SearchCategories = new Dictionary<int, string>();
foreach (var item in value)
{
SearchCategories.Add( item.Key, item.Value );
}
}
}
the Dictionary class implements ISerializable. The definition of Class Dictionary given below.
[DebuggerTypeProxy(typeof(Mscorlib_DictionaryDebugView<,>))]
[DebuggerDisplay("Count = {Count}")]
[Serializable]
[System.Runtime.InteropServices.ComVisible(false)]
public class Dictionary<TKey,TValue>: IDictionary<TKey,TValue>, IDictionary, IReadOnlyDictionary<TKey, TValue>, ISerializable, IDeserializationCallback
I don't think that is the problem. refer to the below link, which says that if you are having any other data type which is not serializable then Dictionary will not be serialized. http://forums.asp.net/t/1734187.aspx?Is+Dictionary+serializable+
You should explore Json.Net, quite easy to use and allows Json objects to be deserialized in Dictionary directly.
example:
string json = @"{""key1"":""value1"",""key2"":""value2""}";
Dictionary<string, string> values = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
Console.WriteLine(values.Count);
// 2
Console.WriteLine(values["key1"]);
// value1
You can use ExtendedXmlSerializer. If you have a class:
public class ConfigFile
{
public String guiPath { get; set; }
public string configPath { get; set; }
public Dictionary<string, string> mappedDrives {get;set;}
public ConfigFile()
{
mappedDrives = new Dictionary<string, string>();
}
}
and create instance of this class:
ConfigFile config = new ConfigFile();
config.guiPath = "guiPath";
config.configPath = "configPath";
config.mappedDrives.Add("Mouse", "Logitech MX Master");
config.mappedDrives.Add("keyboard", "Microsoft Natural Ergonomic Keyboard 4000");
You can serialize this object using ExtendedXmlSerializer:
ExtendedXmlSerializer serializer = new ExtendedXmlSerializer();
var xml = serializer.Serialize(config);
Output xml will look like:
<?xml version="1.0" encoding="utf-8"?>
<ConfigFile type="Program+ConfigFile">
<guiPath>guiPath</guiPath>
<configPath>configPath</configPath>
<mappedDrives>
<Item>
<Key>Mouse</Key>
<Value>Logitech MX Master</Value>
</Item>
<Item>
<Key>keyboard</Key>
<Value>Microsoft Natural Ergonomic Keyboard 4000</Value>
</Item>
</mappedDrives>
</ConfigFile>
You can install ExtendedXmlSerializer from nuget or run the following command:
Install-Package ExtendedXmlSerializer
Here is online example
Source: Stackoverflow.com