Multiple XmlElements referencing to the same property in c# - c#

I have following two files and Because both files having the same structure, I would like to keep one class and refer it multiple times.
XML File1:
<?xml version="1.0" encoding="utf-16"?>
<TRANSFERS>
<TR_DOCTOR_MR>
<REFDOC_CODE>MR Code</REFDOC_CODE>
<REFDOC_HOSPITALKEY>Hospital 1</REFDOC_HOSPITALKEY>
<REFDOC_RIZIV>Riziv 1</REFDOC_RIZIV>
<REFDOC_NAME>Name 1</REFDOC_NAME>
<REFDOC_FNAME>FName 1</REFDOC_FNAME>
<REFDOC_TITLE>Mr.</REFDOC_TITLE>
<REFDOC_INITIALS>RI11</REFDOC_INITIALS>
<REFDOC_FREEFIELD1>FF1</REFDOC_FREEFIELD1>
<REFDOC_FREEFIELD2>FF2</REFDOC_FREEFIELD2>
<REFDOC_FREEFIELD3>FF3</REFDOC_FREEFIELD3>
</TR_DOCTOR_MR>
</TRANSFERS>
XML File2:
<?xml version="1.0" encoding="utf-16"?>
<TRANSFERS>
<TR_DOCTOR_RESP>
<ATDOC_CODE>Ref Doctor</ATDOC_CODE>
<ATDOC_HOSPITALKEY>Hosp 2</ATDOC_HOSPITALKEY>
<ATDOC_RIZIV>Riziv 2</ATDOC_RIZIV>
<ATDOC_NAME>Name 2</ATDOC_NAME>
<ATDOC_FNAME>FName 2</ATDOC_FNAME>
<ATDOC_TITLE>Mr.</ATDOC_TITLE>
<ATDOC_INITIALS>AI22</ATDOC_INITIALS>
<ATDOC_FREEFIELD1>FF1</ATDOC_FREEFIELD1>
<ATDOC_FREEFIELD2>FF2</ATDOC_FREEFIELD2>
<ATDOC_FREEFIELD3>FF3</ATDOC_FREEFIELD3>
</TR_DOCTOR_RESP>
</TRANSFERS>
Here is the C# code:
[XmlRoot("TRANSFERS")]
public class TransferXml
{
[XmlElement("TR_DOCTOR_MR")]
public TransferDoctorXml TR_DOCTOR_MR { get; set; }
[XmlElement("TR_DOCTOR_RESP")]
public TransferDoctorXml TR_DOCTOR_RESP { get; set; }
}
public class TransferDoctorXml
{
[XmlElement("ATDOC_CODE")]
[XmlElement("REFDOC_CODE")]
public string Code { get; set; }
[XmlElement("ATDOC_HOSPITALKEY")]
[XmlElement("REFDOC_HOSPITALKEY")]
public string HospitalKey { get; set; }
[XmlElement("ATDOC_RIZIV")]
[XmlElement("REFDOC_RIZIV")]
public string Riziv { get; set; }
[XmlElement("ATDOC_NAME")]
[XmlElement("REFDOC_NAME")]
public string LastName { get; set; }
[XmlElement("ATDOC_FNAME")]
[XmlElement("REFDOC_FNAME")]
public string FirstName { get; set; }
[XmlElement("ATDOC_TITLE")]
[XmlElement("REFDOC_TITLE")]
public string Title { get; set; }
[XmlElement("ATDOC_INITIALS")]
[XmlElement("REFDOC_INITIALS")]
public string Initials { get; set; }
[XmlElement("ATDOC_FREEFIELD1")]
[XmlElement("REFDOC_FREEFIELD1")]
public string FreeField1 { get; set; }
[XmlElement("ATDOC_FREEFIELD2")]
[XmlElement("REFDOC_FREEFIELD2")]
public string FreeField2 { get; set; }
[XmlElement("ATDOC_FREEFIELD3")]
[XmlElement("REFDOC_FREEFIELD3")]
public string FreeField3 { get; set; }
}
I want both files refer to the same C# class for deserialization to avoid duplicates and have code clean and maintainable. However, it doesn't work like this. I have googled a lot to find out if this is possible. But couldn't find it. Can anyone please help me?
string DoctorMr = File.ReadAllText("C:\\TEMP\\TransferDoctorMr.xml");
TransferXml drXml = XmlHelper<TransferXml>.DeserializeObject(DoctorMr);
Thank you.

Related

How to parse XML with several Attributes and an options list

I have an XML file that looks something similar to this:
<root>
<data label="product data" min="0" max="10">
<option>
<id>1</id>
<name>Name1</name>
</option>
<option>
<id>2</id>
<name>Name2</name>
</option>
<option>
<id>3</id>
<name>Name3</name>
</option>
</data>
</root>
I need to retreive both data attributes and the option list.
I tried this:
[XmlRoot(ElementName = "root")]
public class Data
{
// Retreive data attributes
[XmlElement(ElementName = "data")]
public Options Attributes { get; set; }
// Retrieve option list
[XmlArray("data")]
[XmlArrayItem("option", Type = typeof(GeneralOptions))]
public GeneralOptions[] Options { get; set; }
}
Optional classes:
Options
public class Options
{
[XmlAttribute("label")]
public string Label{ get; set; }
[XmlAttribute("min")]
public string Min{ get; set; }
[XmlAttribute("max")]
public string Max{ get; set; }
}
GeneralOptions
public class GeneralOptions
{
[XmlElement(ElementName = "id")]
public string Id { get; set; }
[XmlElement(ElementName = "name")]
public string Name{ get; set; }
}
But when I try to deserialize the object, it launches the following exception:
The XML element 'data' from namespace '' is already present in the current scope. Use XML attributes to specify another XML name or namespace for the element.
I imagine the problem is that I'm trying to retreive the same element "twice". But I need to retreive both things. I cannot use the [Attribute] thing because there are several Attributes to retreive, and I need to do this with several XML Elements with the same format and I want to reuse it.
So, how can I retreive both of them?
You'll need to restructure it slightly:
[XmlRoot("root")]
public class Data
{
[XmlElement("data")]
public OptionsData Options { get; set; }
}
public class OptionsData
{
[XmlAttribute("label")]
public string Label { get; set; }
[XmlAttribute("min")]
public string Min { get; set; }
[XmlAttribute("max")]
public string Max { get; set; }
[XmlElement("option")]
public List<GeneralOptions> Items { get; } = new List<GeneralOptions>();
}
public class GeneralOptions
{
[XmlElement("id")]
public string Id { get; set; }
[XmlElement("name")]
public string Name { get; set; }
}
I suggest using xmltocsharp or anyother tools to convert the XML to C# Models within seconds... (eliminates all manual mistakes)
As mentioned by #canton7, another easy method is using Visual Studio: Edit -> Paste Special -> Paste XML As Classes
[XmlRoot(ElementName="option")]
public class Option {
[XmlElement(ElementName="id")]
public string Id { get; set; }
[XmlElement(ElementName="name")]
public string Name { get; set; }
}
[XmlRoot(ElementName="data")]
public class Data {
[XmlElement(ElementName="option")]
public List<Option> Option { get; set; }
[XmlAttribute(AttributeName="label")]
public string Label { get; set; }
[XmlAttribute(AttributeName="min")]
public string Min { get; set; }
[XmlAttribute(AttributeName="max")]
public string Max { get; set; }
}
[XmlRoot(ElementName="root")]
public class Root {
[XmlElement(ElementName="data")]
public Data Data { get; set; }
}

C# ignore parent nodes in xml deserialization

this is my first post here and as can you can imagine, i'm just a beginner in c#. So here's my question:
I'm deserializing a given xml to a custom class with XmlSerializer.
XML:
<epg>
<program start="20160404234500" stop="20160405001000" channel="281479340566592">
<eventid>604042345</eventid>
<titles>
<title>Schlauberger - Quizzen, was Spaß macht! (1)</title>
</titles>
<events>
<event>27. Schlauberger - Quizzen, was Spaß macht!</event>
</events>
<descriptions>
<description>27. Schlauberger - Quizzen, was Spaß macht!</description>
</descriptions>
</program>
<program start="20160504234500" stop="20160505001000" channel="281479340566587">
<eventid>604042348</eventid>
<title>Schlauberger - Quizzen, was Spaß macht! (2)</title>
<event>28. Schlauberger - Quizzen, was Spaß macht!</event>
<description>28. Schlauberger - Quizzen, was Spaß macht!</description>
</program>
Custom C# class:
public class Titles
{
[XmlElement("title")]
public string Title { get; set; }
}
public class SubTitles
{
[XmlElement("event")]
public string SubTitle { get; set; }
}
public class Descriptions
{
[XmlElement("description")]
public string Description { get; set; }
}
public class Program
{
[XmlElement("eventid")]
public string EventID { get; set; }
[XmlElement("titles")]
public Titles Titles { get; set; }
[XmlElement("events")]
public SubTitles SubTitles { get; set; }
[XmlElement("descriptions")]
public Descriptions Descriptions { get; set; }
[XmlAttribute("start")]
public string Start { get; set; }
[XmlAttribute("stop")]
public string Stop { get; set; }
[XmlAttribute("channel")]
public string Channel { get; set; }
[XmlElement("title")]
public string Title { get; set; }
[XmlElement("event")]
public string SubTitle { get; set; }
[XmlElement("description")]
public string Description { get; set; }
}
[XmlRoot(ElementName = "epg"), XmlType("epg")]
public class epg
{
[XmlElement("program")]
public List<Program> Program { get; set; }
}
No problem so far. But as you can see, because "title", "event" and "description" is sometimes nested in a majority and sometimes not, i can access the properties in my later code sometimes by a list and sometimes directly. This makes the code really inconvenient.
So is it somehow possible to ignore the majorities and always use the single nodes instead?
You could add some helper functions (or properties) to your Program class, e.g.:
public class Program
{
public Titles Titles { get; set; }
public string Title { get; set; }
public string GetTitle()
{
if (Titles != null)
{
return Titles.Title;
}
else
{
return Title;
}
}
}

Deserializing XML into objects

I have the following XML which I need to deserialize:
<?xml version="1.0" encoding="UTF-8" ?>
<event code="2wuj0ticofhzt" self="/events/2wuj0ticofhzt" revision="1260234836">
<name>Test Event 2013</name>
<partner-settings>
<partner-setting>
<registration-type code="1yfopbwhk" link="/registration-types/1yfopbwhk" />
<personnel code="3eclag1dsrjfi">
<free-badges>unlimited</free-badges>
</personnel>
<personnel code="0nxgc6mfec8yh">
<free-badges>3</free-badges>
</personnel>
</partner-setting>
<partner-setting>
<registration-type code="1ygg67prw" link="/registration-types/1ygg67prw" />
</partner-setting>
</partner-settings>
</event>
Here are my classes that I have created. (I only need to deserialize the fields I have in my classes.):
[XmlRoot("event")]
public class Event
{
[XmlAttribute("code")]
public string Code { get; set; }
[XmlAttribute("name")]
public string EventName { get; set; }
[XmlArray("partner-settings")]
public List<PartnerSetting> PartnerSettings { get; set; }
}
[XmlType("partner-setting")]
public class PartnerSetting
{
[XmlElement("registration-type")]
public RegistrationType RegistrationType { get; set; }
[XmlArray("personnel")]
public List<Personnel> Personnel { get; set; }
}
[XmlRoot("registration-type")]
public class RegistrationType
{
[XmlAttribute("code")]
public string Code { get; set; }
[XmlAttribute("name")]
public string RegistrationTypeName { get; set; }
[XmlElement("type")]
public string Type { get; set; }
}
[XmlType("personnel")]
public class Personnel
{
[XmlAttribute("code")]
public string Code { get; set; }
[XmlElement("free-badges")]
public int FreeBadges { get; set; }
}
When I currently deserialize the above XML it all works except from the Personnel object where I get 0 returned when I'm expecting to see 2.
I'm not doing anything differently when I'm trying to return a personnel list (i.e. XMLArray attribute, return a List) to a partner setting list but for some reason it won't deserialize.
You need to change the attribute into XmlElement to force each element in the list to be rendered as a single XML element:
[XmlElement("personnel")]
public List<Personnel> Personnel { get; set; }

Nested XML deserialization to c# gives null values

I have searched alot to find a solution, but couldn't come up with one after all.
So I hope that someone here can help me out.
I have an xml structure:
<?xml version="1.0" encoding="utf-8" ?>
<ReleaseNoteConfig>
<ReleaseNoteProperties>
<TemplateLocation>Path to the template location</TemplateLocation>
<TemplateFileName>wordfile.docx</TemplateFileName>
<OutLocation>Path to the outlocation</OutLocation>
<ReleaseName>Stackoverflow</ReleaseName>
<ChangeOrder>1234</ChangeOrder>
<ChangesHeader>Change ID</ChangesHeader>
<ProblemsHeader>Problem ID</ProblemsHeader>
<Environment>Test</Environment>
</ReleaseNoteProperties>
<DocProperties>
<AuthorReleaseNote>Vincent Verweij</AuthorReleaseNote>
<CustomerResponsible>Customer name</CustomerResponsible>
<PlannedTestInstallDate>-</PlannedTestInstallDate>
<PlannedAccInstallDate>30/04/2014</PlannedAccInstallDate>
<PlannedProdInstallDate>07/05/2014</PlannedProdInstallDate>
<TestInstallDate>-</TestInstallDate>
<AccInstallDate>-</AccInstallDate>
<ProdInstallDate>-</ProdInstallDate>
<TestInstaller>-</TestInstaller>
<AccInstaller>-</AccInstaller>
<ProdInstaller>-</ProdInstaller>
<UrlProjectPortal>Url to project site</UrlProjectPortal>
</DocProperties>
<SpecialProperties>
<Customer_x0020_Name>Customer company name</Customer_x0020_Name>
<Customer_x0020_Reference>No reference</Customer_x0020_Reference>
<Approval_x0020_Date>15/04/2014</Approval_x0020_Date>
<MyFerranti_x0020_Reference>1234</MyFerranti_x0020_Reference>
<Project_x0020_ID>Proj000001</Project_x0020_ID>
</SpecialProperties>
</ReleaseNoteConfig>
I have used an online generator to create a json from my XML and then json2csharp to obtain the classes that I need. So eventually it came up with this c# code:
public class ReleaseNoteProperties
{
public string TemplateLocation { get; set; }
public string TemplateFileName { get; set; }
public string OutLocation { get; set; }
public string ReleaseName { get; set; }
public string ChangeOrder { get; set; }
public string ChangesHeader { get; set; }
public string ProblemsHeader { get; set; }
public string Environment { get; set; }
}
public class DocProperties
{
public string AuthorReleaseNote { get; set; }
public string CustomerResponsible { get; set; }
public string PlannedTestInstallDate { get; set; }
public string PlannedAccInstallDate { get; set; }
public string PlannedProdInstallDate { get; set; }
public string TestInstallDate { get; set; }
public string AccInstallDate { get; set; }
public string ProdInstallDate { get; set; }
public string TestInstaller { get; set; }
public string AccInstaller { get; set; }
public string ProdInstaller { get; set; }
public string UrlProjectPortal { get; set; }
}
public class SpecialProperties
{
public string Customer_x0020_Name { get; set; }
public string Customer_x0020_Reference { get; set; }
public string Approval_x0020_Date { get; set; }
public string MyFerranti_x0020_Reference { get; set; }
public string Project_x0020_ID { get; set; }
}
public class ReleaseNoteConfig
{
public ReleaseNoteProperties ReleaseNoteProperties { get; set; }
public DocProperties DocProperties { get; set; }
public SpecialProperties SpecialProperties { get; set; }
}
This code will read my XML file and deserializes the XML to the objects.
public ReleaseNoteConfig ReadXmlToObject(string xmlPath)
{
StringReader stream = null;
XmlTextReader reader = null;
var xDocument = XDocument.Load(xmlPath);
string xml = xDocument.ToString();
try
{
// Serialise the object
XmlSerializer serializer = new XmlSerializer(typeof(ReleaseNoteConfig));
// Read the XML data
stream = new StringReader(xml);
// Create a reader
reader = new XmlTextReader(stream);
// Convert reader to an object
return (ReleaseNoteConfig)serializer.Deserialize(reader);
}
catch
{
return null;
}
finally
{
if (stream != null) stream.Close();
if (reader != null) reader.Close();
}
}
Now the problem; when I debug in Visual Studio, I see that two of the three objects are filled. Here is a screenshot that I took from the debugger:
http://www.smartus.be/xmlProblem/debugger.png
As you can see, DocProperties and ReleaseNoteProperties are filled correctly but SpecialProperties has all null values. First I thought it had something to do with the underscores, but when I added an underscore to a property in DocProperties it was also filled correctly.
I also tried adding the attributes above the properties like XmlElement, XmlRoot etc. but that didn't help either.
I also double checked for typos but it seems that there are none...
Hopefully you guys can help me out on this one.
Thanks in advance.
Vincent
Change your SpecialProperties class to this:
public class SpecialProperties
{
[XmlElement("Customer Name")]
public string CustomerName { get; set; }
[XmlElement("Customer Reference")]
public string CustomerReference { get; set; }
[XmlElement("Approval Date")]
public string ApprovalDate { get; set; }
[XmlElement("MyFerranti Reference")]
public string MyFerrantiReference { get; set; }
[XmlElement("Project ID")]
public string ProjectID { get; set; }
}
You can change the property names if you want, the important parts are the XmlElement attributes.
I have checked your code.
Can you Remove the underscores in the "Customer_x0020_Name" ? at the same time you need to change the property names in the class.
Its going to work.
Will this suggestions helps you?
i have checked it .. its working.
I am not sure , whether the tag name with underscore is legal or not.
Mark the answer , if it has solved you question

Unable to Deserialize XML

I have the following code but unable to deserialize, can you see where I'm going wrong? It only catch the first record on the first array item.
[XmlRootAttribute("Booking")]
public class Reservation
{
[XmlArray("Included")]
[XmlArrayItem("Meals")]
public Meals[] Food { get; set; }
[XmlArrayItem("Drinks")]
public Drinks[] Drink { get; set; }
}
public class Meals
{
[XmlAttribute("Breakfast")]
public string Breakfast { get; set; }
[XmlAttribute("Lunch")]
public string Lunch { get; set; }
[XmlAttribute("Dinner")]
public string Dinner { get; set; }
}
public class Drinks
{
[XmlAttribute("Soft")]
public string Softs { get; set; }
[XmlAttribute("Beer")]
public string Beer { get; set; }
[XmlAttribute("Wine")]
public string Wine { get; set; }
}
Here's the associated XML
<?xml version="1.0" standalone="yes"?>
<Booking>
<Included>
<Meals
Breakfast="True"
Lunch="True"
Dinner="False">
</Meals>
<Drinks
Soft="True"
Beer="False"
Wine="False">
</Drinks>
</Included>
<Included>
<Meals
Breakfast="True"
Lunch="False"
Dinner="False">
</Meals>
<Drinks
Soft="True"
Beer="True"
Wine="True">
</Drinks>
</Included>
</Booking>
I'm a bit of a newbie so any help would be great, unfortunately after trawling through the many exmaples you already have online I still haven't been able to figure this out.
Use the following example and apply this syntax in ListItem array,
[XmlType("device_list")]
[Serializable]
public class DeviceList {
[XmlAttribute]
public string type { get; set; }
[XmlElement( "item" )]
public ListItem[] items { get; set; }
}
following link contains all the syntax & attributes
http://msdn.microsoft.com/en-us/library/2baksw0z.aspx
I see no obvious way your class structure could be matched to the XML document. The underlying organizations seem to be quite different.
The following class hierarchy could be easily deserialized from the XML document you provide (assuming your document covers the general case) :
[Serializable]
[XmlRoot("Booking")]
public class Booking : List<Included>
{
}
[Serializable]
public class Included
{
public Meals Meals { get; set; }
public Drinks Drinks { get; set; }
}
public class Meals
{
[XmlAttribute("Breakfast")]
public string Breakfast { get; set; }
[XmlAttribute("Lunch")]
public string Lunch { get; set; }
[XmlAttribute("Dinner")]
public string Dinner { get; set; }
}
public class Drinks
{
[XmlAttribute("Soft")]
public string Softs { get; set; }
[XmlAttribute("Beer")]
public string Beer { get; set; }
[XmlAttribute("Wine")]
public string Wine { get; set; }
}
Then, deserialization code would be : (serializedObject is the string containing your serialized object)
XmlSerializer ser = new XmlSerializer(typeof (string));
XmlReader reader = XmlTextReader.Create(new StringReader(serializedObject));
var myBooking = ser.Deserialize(reader) as Booking;

Categories

Resources