XmlSerializer将C#对象转换为xml字符串

XmlSerializer将C#对象转换为xml字符串,c#,xml,linq,C#,Xml,Linq,我创建了一个C#类: 但当我使用XmlSerializer转换为XML字符串时。结果与下面的xml不同 我的C班有什么问题?我想使用XmlSerializer来输出结果,而不是使用 XmlDocument 有什么想法吗?提前谢谢 <books> <bookNum>2</bookNum> <book> <name>Book 1</name> <record>

我创建了一个C#类:


但当我使用XmlSerializer转换为XML字符串时。结果与下面的xml不同

我的C班有什么问题?我想使用XmlSerializer来输出结果,而不是使用 XmlDocument

有什么想法吗?提前谢谢

<books>
    <bookNum>2</bookNum>
    <book>
        <name>Book 1</name>
        <record>
            <borrowDate>2013-7-1</borrowDate>
            <returnDate>2013-7-12</returnDate>
        </record>
        <record>            
            <borrowDate>2013-8-1</borrowDate>
            <returnDate>2013-8-5</returnDate>
        </record>
    </book>
    <book>
        <name>Book 2</name>
        <record>
            <borrowDate>2013-6-1</borrowDate>
            <returnDate>2013-6-12</returnDate>
        </record>
        <record>            
            <borrowDate>2013-7-1</borrowDate>
            <returnDate>2013-7-5</returnDate>
        </record>
    </book>
</books>
XML:


2.
第一册
2013-1-3
2013-1-5
2013-2-3
2013-4-5
第一册
2013-1-3
2013-1-5
2013-2-3
2013-4-5

您不能使用标准序列化工具对问题中的类进行序列化,使其具有与
节点相同级别的
条目

使用标准序列化工具保存类时,
节点的列表将始终嵌套到与
节点处于同一级别的单独数组节点中。同样的关注点
记录
书籍
类上的数组字段

要生成您想要的XML输出(使用与
节点处于同一级别的
节点),您必须在
书籍
类中实现用于自定义序列化的接口。要查看
IXmlSerializable
实现的示例,请访问以下链接:

另一个解决方案是——正如我的回答评论中所述——从
列表
类型继承
书籍
类,并在
书籍
类字段中记录从
列表
类型继承的类类型

从问题中序列化类时,假设您的指定正确,如下所示:

[XmlRoot("books")]
public class books
{
    [XmlElement("bookNum")]
    public int bookNum { get; set; }

    [XmlRoot("book")]
    public class book
    {
        [XmlElement("name")]
        public string name { get; set; }

        [XmlRoot("record")]
        public class record
        {
            [XmlElement("borrowDate")]
            public string borrowDate { get; set; }

            [XmlElement("returnDate")]
            public string returnDate { get; set; }
        }

        [XmlArray("borrowRecords")]
        [XmlArrayItem("record")]
        public record[] records { get; set; }
    }

    [XmlArray("booksList")]
    [XmlArrayItem("book")]
    public book[] books { get; set; }
}
<books>
    <bookNum>2</bookNum>
    <booksList>
        <book>
            <name>Book 1</name>
            <borrowRecords>
                <record>
                    <borrowDate>2013-1-3</borrowDate>
                    <returnDate>2013-1-5</returnDate>
                </record>
                <record>            
                    <borrowDate>2013-2-3</borrowDate>
                    <returnDate>2013-4-5</returnDate>
                </record>
            </borrowRecords>
        </book>
        <book>
            <name>Book 2</name>
            <borrowRecords>
                <record>
                    <borrowDate>2013-1-3</borrowDate>
                    <returnDate>2013-1-5</returnDate>
                </record>
                <record>            
                    <borrowDate>2013-2-3</borrowDate>
                    <returnDate>2013-4-5</returnDate>
                </record>
            </borrowRecords>
        </book>
    </booksList>
</books>
您将获得如下XML输出:

[XmlRoot("books")]
public class books
{
    [XmlElement("bookNum")]
    public int bookNum { get; set; }

    [XmlRoot("book")]
    public class book
    {
        [XmlElement("name")]
        public string name { get; set; }

        [XmlRoot("record")]
        public class record
        {
            [XmlElement("borrowDate")]
            public string borrowDate { get; set; }

            [XmlElement("returnDate")]
            public string returnDate { get; set; }
        }

        [XmlArray("borrowRecords")]
        [XmlArrayItem("record")]
        public record[] records { get; set; }
    }

    [XmlArray("booksList")]
    [XmlArrayItem("book")]
    public book[] books { get; set; }
}
<books>
    <bookNum>2</bookNum>
    <booksList>
        <book>
            <name>Book 1</name>
            <borrowRecords>
                <record>
                    <borrowDate>2013-1-3</borrowDate>
                    <returnDate>2013-1-5</returnDate>
                </record>
                <record>            
                    <borrowDate>2013-2-3</borrowDate>
                    <returnDate>2013-4-5</returnDate>
                </record>
            </borrowRecords>
        </book>
        <book>
            <name>Book 2</name>
            <borrowRecords>
                <record>
                    <borrowDate>2013-1-3</borrowDate>
                    <returnDate>2013-1-5</returnDate>
                </record>
                <record>            
                    <borrowDate>2013-2-3</borrowDate>
                    <returnDate>2013-4-5</returnDate>
                </record>
            </borrowRecords>
        </book>
    </booksList>
</books>

2.
第一册
2013-1-3
2013-1-5
2013-2-3
2013-4-5
第二册
2013-1-3
2013-1-5
2013-2-3
2013-4-5

我对您的课程代码做了以下更改。我无法使用默认序列化程序复制XML序列化,因为如果不给“Record”元素一个容器元素,它将不会复制该元素

[System.Xml.Serialization.XmlRoot("books")]
public class books 
{
    public int bookNum { get; set; }
    public class book {
        public string name { get; set; }
        public class record {
            public string borrowDate { get; set; }
            public string returnDate { get; set; }
        }
        public record[] records { get; set; }
    }
    public book[] books { get; set; }
}
序列化它会给我以下输出

<books xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <bookNum>2</bookNum>
  <books>
    <book>
      <name>first</name>
      <records>
        <record>
          <borrowDate>19/07/2013 4:41:29 PM</borrowDate>
          <returnDate>19/07/2013 4:41:29 PM</returnDate>
        </record>
      </records>
    </book>
  </books>
</books>

我意识到这已经晚了几年,但我已经能够通过使用实现您想要的结构

我通过使用从xml生成模式定义和从xsd文件生成.Net代码发现了这一点。据我所知,这在.NET3.5到4.6中都有效

以下是我使用的类定义:

public class books
{
    public int bookNum { get; set; }
    public class book {
        public string name { get; set; }
        public class record {
            public string borrowDate { get; set; }
            public string returnDate { get; set; }
        }
        [XmlElement("record")]
        public record[] records { get; set; }
    }
    [XmlElement("book")]
    public book[] allBooks { get; set; }
}
下面是一个演示序列化/反序列化的片段(基于David Colwell的代码片段,顺便说一句,感谢您提供了关于如何排除BOM的提示,这正是我想要的):

这生成的XML可以序列化和反序列化,而无需实现IXmlSerializable,例如:

<books>
  <bookNum>2</bookNum>
  <book>
    <name>book 1</name>
    <record>
      <borrowDate>2/2/2016 5:57:25 PM</borrowDate>
      <returnDate>2/2/2016 5:57:25 PM</returnDate>
    </record>
  </book>
  <book>
    <name>book 2</name>
    <record>
      <borrowDate>2/2/2016 5:57:25 PM</borrowDate>
      <returnDate>2/2/2016 5:57:25 PM</returnDate>
    </record>
    <record>
      <borrowDate>2/2/2016 5:57:25 PM</borrowDate>
      <returnDate>2/2/2016 5:57:25 PM</returnDate>
    </record>
  </book>
</books>

2.
第一册
2016年2月2日下午5:57:25
2016年2月2日下午5:57:25
第二册
2016年2月2日下午5:57:25
2016年2月2日下午5:57:25
2016年2月2日下午5:57:25
2016年2月2日下午5:57:25

如果您需要其他类,例如books类中的book2,则需要一些特殊说明来实现它。 范例

当我尝试运行该程序时,出现以下错误:


“附加信息:反映类型“

发布XMLserializer的输出?”结果与下面的xml不一样时出错”-它如何“不一样”?你得到了什么?(旁注:您在XML中使用了不寻常的日期格式-ISO8601 YYYY-MM-DD)如果您进行XML序列化,您无法获得自定义的XMLMac,您可以。您需要为属性添加属性以更改其元素名称,但您可以。您可以使用属性的实现获得此类输出-请参阅我答案中的第三个摘要。您确定吗?因为我想我刚才是这样做的,让根类(
books
在本例中)扩展
List
,然后使用
xmlement
-属性对其应用属性…@Alxandr继承列表是另一个选项-它稍微改变了问题的条件+1是个好主意。我也猜这在不从列表继承的情况下是可行的,只需提供一个
Add
方法,但是我不知道XmlSerializer的内部是如何工作的…@Alxandr在使用google快速搜索后,我没有找到使用
Add
方法的解决方案-我找到的只是
IXmlSerializable
的不同变体。这只是一个猜测,因为
Add
方法支持
var a=newlist(){“a”、“b”、“c”}
另外,
List
似乎没有实现
IXmlSerializable
,尽管据我所知,它可能只是一个序列化构造函数。我只是想,既然.NET赋予了一个
Add
方法特殊的意义,那么XmlSerializer可能也赋予了它特殊的意义……我们不能让和处于同一级别?books是book的容器元素。这就是它在重新序列化时知道它们属于同一属性的方式。请编辑答案以详细说明特殊说明的主题。投票赞成使用xsd.exe从所需的XML创建类的想法!肯定会把它加到我的工具袋里。
public class books
{
    public int bookNum { get; set; }
    public class book {
        public string name { get; set; }
        public class record {
            public string borrowDate { get; set; }
            public string returnDate { get; set; }
        }
        [XmlElement("record")]
        public record[] records { get; set; }
    }
    [XmlElement("book")]
    public book[] allBooks { get; set; }
}
books bks = new books();
books bks2 = null;
bks.bookNum = 2;
bks.allBooks = new books.book[] 
        { 
            new books.book {
                name="book 1", 
                records = new books.book.record[] {
                        new books.book.record{borrowDate = DateTime.Now.ToString(), returnDate = DateTime.Now.ToString()}
                    }
                },
            new books.book { 
                name="book 2", 
                records = new books.book.record[] { 
                        new books.book.record{borrowDate = DateTime.Now.ToString(), returnDate = DateTime.Now.ToString()}, 
                        new books.book.record{borrowDate = DateTime.Now.ToString(), returnDate = DateTime.Now.ToString()}}
                    },
        };
string xmlString;

System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(books));

XmlWriterSettings settings = new XmlWriterSettings();
settings.Encoding = new UnicodeEncoding(false, false); // no BOM in a .NET string
settings.Indent = true;
settings.OmitXmlDeclaration = true;

XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
// exclude xsi and xsd namespaces by adding the following:
ns.Add(string.Empty, string.Empty);

using(StringWriter textWriter = new StringWriter()) {
    using(XmlWriter xmlWriter = XmlWriter.Create(textWriter, settings)) {
        serializer.Serialize(xmlWriter, bks, ns);
    }
    xmlString = textWriter.ToString(); //This is the output as a string
}

xmlString.Dump();

// Deserialize the xml string now       
using ( TextReader reader = new StringReader(xmlString) ) {
    bks2 = ( books )serializer.Deserialize(reader);
}

bks2.Dump();
<books>
  <bookNum>2</bookNum>
  <book>
    <name>book 1</name>
    <record>
      <borrowDate>2/2/2016 5:57:25 PM</borrowDate>
      <returnDate>2/2/2016 5:57:25 PM</returnDate>
    </record>
  </book>
  <book>
    <name>book 2</name>
    <record>
      <borrowDate>2/2/2016 5:57:25 PM</borrowDate>
      <returnDate>2/2/2016 5:57:25 PM</returnDate>
    </record>
    <record>
      <borrowDate>2/2/2016 5:57:25 PM</borrowDate>
      <returnDate>2/2/2016 5:57:25 PM</returnDate>
    </record>
  </book>
</books>
public class books
{     
   public int bookNum {get; set; }
   public class book {
         public string name {get; set; }
         public class record {
             public string borrowDate {get; set; }
             public string returnDate {get; set; }
         }
         [XmlElement ("record")]
         public record [] records {get; set; }
     }
     [XmlElement ("book")]
     public book [] allBooks {get; set; }

     public int book2Num {get; set; }
     public class book2 {
         public string name {get; set; }
         public class record {
             public string borrowDate {get; set; }
             public string returnDate {get; set; }
         }
         [XmlElement ("record")]
         public record [] records {get; set; }
     }
     [XmlElement ("book2")]
     public book2 [] allBook2 {get; set; }
}`