如何控制 .NET DataContract 序列化,使其使用 XML 属性而不是元素?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/591907/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 12:13:30  来源:igfitidea点击:

How can you control .NET DataContract serialization so it uses XML attributes instead of elements?

.netserializationxml-serializationdatacontract

提问by Brennan

If I have a class marked as a DataContractand a few properties on it marked with DataMemberattributes I can serialize it out to XML easily, but it would create output like:

如果我有一个标记为 a 的类,DataContract并且它的一些属性标记有DataMember属性,我可以轻松地将它序列化为 XML,但它会创建如下输出:

<Person>
    <Name>John Smith</Name>
    <Email>[email protected]</Email>
    <Phone>123-123-1234</Phone>
</Person>

What I would prefer is attributes, like...

我更喜欢的是属性,比如......

<Person Name="John Smith" Email="[email protected]" Phone="123-123-1234" />

The DataMemberattribute allows me to control the Name and Order but not whether it is serialized as an element or attribute. I have looked around and found DataContractFormatand IXmlSerializablebut I am hoping there is there an easier solution.

DataMember属性允许我控制名称和顺序,但不能控制它是否被序列化为元素或属性。我环顾四周并找到了DataContractFormatIXmlSerializable但我希望有一个更简单的解决方案。

What is the easiest way to do this?

什么是最简单的方法来做到这一点?

采纳答案by Greg Beech

You can't do this with the DataContractSerializer; if you want attributes you need to use the XmlSerializerinstead. With the DataContractSerializerclass a more restrictive subset of the XML specification is permitted which improves performance, and improves the interoperability of published services, but gives you rather less control over the XML format.

你不能用DataContractSerializer; 如果你想要属性,你需要使用XmlSerializer代替。对于DataContractSerializer该类,允许使用更严格的 XML 规范子集,这可以提高性能并改进已发布服务的互操作性,但对 XML 格式的控制却较少。

If you're using WCF services then take a look at XmlSerializerFormatAttributewhich allows you to use the XmlSerializerfor serialization.

如果您使用的是 WCF 服务,请查看XmlSerializerFormatAttribute哪些允许您使用XmlSerializerfor 序列化。

回答by Andras Zoltan

You can do this with the DataContractSerializer - the answer is to take over the Xml serialization yourself by implementing the IXmlSerializable interface. For write-only support - you can leave the implementation of ReadXml empty, and return null for GetSchema, and then write the implementation of WriteXml as follows:

您可以使用 DataContractSerializer 执行此操作 - 答案是通过实现 IXmlSerializable 接口自己接管 Xml 序列化。对于只写支持——您可以将 ReadXml 的实现留空,并为 GetSchema 返回 null,然后编写 WriteXml 的实现如下:

public class MyPerson : IXmlSerializable
{
  public string Name { get; set;}
  public string Email { get; set;}
  public string Phone { get; set;}

  public XmlSchema GetSchema() { return null; }
  public void ReadXml(XmlReader reader) { }
  public void WriteXml(XmlWriter writer)
  { 
    writer.WriteAttributeString("name", Name);
    writer.WriteAttributeString("email", Email);
    writer.WriteAttributeString("phone", Phone);
  } 
}

If you're using the same type for, say, JSON serialization as well, then you are still free to add the DataContract and DataMember attributes - the DataContractSerializer will utilise the IXmlSerializable interface implementation only when writing Xml.

如果您也使用相同的类型进行 JSON 序列化,那么您仍然可以自由添加 DataContract 和 DataMember 属性 - DataContractSerializer 将仅在编写 Xml 时使用 IXmlSerializable 接口实现。

I blogged about this here.

我在这里写了关于这个的博客。

回答by HappyNomad

You could convert back and forth between attributes and elements when serializing/deserializing. The following works for the latter.

序列化/反序列化时,您可以在属性和元素之间来回转换。以下适用于后者。

    private XmlReader AttributesToElements( Stream stream )
    {
            var root = XElement.Load( stream );
            foreach ( var element in root.Descendants() ) {
                    foreach ( var attribute in element.Attributes() )
                            element.Add( new XElement( root.Name.Namespace + attribute.Name.LocalName, (string)attribute ) );
                    element.Attributes().Remove();
            }
            return root.CreateReader();
    }