XmlSerializer Converts a C # object to an xml string

I created a C # class:

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 when I use the conversion of XmlSerializer to XML string. The result does not match the below xml.

What is the problem of my C # class? I want to use XmlSerializer to output the result instead of using 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 output result:

 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:

 <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> 
+7
c # xml linq
source share
4 answers

You cannot serialize a class from your question using standard serialization tools so that it has <book> entries at the same level as the <bookNum> node.

When a class saved using standard serialization tools, the list of your <book> nodes will always be nested in a separate node array, which will be at the same level as the <bookNum> node. The same applies to the field of the records array in the book class.

To generate the XML output you want — with <book> nodes at the same level as the <bookNum> node, you will have to implement IXmlSerializable in your books class for custom serialization. To see examples of IXmlSerializable implementations, visit the following links: https://stackoverflow.com/a/166778/

Another solution would be - as pointed out by the user Alexandr in the commentary on my answer - to inherit your books class from List<book> and have on your book field of the records class of the type of the class inheriting from the List<record> .

When serializing a class from your question, assuming your assigned proper XmlRoot, XmlElement, XmlArray and XmlArrayItem attributes look like this:

 [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 the XML output as follows:

 <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> 
+7
source share

I made the following code change to your class. I cannot duplicate XML serialization using the default serializer, because it will not duplicate the Record element without specifying the container element to it.

 [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 conclusion

 <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 } 
+8
source share

I understand that this is a couple of years late, but I was able to achieve the structure you wanted just by using XmlElementAttribute .

I discovered this using XSD.exe to generate schema definitions from xml and generate .Net code from xsd files. As far as I know, this works in .Net from 3.5 to 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 the LinqPad snippet that illustrates serialization / deserialization (based on David Colwell's code snippet, thanks BTW for a hint on how to exclude the spec, this was exactly what I was looking for):

 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 created XML that can be serialized and deserialized without implementing IXmlSerializable, for example:

 <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
source share

If you need other classes, such as book2 inside the books class, you have special instructions for implementing it. Example

 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 displaying type"

0
source share

All Articles