How to cause XmlSerializer to generate attributes instead of elements by default
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.
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; }
}
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.
精彩评论