Картинка блога

Последней моей головной болью был элемент CDATA. По заданию нужно было учесть возможность, что в полях XML может присутствовать HTML разметка. А xml для десериализации портить нельзя, и эскейпинг тоже не подошел бы. Вот и было решено использовать блок CDATA.

Первыми граблями было отсутствие возможности создания CDATA при трансформации XSLT. Где-то читал, что если формат на выходе не XML:

то можно использовать тег … не пробовал.
Хоть w3c предусматривает CDATA для элементов (добавлением аттрибутов cdata-section-elements в xsl:output):

это не работает когда пытаюсь вставить XML элементы.
Решением было сделать еще обработчик, уже с помощью кода:

foreach (XmlNode contentValue in ContentValues)
{
contentValue.InnerXml = doc.CreateCDataSection(contentValue.InnerXml).OuterXml;
}

Все бы хорошо, да вот как известно, System.Collections.Generic.Dictionary не сериализируется, по этому нужен свой класс сериализации. Его не составило проблемы найти, правда был у него один недостаток, не хотел он десиареализировать класс XmlCDataSection, возвращая null. Сериализация по умолчанию работала, значит необходимо было править код SerializableDictionary. Вот что получилось:

using System.Collections.Generic;
using System.Xml;
using System.Xml.Serialization;

public class SerializableDictionary: Dictionary, 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;
if (typeof(TValue) == typeof(XmlCDataSection))
{
var o = reader.Value;
value = (TValue) (object)(new XmlDocument().CreateCDataSection(o));
reader.Read();
} else
{
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 = (typeof(TKey));
XmlSerializer valueSerializer = (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();
}

}
}

Теперь на выходе можно было получать html, который не был эскейпан и игнорировался обычными XML парсерами.
А достать содержимое можно так: Content.First().Value.Value;

Метки:,

Похожие статьи

Один комментарий в “Сериализация Словаря (Dictionary) и XML CDATA.”

  1. Спасибо за статью. Исправьте, пожалуйста, кавычки на корректные с точки зрения синтаксиса 🙂
    И
    XmlSerializer keySerializer = (typeof(TKey));
    XmlSerializer valueSerializer = (typeof(TValue));
    поправить 🙂

    Для полного счастья хотелось бы увидеть небольшой пример использования 🙂