Как заставить XmlSerializer генерировать атрибуты вместо элементов по умолчанию - PullRequest
14 голосов
/ 04 августа 2011

Есть ли способ заставить XmlSerializer сериализовать примитивные члены класса (например, строковые свойства) как атрибуты XML, а не как элементы XML, без необходимости писать [XmlAttribute] перед каждым объявлением свойства ? То есть существует ли глобальный переключатель, который указывает XmlSerializer сериализовать все примитивные члены класса как атрибуты XML?

Предположим, что у нас есть следующий класс:

public class Person
{
    public string FirstName
    {
       ...
    }

    public string LastName
    {
       ...
    }
}

Затем XmlSerializer генерирует этот код по умолчанию:

<Person>
    <FirstName>John</FirstName>
    <LastName>Doe</LastName>
</Person>

Однако мне нужен следующий код:

<Person FirstName="John" LastName="Doe"/>

Еще раз: я хочу сделать это без [XmlAttribute] (или без XmlAttributeOverrides, что было бы еще больше работы).

Одним из возможных решений было бы использование универсального шага постобработки, который применяет XSLT-преобразование для преобразования элементов в атрибуты. Но мне интересно, есть ли более простое решение.

Ответы [ 2 ]

4 голосов
/ 04 августа 2011

Один из способов достижения этого - реализовать логику сериализации в базовом классе, который реализует интерфейс IXmlSerializable . Классы, которые должны быть сериализованы в XML, должны затем быть производными от этого базового класса, чтобы получить функциональность.

Вот пример

public class XmlSerializableEntity : IXmlSerializable
{
    public XmlSchema GetSchema()
    {
        // Implementation omitted for clarity
    }

    public void ReadXml(XmlReader reader)
    {
        // Implementation omitted for clarity
    }

    public void WriteXml(XmlWriter writer)
    {
        var properties = from property in this.GetType().GetProperties()
                         where property.PropertyType.IsPrimitive ||
                               property.PropertyType == typeof(string)
                         select property;

        foreach (var property in properties)
        {
            var name = property.Name;
            var value = property.GetValue(this, null).ToString();
            writer.WriteAttributeString(name, value);
        }
    }
}

Здесь мы используем Reflection , чтобы получить список свойств текущего объекта, тип которого является примитивом или String . Затем эти свойства записываются в вывод XML в виде атрибутов с использованием предоставленного объекта XmlWriter .

Классы, которые нужно сериализовать, просто должны были бы наследоваться от XmlSerializableEntity, чтобы автоматически получить такое поведение:

[Serializable]
public class Foo : XmlSerializableEntity
{
    public int Bar { get; set; }
}
0 голосов
/ 10 января 2012

Я думаю, что Xslt - самый стабильный, простой в обслуживании и элегантный способ работы.Он не требует переоснования всего, опирается на уже протестированную сериализацию, допускает использование пользовательских атрибутов xml в классе и может быть выполнен в памяти с помощью скомпилированного преобразования.

Вот некоторый универсальный xslt, который должен это делать:

<?xml version=’1.0′ encoding=’utf-8′?>
<xsl:stylesheet version=’1.0′ xmlns:xsl=’http://www.w3.org/1999/XSL/Transform’ xmlns:msxsl=’urn:schemas-microsoft-com:xslt’ exclude-result-prefixes=’msxsl’>
<xsl:template match=’*'>
<xsl:copy>
<xsl:for-each select=’@*|*[not(* or @*)]‘>
<xsl:attribute name=’{name(.)}’><xsl:value-of select=’.'/>
</xsl:attribute>
</xsl:for-each>
<xsl:apply-templates select=’*[* or @*]|text()’/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

Сказав это, мне интересно, если элементы медленнее, чем атрибуты, особенно при отправке через строку.

...