默认情况下,如何使XmlSerializer生成属性而不是元素

时间:2011-08-03 20:23:43

标签: c# .net xml-serialization xmlserializer

有没有办法让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 个答案:

答案 0 :(得分:4)

实现此目的的一种方法是在实现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。然后使用提供的XmlWriter对象将这些属性作为属性写入XML输出。

要序列化的类只需继承XmlSerializableEntity即可自动获取此行为:

[Serializable]
public class Foo : XmlSerializableEntity
{
    public int Bar { get; set; }
}

答案 1 :(得分:0)

我认为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>

话虽如此,我想知道元素是否比属性慢,尤其是在线路上发送时。