【问题标题】:How do I serialize an object to xml but not have it be the root element of the xml document如何将对象序列化为 xml 但不让它成为 xml 文档的根元素
【发布时间】:2010-05-26 08:43:05
【问题描述】:

我有以下对象:

public class MyClass
{
    public int Id { get; set;}
    public string Name { get; set; }
}

我想将其序列化为以下 xml 字符串:

<MyClass>
    <Id>1</Id>
    <Name>My Name</Name>
</MyClass>

不幸的是,当我使用 XMLSerializer 时,我得到一个看起来像这样的字符串:

<?xml version="1.0" encoding="utf-8"?>
<MyClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xmlns:xsd="http://www.w3.org/2001/XMLSchema">  
    <Id>1</Id>
    <Name>My Name</Name>
</MyClass>

我不希望 MyClass 成为文档的根元素,而是我最终希望将字符串与其他类似的序列化对象添加到更大的 xml 文档中。

即最终我会得到一个如下所示的 xml 字符串:

<Classes>
    <MyClass>
        <Id>1</Id>
        <Name>My Name</Name>
    </MyClass>
    <MyClass>
        <Id>1</Id>
        <Name>My Name</Name>
    </MyClass>
</Classes>"

我的第一个想法是创建一个类如下:

public class Classes
{
    public List<MyClass> MyClasses { get; set; }
}

...但这只是添加了一个名为 MyClasses 的附加节点来包装 MyClass....的列表。

我的直觉是,我以错误的方式处理这个问题,并且我缺乏创建 xml 文件的经验并没有帮助我指出 .NET 框架的某些部分或其他一些简化这一点的库。

【问题讨论】:

    标签: c# xml xml-serialization


    【解决方案1】:

    您需要使用 XmlWriter 对象 - 这使您可以完全控制 XML 的呈现方式。您还需要将 XmlSerializerNamespaces 实例传递给序列化程序以获得所需的内容。

    下面的示例程序完全符合您的要求(注意如何使用 XmlWriterSettings 初始化 XmlWriter,以及如何将 XmlNamespaces 实例传递给序列化程序):

    公共课 MyClass { 公共 int ID { 获取;放; } 公共字符串名称 { 获取;放; } }


    课堂节目 { 静态无效主要(字符串 [] 参数) { var xml = new StringBuilder(); 使用 (var writer = XmlWriter.Create(xml, 新的 XmlWriterSettings { 缩进 = true, ConformanceLevel = ConformanceLevel.Auto, OmitXmlDeclaration = true })) { MyClass myClass = new MyClass { Id = 1, Name = "我的名字" }; var ns = new XmlSerializerNamespaces(); ns.Add("", ""); var xs = new XmlSerializer(typeof(MyClass), ""); xs.Serialize(writer, myClass, ns); } Console.WriteLine(xml.ToString()); // 暂停程序执行以查看结果... Console.WriteLine("回车退出"); Console.ReadLine(); }


    //Result:
    <MyClass>
    <Id>1</Id>
    <Name>My Name</Name>
    </MyClass>
    

    【讨论】:

      【解决方案2】:

      不要使用 XmlSerializer,而是使用 DataContracts。创建一个新类型Classes,它继承List&lt;MyClass&gt;,如:

      [CollectionDataContract(Name = "Classes")]
      public class Classes : List<MyClass>
      {
      }
      
      [DataContract(Name = "MyClass")]
      public class MyClass
      {
          [DataMember(Name="Id")]
          public int Id { get;set; }
      }
      

      现在使用DataContractSerializer 序列化您的Classes 实例:

      Classes myItems = new Classes();
      myItems.Add( ... );
      
      DataContractSerializer serializer = new DataContractSerializer(typeof(Classes));
      serializer.WriteObject( /* some stream */, myItems);
      

      回应评论

      使用这样的东西:

      [CollectionDataContract(Name = "MyClasses1")]
      public class MyClassesOne : List<MyClass> { }
      
      [CollectionDataContract(Name = "MyClasses2")]
      public class MyClassesTwo : List<MyClass> { }
      
      [DataContract(Name = "Classes")]
      public class Classes {
          [DataMember] public MyClassesOne MyClasses1 { get; set; }
          [DataMember] public MyClassesTwo MyClasses2 { get; set; }
      }
      

      任何客户都更容易使用它。

      【讨论】:

      • +1 为此,但我会让 Classes 对象从 List 派生,这样他就可以使用混合的类包,而不是将“类”节点限制为 MyClass
      • 当我希望类包含 MyClass 和 MyClass2 的列表时,如何让它工作?我试着让它实现 List 但它抛出了 SerializationException...
      • 不要。而是使用类似:&lt;Classes&gt;&lt;MyClasses1&gt;.. list of myclasses1 .. &lt;/MyClasses1&gt;&lt;MyClasses2&gt; .. list of myclasses2 .. &lt;/MyClasses2&gt;&lt;/Classes&gt;.
      【解决方案3】:

      元素成为根节点应该不是问题。您可以稍后将它(它将是 XmlDocument 的 DocumentElement)导入另一个 XmlDocument。

      【讨论】:

        【解决方案4】:

        您可以查看XStream for .NET。这个tutorial 向您展示了如何实现您想要的。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-09-23
          • 1970-01-01
          • 2015-04-25
          • 2011-12-03
          • 2019-03-04
          • 1970-01-01
          相关资源
          最近更新 更多