Страницы

Поиск по вопросам

среда, 24 апреля 2019 г.

XML-сериализация по особым правилам

Имеется электронный документооборот. Обмен данными выполняется с помощью XML следующей структуры:

Проблема на лицо - требуется куча классов примерно такой структуры:
[XmlRoot(ElementName="tag1")] public class Tag1 { [XmlAttribute(AttributeName="value")] public int Value { get; set; } }
и потом:
[XmlRoot(ElementName="document")] public class Document { [XmlElement(ElementName="tag1")] public Tag1 Tag1 { get; set; } [XmlElement(ElementName="tag2")] public Tag2 Tag2 { get; set; } [XmlElement(ElementName="tag3")] public Tag3 Tag3 { get; set; } [XmlElement(ElementName="tag4")] public Tag4 Tag4 { get; set; } [XmlElement(ElementName="tag5")] public Tag5 Tag5 { get; set; } [XmlElement(ElementName="tag6")] public Tag6 Tag6 { get; set; } [XmlElement(ElementName="tag7")] public Tag7 Tag7 { get; set; } [XmlElement(ElementName="outerTag1")] public OuterTag1 OuterTag1 { get; set; } [XmlElement(ElementName="outerTag2")] public OuterTag2 OuterTag2 { get; set; } }
Хотелось бы вместо этого написать класс со свойствами простых типов:
[XmlRoot(ElementName="document")] public class Document { [...(ElementName="tag1")] public int Tag1 { get; set; } [...(ElementName="tag2")] public string Tag2 { get; set; } [...(ElementName="tag3")] public DateTime Tag3 { get; set; } [...(ElementName="tag4")] public int Tag4 { get; set; } [...(ElementName="tag5")] public DateTime Tag5 { get; set; } [...(ElementName="tag6")] public string Tag6 { get; set; } [...(ElementName="tag7")] public decimal Tag7 { get; set; } [XmlElement(ElementName="outerTag1")] public OuterTag1 OuterTag1 { get; set; } [XmlElement(ElementName="outerTag2")] public OuterTag2 OuterTag2 { get; set; } }
и не плодить кучу мелких классов типа Tag1, Tag2, ...
Можно ли как-то это сделать? В идеале хотелось бы сделать кастомный атрибут MyXmlElement и использовать его вместо XmlElement, но как научить XmlSerializer понимать его и генерировать соответствующую разметку? Или может есть какой-то другой способ?


Ответ

Отказался от реализации интерфейса IXmlSerializable - решение получалось очень громоздким и не красивым, к тому же нужно учесть много всевозможных нюансов, которые учтены в штатной работе сериализатора.
В итоге написал простой класс:
public class Tag { [XmlAttribute(AttributeName = "value")] public T Value { get; set; }
public override string ToString() => Value.ToString();
public static implicit operator Tag(T value) => new Tag { Value = value }; public static implicit operator T(Tag tag) => tag.Value; }
Это позволило выбросить кучу мелких классов Tag1, Tag2 и т.д. Сам документ принял вид:
[XmlRoot(ElementName="document")] public class Document { [XmlElement(ElementName="tag1")] public Tag Tag1 { get; set; } [XmlElement(ElementName="tag2")] public Tag Tag2 { get; set; } [XmlElement(ElementName="tag3")] public Tag Tag3 { get; set; } [XmlElement(ElementName="tag4")] public Tag Tag4 { get; set; } [XmlElement(ElementName="tag5")] public Tag Tag5 { get; set; } [XmlElement(ElementName="tag6")] public Tag Tag6 { get; set; } [XmlElement(ElementName="tag7")] public Tag Tag7 { get; set; } [XmlElement(ElementName="outerTag1")] public OuterTag1 OuterTag1 { get; set; } [XmlElement(ElementName="outerTag2")] public OuterTag2 OuterTag2 { get; set; } }
Ну и благодаря операторам для неявного приведения типов документ создается так же просто:
var doc = new Document { Tag1 = 1, Tag2 = "text", ... };

Комментариев нет:

Отправить комментарий