Как сериализовать Dictionary<string, object>?

215
07 сентября 2017, 15:36

Имеется многоуровневый словарь Dictionary<string, object>, где значением опять-же может быть многоуровневый словарь Dictionary<string, object>. Каким образом можно преобразовать его в XML?

На просторах интернета был найден класс SerializableDictionary, но он работает только с одноуровневыми словарями:

using System.Collections.Generic;
using System.Xml.Serialization;
public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable {
    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();
        }
    }
}
public static string Serialize(SerializableDictionary<string, object> data) {
    using(StringWriter sw = new StringWriter()) {
        XmlSerializer ser = new XmlSerializer(typeof(SerializableDictionary<string, object>));
        ser.Serialize(sw, data);
        return sw.ToString();
    }
}
Serialize(new SerializableDictionary<string, object>() {
    { "Node 1", "Node 1 value" },
    { "Node 2", true },
    { "Node 3", 5}
});
//<?xml version="1.0" encoding="utf-16"?>
//<dictionary>
//  <item>
//    <key>
//      <string>Node 1</string>
//    </key>
//    <value>
//      <anyType xmlns:q1="http://www.w3.org/2001/XMLSchema" d4p1:type="q1:string" xmlns:d4p1="http://www.w3.org/2001/XMLSchema-instance">Node 1 value</anyType>
//    </value>
//  </item>
//  <item>
//    <key>
//      <string>Node 2</string>
//    </key>
//    <value>
//      <anyType xmlns:q1="http://www.w3.org/2001/XMLSchema" d4p1:type="q1:boolean" xmlns:d4p1="http://www.w3.org/2001/XMLSchema-instance">true</anyType>
//    </value>
//  </item>
//  <item>
//    <key>
//      <string>Node 3</string>
//    </key>
//    <value>
//      <anyType xmlns:q1="http://www.w3.org/2001/XMLSchema" d4p1:type="q1:int" xmlns:d4p1="http://www.w3.org/2001/XMLSchema-instance">5</anyType>
//    </value>
//  </item>
//</dictionary>
Serialize(new SerializableDictionary<string, object>() {
    { "Node 1", "Node 1 value" },
    { "Node 2", true },
    { "Node 3", new int[]{1,2,3}}
});
// System.InvalidOperationException: The type System.Int32[] may not be used in this context.
// System.InvalidOperationException: There was an error generating the XML document.
//                                   method WriteXml valueSerializer.Serialize(writer, value);

В идеале хотелось бы иметь структуру XML, где имя узла соответствует имени элемента. Например:

<?xml version="1.0" encoding="utf-16"?>
<Node1>Node 1 value</Node1>
<Node2>true</Node2>
<Node3>
  <Item>1</Item>
  <Item>2</Item>
  <Item>3</Item>
</Node3>

Поиграться с кодом можно здесь.

READ ALSO
Проблемы с historyAPI

Проблемы с historyAPI

Добрый день! Возникла проблема с historyAPI, а точнее с перехватчиком событийСуть проблемы: если нажимать на область контента ссылки - событие...

362
GSAP drawSVG отсутствует плавность?

GSAP drawSVG отсутствует плавность?

codepen Необходимо, чтобы прямая шла плавно без разрывов

279
Как сделать чтобы меню не закрывалось при изменении высоты?

Как сделать чтобы меню не закрывалось при изменении высоты?

Нашёл адаптивное меню, которое не конфликтует с остальными скриптамиНо возникла проблема

290
Как найти слово из одной буквы в строке?

Как найти слово из одной буквы в строке?

Задача, преобразовать строку в объект вида:

317