如何使 XmlSerializer 默认生成属性而不是元素

发布于 2024-11-27 22:09:58 字数 796 浏览 0 评论 0 原文

有没有办法让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 转换将元素转换为属性。但我想知道是否有更简单的解决方案。

Is there a way to cause XmlSerializer to serialize primitive class members (e.g. string properties) as XML attributes, not as XML elements, without having to write [XmlAttribute] in front of each property declaration?
I.e. is there a global switch that tells XmlSerializer to serialize all primitive class members as XML attributes?

Assume that we have the following class:

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

    public string LastName
    {
       ...
    }
}

Then XmlSerializer generates this code by default:

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

What I want, however, is this code:

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

Again: I want to do that without [XmlAttribute] (or without XmlAttributeOverrides, which would be even more work).

One possible solution would be to use a generic postprocessing step that applies an XSLT transform to convert elements to attributes. But I wonder whether there is a simpler solution.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

岁月如刀 2024-12-04 22:09:58

实现此目的的一种方法是在实现 IXmlSerialized 接口。然后,要序列化为 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);
        }
    }
}

在这里我们使用 反射 从当前对象获取属性列表,其类型为原始类型或 字符串。然后,使用提供的 XmlWriter 将这些属性作为属性写入 XML 输出 对象。

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

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

One way to achieve this is to implement the serialization logic in a base class that implements the IXmlSerializable interface. The classes that are to be serialized to XML, would then have to derive from this base class in order to get the functionality.

Here's an example

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);
        }
    }
}

Here we are using Reflection to get a list of properties from the current object, whose type is a primitive or a String. These properties are then written to the XML output as attributes using the provided XmlWriter object.

The classes to be serialized would simply have to inherit from XmlSerializableEntity to automatically get this behavior:

[Serializable]
public class Foo : XmlSerializableEntity
{
    public int Bar { get; set; }
}
楠木可依 2024-12-04 22:09:58

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

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

I think Xslt is the most stable, easy to maintain and elegant way to go.
It does not require re-basing everything,
relies on already tested serialization,
allows xml custom attributes in the class,
and can be done in memory with a compiled transform.

Here is some generic xslt that ought to do it:

<?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>

Having said that, I wonder if elements are slower than attributes, especially when sent across the line.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文