Deserialize a xml file with child elements in c# - 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; }
}

Related

What is wrong in my class hierarchy for an xml deserialization?

I'm trying to deserialize the following xml document into a C# object:
<ns1:StockerFichiers
xmlns:ns1="http://www.foo.fr/bar/Repository"
xmlns:ns0="http://www.foo.fr/bar/Transport/">
<ns1:fichiersAStocker>
<ns0:FichierIdentifie>
<ns0:Contenu></ns0:Contenu>
<ns0:DomaineIdLocalDoc>128</ns0:DomaineIdLocalDoc>
<ns0:EstOriginal>true</ns0:EstOriginal>
<ns0:IdLocalDoc>2018-07-06T154554_70183_2</ns0:IdLocalDoc>
<ns0:PieceDynamique>false</ns0:PieceDynamique>
<ns0:GoldenSource>false</ns0:GoldenSource>
<ns0:TypeDoc>PDF</ns0:TypeDoc>
<ns0:TypeMime>application/pdf</ns0:TypeMime>
</ns0:FichierIdentifie>
</ns1:fichiersAStocker>
</ns1:StockerFichiers>
I know a lot of deserialization questions already exist, but even if some seems to be solving the same issue I face, None of what I've tried did populate my List<FichierIdentifie>.
Where I deserialize:
public void StockerFichiersXmlBase64(string fichiersAStocker)
{
//serializer
XmlRootAttribute xroot = new XmlRootAttribute();
xroot.ElementName = "StockerFichiers";
xroot.Namespace = NamespacesConstantes.NAMESPACE_SWREPOSITORY; //ns1
XmlSerializer deserializer = new XmlSerializer(typeof(StockerFichiersRoot),xroot );
//fichiersAStocker is base64 encoded
byte[] data = Convert.FromBase64String(fichiersAStocker);
StringReader stringReader = new StringReader(Encoding.UTF8.GetString(data));
//deserialization
StockerFichiersRoot deserializedFiles = (StockerFichiersRoot)deserializer.Deserialize(stringReader);
}
My current version :
// Root
[XmlRoot(ElementName = "StockerFichiers", Namespace = NamespacesConstantes.NAMESPACE_SWREPOSITORY)]
public class StockerFichiersRoot
{
[XmlElement(ElementName = "fichiersAStocker", Namespace = NamespacesConstantes.NAMESPACE_SWREPOSITORY)]
public FichiersAStocker fichiersAStocker { get; set; }
}
//sub root
public class FichiersAStocker
{
[XmlArray(ElementName = "fichiersAStocker", Namespace = NamespacesConstantes.NAMESPACE_SWREPOSITORY)]
[XmlArrayItem(ElementName = "FichierIdentifie", Namespace=NamespacesConstantes.NAMESPACE_MSS_TRANSPORT)]
public List<FichierIdentifie> FichiersIdentifie { get; set; }
}
public class FichierIdentifie
{
[XmlElement(Namespace = NamespacesConstantes.NAMESPACE_TRANSPORT)]
public byte[] Contenu { get; set; }
//all fields are similar to the first one
}
And with this variation of the subroot class according to Is it possible to deserialize XML into List<T>? :
//sub root
public class FichiersAStocker
{
[XmlElement(ElementName = "FichierIdentifie", Namespace=NamespacesConstantes.NAMESPACE_MSS_TRANSPORT)]
public List<FichierIdentifie> FichiersIdentifie { get; set; }
}
I've also tried to remove the class FichiersAStocker (the sub root), to put the List<FichierIdentifie> in the root class, with both [xmlArray..] and [XmlElement] variations but with no success.
I always get an object with the list empty.
Try using XML2CSharp to generate class. Then try using that class or use it for debugging.
Generated code for your XML looks like this:
(You can remove unwanted properties)
/*
Licensed under the Apache License, Version 2.0
http://www.apache.org/licenses/LICENSE-2.0
*/
using System;
using System.Xml.Serialization;
using System.Collections.Generic;
namespace Xml2CSharp
{
[XmlRoot(ElementName="FichierIdentifie", Namespace="http://www.foo.fr/bar/Transport/")]
public class FichierIdentifie {
[XmlElement(ElementName="Contenu", Namespace="http://www.foo.fr/bar/Transport/")]
public string Contenu { get; set; }
[XmlElement(ElementName="DomaineIdLocalDoc", Namespace="http://www.foo.fr/bar/Transport/")]
public string DomaineIdLocalDoc { get; set; }
[XmlElement(ElementName="EstOriginal", Namespace="http://www.foo.fr/bar/Transport/")]
public string EstOriginal { get; set; }
[XmlElement(ElementName="IdLocalDoc", Namespace="http://www.foo.fr/bar/Transport/")]
public string IdLocalDoc { get; set; }
[XmlElement(ElementName="PieceDynamique", Namespace="http://www.foo.fr/bar/Transport/")]
public string PieceDynamique { get; set; }
[XmlElement(ElementName="SisraGoldenSource", Namespace="http://www.foo.fr/bar/Transport/")]
public string SisraGoldenSource { get; set; }
[XmlElement(ElementName="TypeDocSisra", Namespace="http://www.foo.fr/bar/Transport/")]
public string TypeDocSisra { get; set; }
[XmlElement(ElementName="TypeMime", Namespace="http://www.foo.fr/bar/Transport/")]
public string TypeMime { get; set; }
}
[XmlRoot(ElementName="fichiersAStocker", Namespace="http://www.foo.fr/bar/Repository")]
public class FichiersAStocker {
[XmlElement(ElementName="FichierIdentifie", Namespace="http://www.foo.fr/bar/Transport/")]
public FichierIdentifie FichierIdentifie { get; set; }
}
[XmlRoot(ElementName="StockerFichiers", Namespace="http://www.foo.fr/bar/Repository")]
public class StockerFichiers {
[XmlElement(ElementName="fichiersAStocker", Namespace="http://www.foo.fr/bar/Repository")]
public FichiersAStocker FichiersAStocker { get; set; }
[XmlAttribute(AttributeName="ns1", Namespace="http://www.w3.org/2000/xmlns/")]
public string Ns1 { get; set; }
[XmlAttribute(AttributeName="ns0", Namespace="http://www.w3.org/2000/xmlns/")]
public string Ns0 { get; set; }
}
}
Really frustrating mistake that took me half a day to solve :
notice how "NamespacesConstantes.NAMESPACE_MSS_TRANSPORT" is close to "NamespacesConstantes.NAMESPACE_TRANSPORT". Add some lazy autocompletion and you can fool yourself while defining the [XmlElement...] in the "FichiersAStocker" class.
Thanks for your help Matt, I noticed this mistake while i paste some of my code on https://dotnetfiddle.net/ ! :)

create xml from object without setting values in it c#

I want to convert a c# class to an xml file without declaring default values in it. If I declare values on every propery in the class I got it to work and the XML has all the properties in it. The primarydata is my class with properties in it.
var pD = new PrimaryData();
XmlSerializer serializerPrimaryData = new XmlSerializer(typeof(PrimaryData));
serializerPrimaryData.Serialize(File.Create(xmlLocation), pD,ns);
But I dont want to declare any values.
If i run this code I get just:
<?xml version="1.0"?>
<PrimaryData />
I don't get the properties in the class as you can see. So how can I get the properties in the class without declaring them to a default value?
Any suggestions?
I have followed this guide: https://codehandbook.org/c-object-xml/
But he is declaring default values to his class.
public class PrimaryData
{
public PrimaryData();
public string BatchId { get; set; }
public CurrentOperation CurrentOperation { get; set; }
public Heat Heat { get; set; }
public string MaterialId { get; set; }
public List<Operation> Operations { get; set; }
public OrderInfo OrderInfo { get; set; }
public Plate Plate { get; set; }
}
Just set default values.
public class Employee
{
public string FirstName { get; set; } = "";
public string LastName { get; set; } = "";
}
public static void Main(string[] args)
{
var employee = new Employee();
var sw = new StringWriter();
var se = new XmlSerializer(employee.GetType());
var tw = new XmlTextWriter(sw);
se.Serialize(tw, employee);
Console.WriteLine(sw.ToString());
Console.Read();
}
Result
<?xml version="1.0" encoding="utf-16"?>
<Employee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<FirstName />
<LastName />
</Employee>
Second solution is to set XmlElement(IsNullable = true)
public class Employee
{
[XmlElement(IsNullable = true)]
public string FirstName { get; set; }
[XmlElement(IsNullable = true)]
public string LastName { get; set; }
}
I have no clue what you are trying to do ...
XML serialization just makes a mirror of the object in different structure (aka XML - object will be represented by structured text).
If your class has no properties, nothing will be serialized to XML but only the base empty object.
My suggestion is to make a class with Dictionary<string, object> as property. Then you will be able to write into the Dictionary and serialize it.
But, it has some drawbacks. XML Serialization (if I remember correctly) does not support Dictionaries, so I would go with DataContract instead.
That might work :)
[DataContract]
public class PrimaryData
{
[DataMember(Name = "Data", Order = 0, IsRequired = true)]
public Dictionary<string, object> Data { get; set; }
}
You should add this annotation to your properties:
[XmlElement(IsNullable = true)]
public string Prop { get; set; }
The result in your xml should be something like this:
<Prop xsi:nil="true" />

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

XML parsing using attributes

I have XML-based config for application shortcuts bindings. i need to parse it.
<ShortcutBinding>
<ShortcutHandler Name ="Retail.Application.Documents.Outcome.Presentation.OutcomePresenter">
<Shortcut Name="EditHeader">
<Key>CTRL</Key>
<Key>F4</Key>
</Shortcut>
<Shortcut Name="EditItem">
<Key>F4</Key>
</Shortcut>
</ShortcutHandler>
</ShortcutBinding>
I know that .Net has attributes for deserializing XML into objects.
Can anyone write complete example for such deserialization, using attributes.
public class ShortcutBinding
{
public ShortcutHandler ShortcutHandler { get; set; }
}
public class ShortcutHandler
{
[XmlAttribute]
public string Name { get; set; }
[XmlElement("Shortcut")]
public List<Shortcut> Shortcuts { get; set; }
}
public class Shortcut
{
[XmlAttribute]
public string Name { get; set; }
[XmlElement("Key")]
public List<string> Keys { get; set; }
}
Deserializing:
XmlSerializer serializer = new XmlSerializer(typeof(ShortcutBinding));
var binding = (ShortcutBinding)serializer.Deserialize(XmlReader.Create(path));

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