Change the order of elements when serializing XML - c#

I need to serialize an Object to XML and back. The XML is fix and I can't change it.
I fail to generate this structure after bookingList.
How can I "group" these <booking> elements to appear as a LIST and keep <error> & <counter> before this List of <booking> elements.
See my example here:
Structure i need....
<nicexml>
<key_id>1234567</key_id>
<surname>Jil</surname>
<name>Sander</name>
<station_id>1</station_id>
<ownBookings>
<bookingList>
<error></error>
<counter>20</counter>
<booking>
<bookingID>1234567890</bookingID>
</booking>
<booking>
<bookingID>2345678901</bookingID>
</booking>
</bookingList>
</ownBookings>
</nicexml>
Structure i get with C# code below....
<nicexml>
<key_id>1234567</key_id>
<surname>Jil</surname>
<name>Sander</name>
<station_id>1</station_id>
<ownBookings>
<bookingList>
<booking>
<booking>
<bookingID>1234567890</bookingID>
</booking>
<booking>
<bookingID>2345678901</bookingID>
</booking>
<booking>
<error></error>
<counter>20</counter>
</bookingList>
</ownBookings>
</nicexml>
C# Code:
using System;
using System.Xml.Serialization;
using System.Collections.Generic;
namespace xml_objects_serials
{
public class bookings
{
public class nicexml
{
public string key_id
{ get; set; }
public string surname
{ get; set; }
public string name
{ get; set; }
public int station_id
{ get; set; }
public ownBookings ownBookings
{ get; set; }
}
public class ownBookings
{
public bookingList bookingList
{ get; set; }
}
public class bookingList {
public string error
{ get; set; }
public int counter
{ get; set; }
public List<booking> booking= new List<booking>();
}
public class booking
{
public int bookingID
{ get; set; }
}
}

Try decorating the properties of the bookingListclass with the XmlElementAttribute, in order to control how the objects of that class are going to be serialized to XML.
Here's an example:
public class bookingList
{
[XmlElement(Order = 1)]
public string error { get; set; }
[XmlElement(Order = 2)]
public int counter { get; set; }
[XmlElement(ElementName = "booking", Order = 3)]
public List<booking> bookings = new List<booking>();
}
public class booking
{
public int id { get; set; }
}
In my test I obtained this output:
<?xml version="1.0" ?>
<bookingList>
<error>sample</error>
<counter>0</counter>
<booking>
<id>1</id>
</booking>
<booking>
<id>2</id>
</booking>
<booking>
<id>3</id>
</booking>
</bookingList>
Related resources:
Controlling XML Serialization Using Attributes

I was facing with this problem and i solved it... Well it is very interesting, and this is a bug in .net maybe.
the problem is here:
public List<booking> booking= new List<booking>();
You should use:
public List<booking> booking { get; set; }
And you will get the defined order .... but why? who knows... :)

Related

Deserializing XML with different Namespaces UWP

I have following XML-Data:
<?xml version="1.0"?>
<e:propertyset xmlns:e="urn:schemas-upnp-org:event-1-0">
<e:property>
<LastChange>
<Event xmlns="urn:schemas-upnp-org:metadata-1-0/RCS/">
<InstanceID val="0">
<RoomVolumes val="uuid:29e07ad9-224f-4160-a2bc-61d17845182a=100"/>
<Volume channel="Master" val="100"/>
<Mute channel="Master" val="0"/>
<RoomMutes val="uuid:29e07ad9-224f-4160-a2bc-61d17845182a=0"/>
</InstanceID>
</Event>
</LastChange>
</e:property>
</e:propertyset>
And here are my classes:
[XmlRoot("propertyset", Namespace = "urn:schemas-upnp-org:event-1-0")]
public class EventPropertySet
{
[XmlElement("property")]
public List<EventProperty> Properties { get; set; }
}
public class EventProperty
{
[XmlElement("LastChange")]
public string LastChange { get; set; }
[XmlElement("SinkProtocolInfo")]
public string SinkProtocolInfo { get; set; }
[XmlElement("IndexerStatus")]
public string IndexerStatus { get; set; }
[XmlElement("SystemUpdateID")]
public string SystemUpdateID { get; set; }
}
Now when I try to deserialize the XML-Data 'LastChange' is always 'null'.
When I modify the class 'EventProperty' like so:
public class EventProperty
{
[XmlElement("LastChange", Namespae = "")]
public string LastChange { get; set; }
[XmlElement("SinkProtocolInfo", Namespae = "")]
public string SinkProtocolInfo { get; set; }
[XmlElement("IndexerStatus", Namespae = "")]
public string IndexerStatus { get; set; }
[XmlElement("SystemUpdateID", Namespae = "")]
public string SystemUpdateID { get; set; }
}
The deserialization throws an exception:
XmlException: ReadElementContentAs() methods cannot be called on an element that has child elements. Line 1, position 103.
Any ideas what I should do?
Sorry, I found the problem. The data behind "LastChange" is normaly a parsed XML-Structure (like this:)
<LastChange><Event xmlns="urn:schemas-upnp-org:metadata-1-0/RCS/"><InstanceID val="0"><RoomVolumes val="uuid:29e07ad9-224f-4160-a2bc-61d17845182a=100"/><Volume channel="Master" val="100"/><Mute channel="Master" val="0"/><RoomMutes val="uuid:29e07ad9-224f-4160-a2bc-61d17845182a=0"/></InstanceID></Event></LastChange>
Now when I don't do the "DeParse" with WebUtility.HtmlDecode, everythings works fine.

XmlSerializer Deserialize list only getting the first item

This is my XML i get from an API:
<?xml version="1.0" encoding="UTF-8"?>
<response>
<datetime>2015-05-18 11:37:32</datetime>
<count>2</count>
<smsleft>40920</smsleft>
<sms><smsid>535041581</smsid><smsid>535041583</smsid></sms>
</response>
This is my class i try to parse it to:
[XmlRoot("response")]
public class SMSResponse
{
[XmlElement("sms")]
public List<smsid> Sms { get; set; }
}
public class smsid
{
[XmlElement("smsid")]
public string SmsID { get; set; }
}
Using this code:
XmlSerializer serializer = new XmlSerializer(typeof(SMSResponse));
using (TextReader reader = new StringReader(response))
{
SMSResponse result = (SMSResponse)serializer.Deserialize(reader);
}
However i only get the first SmsID in the list in my result, not 2 as in the reponse.
What am i doing wrong?
You've declared SmsID as a string, so only a single one can be deserialized. You've declared Sms as a list, but only one exists in your input file.
Try:
[XmlRoot("response")]
public class SMSResponse
{
[XmlArray("sms")]
[XmlArrayItem("smsid")]
public List<string> SmsID { get; set; }
}
Change your code to this
[XmlRoot("response")]
public class SMSResponse
{
[XmlElement("sms")]
public SMS Sms { get; set; }
}
public class SMS
{
[XmlElement("smsid")]
public List<string> SmsID { get; set; }
}
[XmlRoot("response")]
public class SMSResponse
{
[XmlArray(ElementName = "sms")]
[XmlArrayItem(ElementName = "smsid", Type = typeof(smsid))]
public List<smsid> Sms { get; set; }
}
public class smsid
{
[XmlText]
public string SmsID { get; set; }
}

How to Deserialize a xml file's listed items which is present within another listed items

I have an auto generated xml file with the following format.
<?xml version="1.0"?>
<School>
<Classes numberOfFields="5">
<Class name="10" dataType="double">
<Section value="A"/>
<Section value="B"/>
<Section value="C"/>
</Class>
<Class dataType="double"/>
<Class dataType="double"/>
<Class dataType="double"/>
<Class dataType="double"/>
</Classes>
</School>
I deserialize using "XmlDeserializer" as follows
School schoolResult = (School)xmlSerializer.Deserialize(stream);
XmlRootElement contains a collection of "Class" under "Classes" tag and further each "Class" would contain Collection of "Section".
And in C#, I have declared like this to deserialize "Classes" into a List of classes.
[XmlArray("Classes")]
[XmlArrayItem("Class", typeof(Class))]
public List<Class> Classes {};
Now to further deserialize Class into List of Sections, I have added the code as below.
[XmlArray("Class")]
[XmlArrayItem(ElementName="Section")]
public List<Section> ClassSections {};
My problem is I couldn't get the List of Sections values properly. Because I have "Class" as a class name in the first part and in second part I have mentioned same "Class" as Array element. So could any one tell how can I properly Deserialize my "School" object using "XmlSerializer" to get all the values properly.
Note: I cannot have a Array root tag like "Sections" under "Class". Because my xml document is auto generated. I cannot specify my own format.
Thanks...
try this :
public class School
{
[XmlAttribute]
public int numberOfFields { get; set; }
[XmlArray("Classes")]
[XmlArrayItem("Class", typeof(Class))]
public List<Class> Classes { get; set; }
}
public class Class
{
[XmlAttribute]
public string name { get; set; }
[XmlAttribute]
public string dataType { get; set; }
[XmlElement("Section")]
public List<Section> ClassSections { get; set; }
}
public class Section
{
[XmlAttribute]
public string value { get; set; }
}
* EDIT #1 **
--------------- Update Structure due to NumberOfFields is not readed ----------------
in my opinion it's not correct structure, but when u said it's an auto generated XML file, i think it simplest way to read it.
public class School
{
[XmlElement("Classes")]
public List<ArrayClass> Classes { get; set; }
}
public class ArrayClass
{
[XmlAttribute]
public int numberOfFields { get; set; }
[XmlElement("Class")]
public List<Class> Class { get; set; }
}
static void Main(string[] args)
{
var xml ="<?xml version=\"1.0\"?><School><Classes numberOfFields=\"5\"><Class name=\"10\" dataType=\"double\"><Section value=\"A\"/><Section value=\"B\"/><Section value=\"C\"/></Class><Class dataType=\"double\"/><Class dataType=\"double\"/><Class dataType=\"double\"/><Class dataType=\"double\"/></Classes></School>";
School result;
var serializer = new XmlSerializer(typeof(School));
var xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xml);
using (var reader = new XmlNodeReader(xmlDoc))
{
result = (School)serializer.Deserialize(reader);
}
}
public class School
{
[XmlArray("Classes")]
[XmlArrayItem("Class")]
public List<Class> Classes { get; set; }
}
public class Class
{
[XmlElement("Section")]
public List<Section> ClassSections { get; set; }
}
public class Section
{
[XmlAttribute("value")]
public string Value { get; set; }
}

How to write/set sub-node with multiple cdata xml c#

I try to produce XML like below
<?xml version="1.0" encoding="UTF-8"?>
<movie>
<title><![CDATA[Con Air]]></title>
<plot><![CDATA[When the government puts all its rotten criminal eggs in one airborne basket, it's asking for trouble. Before you can say, "Pass the barf bag," the crooks control the plane, led by creepy Cyrus "The Virus" Grissom. Watching his every move is the just-released Cameron Poe, who'd rather reunite with his family. The action climaxes with an incredible crash sequence in Las Vegas.]]></plot>
<tagline><![CDATA[They were deadly on the ground; Now they have wings]]></tagline>
<year>1997</year>
<id>tt0118880</id>
<rating>65</rating>
<votes>93</votes>
<budget>75000000</budget>
<revenue>224012234</revenue>
<company><![CDATA[Touchstone Pictures]]></company>
<genre>
<name><![CDATA[Action]]></name>
<name><![CDATA[Adventure]]></name>
<name><![CDATA[Thriller]]></name>
</genre>
</movie>
I use C# XmlDocument to generate the XML File using serializable class below
[Serializable]
public class movie
{
public movie()
{
this.genre = new Genre();
}
[XmlIgnore]
public string title { get; set; }
[XmlElement("title")]
public XmlCDataSection titleCDATA
{
get { return new XmlDocument().CreateCDataSection(title); }
set { title = value.Value; }
}
[XmlIgnore]
public string plot { get; set; }
[XmlElement("plot")]
public XmlCDataSection plotCDATA
{
get { return new XmlDocument().CreateCDataSection(plot); }
set { plot = value.Value; }
}
[XmlIgnore]
public string tagline { get; set; }
[XmlElement("tagline")]
public XmlCDataSection taglineCDATA
{
get { return new XmlDocument().CreateCDataSection(tagline); }
set { tagline = value.Value; }
}
public int year { get; set; }
public string id { get; set; }
public int rating { get; set; }
public int votes { get; set; }
public long budget { get; set; }
public long revenue { get; set; }
[XmlIgnore]
public string company { get; set; }
[XmlElement("company")]
public XmlCDataSection companyCDATA
{
get { return new XmlDocument().CreateCDataSection(company); }
set { company = value.Value; }
}
[XmlElement("genre")]
public Genre genre { get; set; }
}
public class Genre
{
public Genre()
{
}
public string[] name { get; set; }
}
But the output not as expected like below
<?xml version="1.0" encoding="utf-16"?>
<movie>
<title><![CDATA[Monster House]]></title>
<plot><![CDATA[Monsters under the bed are scary enough, but what happens when an entire house is out to get you? Three teens aim to find out when they go up against a decrepit neighboring home and unlock its frightening secrets.]]></plot>
<tagline><![CDATA[The House is . . . ALIVE!]]></tagline>
<year>2006</year>
<id>tt0385880</id>
<rating>57</rating>
<votes>74</votes>
<budget>0</budget>
<revenue>0</revenue>
<company><![CDATA[Sony Pictures Entertainment]]></company>
<genre>
<name>
<string>Adventure</string>
<string>Animation</string>
<string>Comedy</string>
<string>Fantasy</string>
<string>Mystery</string>
<string>Science Fiction</string>
<string>Family</string>
</name>
</genre>
</movie>
How can I create sub-node xml like the genre sub-node in the first example?
I think your issue with element names called "string" instead of "name" should be solved by using proper annotation as covered in Controlling XML Serialization Using Attributes .
You'll have to modify you class a bit (and I'm not sure you can get CDATA for names, but it should be fine):
public class Movie
{
....
[XmlArray("genre")]
[XmlArrayItem("Name")]
public string[] Genre { get; set; }
}

Deserialize XML with multiple namespaces to objects

I´m trying to deserialize this XML to objects in C# .NET 4.5:
<DIDL-Lite xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/"
xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/">
<item id="28" parentID="19" restricted="1">
<dc:creator>Alicia Keys</dc:creator>
<dc:date>2003-01-01</dc:date>
<dc:title>Gangsta Lovin&apos; (feat. Alicia Keys)</dc:title>
</item>
</DIDL-Lite>
Code:
I´m not getting any "item" Lists. The object isn't deserialized.
MemoryStream reader = new MemmoryStream(System.Text.Encoding.Unicode.GetBytes(Result));
var ser = new XmlSerializer(typeof(DIDLLite));
DIDLLite device = (DIDLLite)ser.Deserialize(reader);
Class DIDLLite:
[XmlRoot("DIDL-Lite", Namespace = "urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/")]
public class DIDLLite {
DIDLLite() {
this.serviceItem = new List<ContainerItem>();
}
[System.Xml.Serialization.XmlArrayItem("item", typeof(ServiceListTypeService), IsNullable = false)]
List<ContainerItem> serviceItem = new List<ContainerItem>();
}
Class ContainerItem:
public class ContainerItem
{
[System.Xml.Serialization.XmlAttribute("id")]
public string id { get; set; }
[System.Xml.Serialization.XmlAttribute("parentID")]
public string parentID { get; set; }
[System.Xml.Serialization.XmlAttribute("restricted")]
public string restricted { get; set; }
[System.Xml.Serialization.XmlAttribute("searchable")]
public string searchable { get; set; }
public string title { get; set; }
}
You have several issues:
you define an XmlArrayItem attribute - but really, in your XML, you don't have any list of items. If you want to use an Xml array construct, you'd need to have something like this for your XML:
<DIDL-Lite .....>
<Items>
<item id="28" parentID="19" restricted="1">
......
</item>
<item id="29" parentID="19" restricted="1">
......
</item>
</Items>
</DIDL-Lite>
So you would need to have an <Items>...</Items> wrapper around your <item> elements.
You have this declaration:
[XmlArrayItem("item", typeof(ServiceListTypeService), IsNullable = false)]
but where is the ServiceListtypeService defined? I don't see any trace of it....
I simplified your code a bit - and this works just fine:
[XmlRoot("DIDL-Lite", Namespace = "urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/")]
public class DIDLLite
{
[XmlElement("item")]
public ContainerItem Item { get; set; }
}
public class ContainerItem
{
[XmlAttribute("id")]
public string id { get; set; }
[XmlAttribute("parentID")]
public string parentID { get; set; }
[XmlAttribute("restricted")]
public string restricted { get; set; }
[XmlAttribute("searchable")]
public string searchable { get; set; }
// you were missing these elements and their namespace
[XmlElement(Namespace = "http://purl.org/dc/elements/1.1/")]
public string creator { get; set; }
[XmlElement(Namespace = "http://purl.org/dc/elements/1.1/")]
public string date { get; set; }
[XmlElement(Namespace = "http://purl.org/dc/elements/1.1/")]
public string title { get; set; }
}
And now, when I run your code to deserialize your XML, I do get the objects filled nicely.

Categories