XmlSerializer 将 C# 对象转换为 xml 字符串
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17739330/
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
XmlSerializer Convert C# object to xml string
提问by Ricky Yip
I have created a C# class:
我创建了一个 C# 类:
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; }
}
But is when I use XmlSerializer convert to XML string. The result is not the same as below xml.
但是当我使用 XmlSerializer 转换为 XML 字符串时。结果与下面的xml不同。
What is the problem of my C# class? I want to use XmlSerializer to ouput the result instead of using XmlDocument.
我的 C# 类有什么问题?我想使用 XmlSerializer 来输出结果而不是使用 XmlDocument。
Any ideas? Thanks in advance!
有任何想法吗?提前致谢!
<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>
EDIT
编辑
Below is my C# code and the ouput result:
下面是我的 C# 代码和输出结果:
books books = new books {
bookNum = 2,
Books = new books.book[] {
new books.book {
name = "Book1",
records = new books.book.record[] {
new books.book.record {
borrowDate = "2013-1-3",
returnDate = "2013-1-5"
},
new books.book.record {
borrowDate = "2013-2-3",
returnDate = "2013-4-5"
}
}
},
new books.book {
name = "Book1",
records = new books.book.record[] {
new books.book.record {
borrowDate = "2013-1-3",
returnDate = "2013-1-5"
},
new books.book.record {
borrowDate = "2013-2-3",
returnDate = "2013-4-5"
}
}
}
}
};
XmlSerializer xsSubmit = new XmlSerializer(typeof(books));
XmlDocument doc = new XmlDocument();
System.IO.StringWriter sww = new System.IO.StringWriter();
XmlWriter writer = XmlWriter.Create(sww);
xsSubmit.Serialize(writer, books);
var xml = sww.ToString(); // Your xml
context.Response.Write(xml);
XML:
XML:
<books>
<bookNum>2</bookNum>
<Books>
<book>
<name>Book1</name>
<records>
<record>
<borrowDate>2013-1-3</borrowDate>
<returnDate>2013-1-5</returnDate>
</record>
<record>
<borrowDate>2013-2-3</borrowDate>
<returnDate>2013-4-5</returnDate>
</record>
</records>
</book>
<book>
<name>Book1</name>
<records>
<record>
<borrowDate>2013-1-3</borrowDate>
<returnDate>2013-1-5</returnDate>
</record>
<record>
<borrowDate>2013-2-3</borrowDate>
<returnDate>2013-4-5</returnDate>
</record>
</records>
</book>
</Books>
</books>
采纳答案by Andrii Kalytiiuk
You cannot serialize class from your question using standard serialization tools so that it will have <book>
entries on the same level as <bookNum>
node.
您不能使用标准序列化工具从您的问题中序列化类,以便它具有<book>
与<bookNum>
节点相同级别的条目。
When class saved with standard serialization tools list of your <book>
nodes will always be nested into separate array nodethat will be on the same level as <bookNum>
node. Same concerns records
array field on book
class.
当使用标准序列化工具保存的类时,您的<book>
节点列表将始终嵌套到与node处于同一级别的单独数组节点中<bookNum>
。同样关注类records
上的数组字段book
。
To generate XMLoutput that you want to - with <book>
nodes on same level as <bookNum>
node - you will have to implement IXmlSerializableinterface in your books
class for custom serialization. To see examples of IXmlSerializable
implementation visit these links: StackOverflow answer, CodeProject article.
要生成您想要的XML输出 -<book>
节点与节点位于同一级别<bookNum>
- 您必须在类中实现IXmlSerializable接口以books
进行自定义序列化。要查看IXmlSerializable
实现示例,请访问以下链接:StackOverflow 答案、CodeProject 文章。
Another solution will be - as stated user Alexandrin comment to my answer - to inherit your books
class from List<book>
type and to have on your book
class field records
of class type that is inherited from List<record>
type.
另一个解决方案将是 - 正如用户 Alexandr在对我的回答的评论中所说-books
从List<book>
类型继承您的类,并在您的book
类字段records
上拥有从类型继承的类List<record>
类型。
When serializing class from your question, assuming that your assigned proper XmlRoot, XmlElement, XmlArray and XmlArrayItem attributesas follows:
从您的问题序列化类时,假设您分配了正确的XmlRoot、XmlElement、XmlArray 和 XmlArrayItem 属性,如下所示:
[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; }
}
you will get XMLoutput as follows:
您将获得如下XML输出:
<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>
回答by David Colwell
I made the following change to your class code. I am unable to duplicate the XML serialization using the default serializer, because it will not duplicate the 'Record' element without giving it a container element.
我对您的课程代码进行了以下更改。我无法使用默认序列化器复制 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; }
}
Serializing this gives me the following output
序列化这给了我以下输出
<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>
using this test code
使用此测试代码
books bks = new books();
bks.bookNum = 2;
bks.books = new books.book[]{ new books.book{name="first", records = new books.book.record[] {new books.book.record{borrowDate = DateTime.Now.ToString(), returnDate = DateTime.Now.ToString()}}}};
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;
using(StringWriter textWriter = new StringWriter()) {
using(XmlWriter xmlWriter = XmlWriter.Create(textWriter, settings)) {
serializer.Serialize(xmlWriter, bks);
}
return textWriter.ToString(); //This is the output as a string
}
回答by vbigham
I realize this is a couple of years late, but I have been able to achieve the structure that you desired just by using XmlElementAttribute.
我意识到这已经晚了几年,但我已经能够通过使用XmlElementAttribute来实现您想要的结构。
I discovered this by using XSD.exeto generate schema definitions from xml and generate .Net code from xsd files. As far as I know, this works in .Net 3.5 through 4.6.
我通过使用XSD.exe从 xml 生成架构定义并从 xsd 文件生成 .Net 代码发现了这一点。据我所知,这适用于 .Net 3.5 到 4.6。
Here is the class definition I used:
这是我使用的类定义:
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; }
}
And here is a LinqPadsnippet that illustrates the serialization/deserialization (based on David Colwell's code snippet, thanks BTW for the tip on how to exclude BOM, it was just what I was looking for):
这是一个说明序列化/反序列化的LinqPad片段(基于 David Colwell 的代码片段,感谢 BTW 关于如何排除 BOM 的提示,这正是我正在寻找的):
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();
This produced XML that is can be serialized and deserialized without implementing IXmlSerializable, such as:
生成的 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>
回答by Rodolfo Ruiz
if you need other classes, such as book2 inside the books class, you have some special instructions to implement it. example
如果您需要其他类,例如书籍类中的 book2,您有一些特殊的说明来实现它。例子
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; }
}`
When I try to run the program I have the following error:
当我尝试运行该程序时,出现以下错误:
"Additional information: Error when reflecting the type "
“附加信息:反映类型时出错”