Deserialize XML with multiple namespaces to objects - c#

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.

Related

Deserialize a xml file with child elements in c#

I am trying to Deserialize a xml file of this type
<?xml version="1.0" encoding="UTF-8"?>
<Network>
<ROUTES>
<ROUTE ID="RT_BALA_GLNC_R_162_154_1" DIRECTION="LEFT" ZONE="Richmond_Hill">
<ENTRANCESIGNAL>BALA_GLNC_G162</ENTRANCESIGNAL>
<EXITSIGNAL>BALA_DONS_G154</EXITSIGNAL>
<POINTENDIDS>
<POINTENDID POS="N">PT_BALA_GLNC_W11.TrackPortionConnection</POINTENDID>
<POINTENDID POS="N">PT_BALA_GLNC_W23.TrackPortionConnection</POINTENDID>
</POINTENDIDS>
</ROUTE>
<ROUTE ID="RT_BALA_ORLS_R_111_119_1" DIRECTION="RIGHT" ZONE="Richmond_Hill">
<ENTRANCESIGNAL>BALA_ORLS_G111</ENTRANCESIGNAL>
<EXITSIGNAL>BALA_ORLN_G119</EXITSIGNAL>
<POINTENDIDS>
<POINTENDID POS="N">PT_BALA_ORLS_W1.TrackPortionConnection</POINTENDID>
</POINTENDIDS>
</ROUTE>
<ROUTE ID="RT_BALA_GLNC_R_162D_154_1" DIRECTION="LEFT" ZONE="Richmond_Hill">
<ENTRANCESIGNAL>BALA_GLNC_G162D</ENTRANCESIGNAL>
<EXITSIGNAL>BALA_DONS_G154</EXITSIGNAL>
<POINTENDIDS>
<POINTENDID POS="R">PT_BALA_GLNC_W11.TrackPortionConnection</POINTENDID>
<POINTENDID POS="N">PT_BALA_GLNC_W23.TrackPortionConnection</POINTENDID>
</POINTENDIDS>
</ROUTE>
</ROUTES>
</Network>
I have tried this
class Program
{
static void Main(string[] args)
{
XmlSerializer deserializer = new XmlSerializer(typeof(Network));
TextReader reader = new StreamReader(#"xml File Location");
object obj = deserializer.Deserialize(reader);
Network XmlData = (Network)obj;
reader.Close();
Console.ReadLine();
}
}
[XmlRoot("Network")]
public class Network
{
[XmlElement("ROUTES")]
public List<ROUTE> ROUTES { get; set; }
}
public class ROUTE
{
[XmlAttribute("ID")]
public string ID { get; set; }
[XmlAttribute("DIRECTION")]
public string DIRECTION { get; set; }
[XmlElement("ENTRANCESIGNAL")]
public string ENTRANCESIGNAL { get; set; }
[XmlElement("EXITSIGNAL")]
public string EXITSIGNAL { get; set; }
[XmlElement("POINTENDIDS")]
public POINTENDIDS POINTENDIDS { get; set; }
}
public class POINTENDIDS
{
[XmlElement("POINTENDID")]
public List<POINTENDID> POINTENDID { get; set; }
}
public class POINTENDID
{
[XmlAttribute("POS")]
public string POS { get; set; }
}
I am doing it in a console application,
I started Debugging and put breakpoint on Network XmlData = (Network)obj;
I've got only 1 ROUTES and the values of "ID", "DIRECTION", "ENTRANCESIGNAL" ...etc are set to Null
being beginner in c# programming , I don't really understand what should I do !
Need help for this implementation
Fix you Network Class. The names in square brackets are case sensitive. You also need to add the Xml array attributes.
[XmlRoot("Network")]
public class Network
{
[XmlArrayItem("ROUTE")]
[XmlArray("ROUTES")]
public List<ROUTE> ROUTES { get; set; }
}
using System.Xml; //XmlDoc
using System.Xml.Linq;//XElement
using System.IO;//Path,File,Directory, Stream
Read and parse xml file:
XmlDocument XmlDoc = new XmlDocument();
XmlDoc.Load(XmlFilePath);
Another approach is using XElement instead:
XElement a = XElement.Load(#"c:\path\file");
Most often I prefer XElement over XmlDocument, but that's personal
If you are starting with C#, you'd need a book, and a simpler project. Streams and Xml are syntactically complex. Also, console apps are ugly, and Forms apps are not that hard to do with the graphical tools of VisualStudio.
Your C# classes are not exactly aligned with the XML file and the serializer returns only a partial result. What you can do instead if the XML structure is fixed is outlined here.
https://stackoverflow.com/a/17315863/99804
This then works as you want it to.
You will get the following auto-generated code.
Note: I have cleaned up the output to use auto-properties etc.
using System;
using System.Xml.Serialization;
// NOTE: Generated code may require at least .NET Framework 4.5 or .NET Core/Standard 2.0.
/// <remarks />
[Serializable]
[XmlType(AnonymousType = true)]
[XmlRoot(Namespace = "", IsNullable = false)]
public class Network
{
/// <remarks />
[XmlArrayItem("ROUTE", IsNullable = false)]
public NetworkROUTE[] ROUTES { get; set; }
}
[Serializable]
[XmlType(AnonymousType = true)]
public class NetworkROUTE
{
[XmlAttribute]
public string DIRECTION { get; set; }
public string ENTRANCESIGNAL { get; set; }
public string EXITSIGNAL { get; set; }
[XmlAttribute]
public string ID { get; set; }
[XmlArrayItem("POINTENDID", IsNullable = false)]
public NetworkROUTEPOINTENDID[] POINTENDIDS { get; set; }
[XmlAttribute]
public string ZONE { get; set; }
}
[Serializable]
[XmlType(AnonymousType = true)]
public class NetworkROUTEPOINTENDID
{
[XmlAttribute]
public string POS { get; set; }
[XmlText]
public string Value { get; set; }
}

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.

Xml Serialization for list Property doesn't work when one item in the list

<TotalRecords ItineraryCount='1' >
<Recs ItineraryNumber="1" >
<Amount>516.6</Amount>
<TravelTime>940</TravelTime>
<FSegment>
<OutProperty>
<Segment No="1">
<Name>Ronald</Name>
<City>London</City>
<Country>United Kingdom</Country>
</Segment>
<Segment No="2">
<Name>Richard</Name>
<City>
London
</City>
<Country>United Kingdom</Country>
</Segment>
</OutProperty>
</FSegment>
</Recs>
</TotalRecords >
I am serializing xml to object of TotalRecords Class. It works fine when there are more than one segment in the OutProperty but in case of one segment it doesn't serialize into list property.
I have also tried with [XmlArray("")] and [XMlArrayItem("")] but it doesn't work. Anyone have idea?
public class TotalRecords
{
public Recs recs { get; set; }
public string ItineraryCount { get; set; }
}
public partial class Recs
{
public string amountField { get; set; }
public string travelTimeField { get; set; }
public FSegment fSegmentField { get; set; }
public string itineraryNumberField { get; set; }
}
public class FSegment
{
public List<Segment> OutProperty {get;set;}
}
public class Segment
{
public string nameField { get; set; }
public string cityField { get; set; }
public string countryField { get; set; }
}
Try to use the following for your Classes and their Properties:
[DataContract]
public class Contact
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
}
Hacking like this helps in many cases, perhaps in your too (converting List to array):
public class FSegment
{
[XmlIgnore]
public List<Segment> OutProperty {get;set;}
[XmlArray("OutProperty");
public Segment[] _OutProperty
{
get { return OutProperty.ToArray(); }
set { OutProperty = new List<Segment>(value); }
}
}
I am not exactly sure how your provided class definition worked previously without any XML attribute/element definitions since your variable names are not the same as the XML identifiers, meaning that the serialization wouldn't populate the properties that it couldn't find a name for.
Nether the less, the main issue here is that you are trying to put a list into a normal property.
From the XML provided, OutProperty is a single sub element of FSegment and Segment is an array of sub elements of OutProperty, but in your provided code, you tried to make Segment an array sub element of FSegment.
The correct structure of the class definition should be as follows (also including the XML definitions)
[System.Xml.Serialization.XmlRoot(ElementName="TotalRecords")]
public class TotalRecords
{
[System.Xml.Serialization.XmlElement(ElementName="Recs")]
public Recs recs { get; set; }
[System.Xml.Serialization.XmlAttribute(AttributeName = "ItineraryCount")]
public string ItineraryCount { get; set; }
}
public partial class Recs
{
[System.Xml.Serialization.XmlElement(ElementName = "Amount")]
public string amountField { get; set; }
[System.Xml.Serialization.XmlElement(ElementName = "TravelTime")]
public string travelTimeField { get; set; }
[System.Xml.Serialization.XmlElement(ElementName = "FSegment")]
public FSegment fSegmentField { get; set; }
[System.Xml.Serialization.XmlAttribute(AttributeName = "ItineraryNumber")]
public string itineraryNumberField { get; set; }
}
public class FSegment
{
[System.Xml.Serialization.XmlElement(ElementName = "OutProperty")]
public SegmentList OutProperty { get; set; }
}
public class SegmentList
{
[System.Xml.Serialization.XmlElement(ElementName = "Segment")]
public List<Segment> segmentField { get; set; }
}
public class Segment
{
[System.Xml.Serialization.XmlElement(ElementName = "Name")]
public string nameField { get; set; }
[System.Xml.Serialization.XmlElement(ElementName = "City")]
public string cityField { get; set; }
[System.Xml.Serialization.XmlElement(ElementName = "Country")]
public string countryField { get; set; }
[System.Xml.Serialization.XmlAttribute(AttributeName = "No")]
public int segmentNoField { get; set; }
}
Please note that in the above structure, Segment is a list object under the OutProperty object, which resides under the FSegment object.
Using this class structure to load your XML produces the (assumed) correct data in the created objects.
Using the XML definitions allows you to decouple the actual names of class properties from what they are called in the XML data. This allows you to changes the one or the other without affecting the other one, which is useful when you don't control the creation of the XML data.
If you don't want all the XML definitions in your code, change the names of the classes so that you can name your properties the same as what they are called in the XML file. That will allow you couple everything directly

Deserializing xml element to Array with XmlSerializer doesn't work

I want to deserialize the following xml into my class, i can't change the xml because it commes from a device over tcp/ip.
<?xml version="1.0" encoding="utf-8"?>
<CONTACTINFORMATION UID="1234">
<LoginId><![CDATA[1234]]></LoginId>
<ContactId><![CDATA[2134]]></ContactId>
<ContactType>CCININTERN</ContactType>
<Status>CONVERSATION</Status>
<From><![CDATA[123]]></From>
<To><![CDATA[123]]></To>
<WaitTime><![CDATA[123]]></WaitTime>
<ContactPropertySummary>
<ContactProperty>
<Name><![CDATA[13]]></Name>
<Value><![CDATA[13]]></Value>
<Hidden>NO</Hidden>
<Url><![CDATA[13]]></Url>
</ContactProperty>
</ContactPropertySummary>
<SkillSummary>
<Skill>
<Name><![CDATA[123]]></Name>
<Mandatory>YES</Mandatory>
</Skill>
<Skill>
<Name><![CDATA[124]]></Name>
<Mandatory>YES</Mandatory>
</Skill>
</SkillSummary>
<ContactCodeSummary>
<ContactCode>
<Id>123</Id>
<Hidden>NO</Hidden>
<Assigned>YES</Assigned>
</ContactCode>
</ContactCodeSummary>
<GroupSummary>
<Group>
<Name><![CDATA[123]]></Name>
<Mandatory>YES</Mandatory>
</Group>
</GroupSummary>
<PreviousAgent><![CDATA[2]]></PreviousAgent>
<ScratchPadId><![CDATA[2]]></ScratchPadId>
<ScratchPadData><![CDATA[2]]></ScratchPadData>
<FaxSpecific>
<NbrOfPages>2</NbrOfPages>
</FaxSpecific>
</CONTACTINFORMATION>
My class:
[Serializable]
[XmlRoot("CONTACTINFORMATION")]
public class Contact
{
#region :: PROPERTIES ::
public string LoginId { get; set; }
public string ContactId { get; set; }
public ContactType ContactType { get; set; }
public ContactStatus Status { get; set; }
[XmlElement("From")]
public string ContactFrom { get; set; }
[XmlElement("To")]
public string ContactTo { get; set; }
public int WaitTime { get; set; }
[XmlElement("SkillSummary", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
[XmlArray("Skill")]
//[XmlElement("SkillSummary", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
public Skill[] Skills { get; set; }
[XmlArray("ContactPropertySummary")]
public ContactProperty[] Properties { get; set; }
[XmlArray("GroupSummary", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
[XmlArrayItem("Group", typeof(Group), Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
public Group[] Groups { get; set; }
}
The arry of skills has 2 skills, after deserializing there is only 1 skill in the arry, the groups and properties array is null...
What i'm doing wrong?
You should properly decorate array properties with XmlArray and XmlArrayItem attributes. For e.g. for skills property you are using XmlElement with XmlArray which is not permitted.
[XmlArrayItem("Skill", typeof(Skill), Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
[XmlArray("SkillSummary", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
public Skill[] Skills
{
get;
set;
}
[XmlArray("ContactPropertySummary")]
[XmlArrayItem("ContactProperty", typeof(ContactProperty), Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
public ContactProperty[] Properties
{
get;
set;
}
[XmlArray("GroupSummary", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
[XmlArrayItem("Group", typeof(Group), Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
public Group[] Groups
{
get;
set;
}
Make Sure that xmlArrayItem 'types' have proper read/write properties
public class Skill
{
public string Name
{
get;
set;
}
public string Mandatory
{
get;
set;
}
}
I recommend you to provide as much information to the XMLSerializer, through attributes, as you can.
You don't seem to be too off the mark. Using the above definitions I was able to successfully deserialize the XML you provided.
Start by defining a class Skill and then using this class in your Contract class.
// We're going to define a class called Skill
[Serializable()]
public class Skill
{
[System.Xml.Serialization.XmlElement("Name")]
public string Name { get; set; }
[System.Xml.Serialization.XmlElement("Mandatory")]
public string Mandatory { get; set; }
}
[Serializable]
[XmlRoot("CONTACTINFORMATION")]
public class Contact
{
// ...... Rest of your elements
[XmlArray("SkillSummary")]
[XmlArrayItem("Skill", typeof(Skill))]
public Skills[] Skill { get; set; }
}
Please do the same for Groups and Properties as well.

XML serialization array in C#

I'm having trouble figuring this out, I have an xml sheet that looks like this
<root>
<list id="1" title="One">
<word>TEST1</word>
<word>TEST2</word>
<word>TEST3</word>
<word>TEST4</word>
<word>TEST5</word>
<word>TEST6</word>
</list>
<list id="2" title="Two">
<word>TEST1</word>
<word>TEST2</word>
<word>TEST3</word>
<word>TEST4</word>
<word>TEST5</word>
<word>TEST6</word>
</list>
</root>
And I'm trying to serialize it into
public class Items
{
[XmlAttribute("id")]
public string ID { get; set; }
[XmlAttribute("title")]
public string Title { get; set; }
//I don't know what to do for this
[Xml... something]
public list<string> Words { get; set; }
}
//I don't this this is right either
[XmlRoot("root")]
public class Lists
{
[XmlArray("list")]
[XmlArrayItem("word")]
public List<Items> Get { get; set; }
}
//Deserialize XML to Lists Class
using (Stream s = File.OpenRead("myfile.xml"))
{
Lists myLists = (Lists) new XmlSerializer(typeof (Lists)).Deserialize(s);
}
I'm really new with XML and XML serializing, any help would be much appreciated
It should work if you declare your classes as
public class Items
{
[XmlAttribute("id")]
public string ID { get; set; }
[XmlAttribute("title")]
public string Title { get; set; }
[XmlElement("word")]
public List<string> Words { get; set; }
}
[XmlRoot("root")]
public class Lists
{
[XmlElement("list")]
public List<Items> Get { get; set; }
}
If you just need to read your XML into an object structure, it might be easier to use XLINQ.
Define your class like so:
public class WordList
{
public string ID { get; set; }
public string Title { get; set; }
public List<string> Words { get; set; }
}
And then read the XML:
XDocument xDocument = XDocument.Load("myfile.xml");
List<WordList> wordLists =
(
from listElement in xDocument.Root.Elements("list")
select new WordList
{
ID = listElement.Attribute("id").Value,
Title = listElement.Attribute("title").Value,
Words =
(
from wordElement in listElement.Elements("word")
select wordElement.Value
).ToList()
}
).ToList();

Categories