My application has 2 parts, an android client and a windows print server coded in c#.
I used Xstream in java to convert my object to XML (in android). here's a part of it:
<ROOT>
<id>1</id>
<serial>92000</serial>
<date>2013/2/15</date>
<ITEMS>
<ITEM>
<name>/**SOMETHING**/</name>
<idd>/**SOMETHING**/</idd>
<pd>/**SOMETHING**/</pd>
<ed>/**SOMETHING**/</ed>
</ITEM>
<ITEM>
<name>/**SOMETHING**/</name>
<idd>/**SOMETHING**/</idd>
<pd>/**SOMETHING**/</pd>
<ed>/**SOMETHING**/</ed>
</ITEM>
<ITEM>
<name>/**SOMETHING**/</name>
<idd>/**SOMETHING**/</idd>
<pd>/**SOMETHING**/</pd>
<ed>/**SOMETHING**/</ed>
</ITEM>
</ITEMS>
</ROOT>
as you can see, I have 2 object types, one ROOT object type, and a nested list of second object type named ITEMS.
I can read the ROOT object's name,serial and date, but for the nested list of ITEMS object, it always return null.
the class for the Root class in c# is:
[XmlRoot("ROOT")]
public class ROOT_CLASS
{
[XmlElement("id")]
public string idVar{ get; set; }
[XmlElement("serial")]
public string serialVar{ get; set; }
[XmlElement("date")]
public string dateVar{ get; set; }
[XmlArray("ITEMS")]
[XmlArrayItem("ITEM")]
public List<NESTED_CLASS> oi { get; set; }
}
and here is the nested object class:
[XmlRoot("ITEM")]
public class NESTED_CLASS
{
[XmlElement("name")]
public string nameVV; { get; set; }
[XmlElement("idd")]
public string iddVV; { get; set; }
[XmlElement("pd")]
public string pdVV; { get; set; }
[XmlElement("ed")]
public string edVV; { get; set; }
}
okay, How can I deserialize the NESTED_CLASS list out of this xml? as I said, I always get a null out of it. please help me.
thanks...
Use XmlArray attribute
[XmlRoot(ElementName = "ROOT")]
public class Root
{
public int id { get; set; }
public int serial { get; set; }
public string date { get; set; }
[XmlArray(ElementName = "ITEMS")]
[XmlArrayItem("ITEM")]
public List<RootItem> Items { get; set; }
}
public class RootItem
{
public string name { get; set; }
public string idd { get; set; }
public string pd { get; set; }
public string ed { get; set; }
}
Instead of doing this manually, you could also generate your C# class by using xsd.exe. This may be easier, and faster in case this xml changes over time; and you don't have to worry about problems you are having now.
See Generate C# class from XML for an example on how to do that.
Note that if you are working with very large xml files, this approach may not be the best one as it loads the entire xml into memory. If this is the case, you might want to use this approach instead.
Related
XML to be deserialized:
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<changes next="296">
<change>
<objectid>E702C43C-E04B-450B-BEBC-76646AB299C5</objectid>
<parentid>ED98C97F-A202-48ED-AEEA-34362508A30B</parentid>
<objecttype>file</objecttype>
<listentype>remove</listentype>
</change>
<change>
<objectid>3A242975-CEF0-432B-A997-B33D85C138C8</objectid>
<parentid>ED98C97F-A202-48ED-AEEA-34362508A30B</parentid>
<objecttype>file</objecttype>
<listentype>add</listentype>
</change>
</changes>
Data models used:
[XmlRoot("changes")]
public class ChangeListener
{
public List<Change> Changes { get; set; }
}
[XmlRoot("change")]
public class Change
{
[XmlElement("objectid")]
public Guid objectid { get; set; }
[XmlElement("parentid")]
public Guid parentid { get; set; }
[XmlElement("objecttype")]
public string objecttype { get; set; }
[XmlElement("listentype")]
public string listentype { get; set; }
}
Deserialization code, here result is above xml in string format:
(ChangeListener)new XmlSerializer(typeof(ChangeListener)).Deserialize(new MemoryStream(Encoding.UTF8.GetBytes(result)))
But I am getting errors for this code; I also tried couple of things e.g. marked Changes property of ChangeListener class with [XmlElement("changes")] instead of marking class as xmlroot but it also did not worked.
Kindly suggest good approach for this issues.
The problem is that the Changes List in the ChangeListener is confusing the serializer because there's nothing called 'Changes' in the XML.
The only change we need to make is to annotate the declaration of Changes with [XmlElement("change")] as below:
[XmlRoot("changes")]
public class ChangeListener
{
[XmlElement("change")]
public List<Change> Changes { get; set; }
}
The XML shown then deserializes correctly.
The Class for mentioned XML should look like below.
[XmlRoot(ElementName="change")]
public class Change {
[XmlElement(ElementName="objectid")]
public string Objectid { get; set; }
[XmlElement(ElementName="parentid")]
public string Parentid { get; set; }
[XmlElement(ElementName="objecttype")]
public string Objecttype { get; set; }
[XmlElement(ElementName="listentype")]
public string Listentype { get; set; }
}
[XmlRoot(ElementName="changes")]
public class Changes {
[XmlElement(ElementName="change")]
public List<Change> Change { get; set; }
[XmlAttribute(AttributeName="next")]
public string Next { get; set; }
}
Try changing the type of objectid and parentid from Guid to string.
Share the error details if you still get errors.
I am working in C#, Visual Studio 2015, targeting .NET 4.5. We have existing systems (some written in Java, some legacy code in C++, etc.) that already exchange XML in particular formats. I have studied XMLSerializer, DataContractSerializer, and looked briefly at the ISerializable Interface. While I think I already know the answer (ISerializable), I figured I would see if anyone has any clever ideas or solutions for duplicating the XML format we need without coding it all ourselves. We have four different XML messages to duplicate, here is just one of them:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE message SYSTEM "work_request_20.dtd">
<message message_id="1005" message_dt="01/21/2008 09:50:23.221 AM" message_type="Work_Request" message_sub_type="New" message_dtd_version_number="2.0">
<header>
<from_application_id>3367e115-c873-4ac9-a1dd-7e45231dc3d5</from_application_id>
<to_application_id>35e0cca2-e423-4ffe-ba07-7d056775c228</to_application_id>
</header>
<body>
<work_request requisition_number="REQ44">
<client client_id="44">
<first_name>Barak</first_name>
<last_name>Obama</last_name>
</client>
<patient patient_id="4444" patient_species="CANINE" patient_gender="MALE_INTACT">
<patient_name>Bo</patient_name>
<patient_breed>Portuguese Water Dog</patient_breed>
<patient_birth_dt>04/04/2004</patient_birth_dt>
<patient_weight patient_weight_uom="lbs">
<weight>44.4</weight>
</patient_weight>
</patient>
<doctor>
<first_name>Surgeon</first_name>
<last_name>General</last_name>
</doctor>
<service_add>
<service_cd>ALB</service_cd>
<service_cd>GLU</service_cd>
<service_cd>BUN</service_cd>
</service_add>
</work_request>
</body>
</message>
If anyone can suggest any brilliant shortcuts as compared to the obvious solution, we would be forever grateful.
Thanks in advance.
Serializing with XmlSerializer is likely going to be the easiest solution. If classes auto-generated by xsd.exe are too bloated, you can use another code generation tool such as https://xmltocsharp.azurewebsites.net/ to generate them for you -- or even do it yourself manually.
For instance, I generated the following types using https://xmltocsharp.azurewebsites.net/ then made a few manual tweaks that are mentioned in comments:
[XmlRoot(ElementName="header")]
public class Header {
// I modified the types of these properties from string to Guid
[XmlElement(ElementName="from_application_id")]
public Guid From_application_id { get; set; }
[XmlElement(ElementName="to_application_id")]
public Guid To_application_id { get; set; }
}
[XmlRoot(ElementName="client")]
public class Client {
[XmlElement(ElementName="first_name")]
public string First_name { get; set; }
[XmlElement(ElementName="last_name")]
public string Last_name { get; set; }
[XmlAttribute(AttributeName="client_id")]
public string Client_id { get; set; }
}
[XmlRoot(ElementName="patient_weight")]
public class Patient_weight {
// I changed weight from string to decimal
[XmlElement(ElementName="weight")]
public decimal Weight { get; set; }
[XmlAttribute(AttributeName="patient_weight_uom")]
public string Patient_weight_uom { get; set; }
}
[XmlRoot(ElementName="patient")]
public class Patient {
[XmlElement(ElementName="patient_name")]
public string Patient_name { get; set; }
[XmlElement(ElementName="patient_breed")]
public string Patient_breed { get; set; }
[XmlElement(ElementName="patient_birth_dt")]
public string Patient_birth_dt { get; set; }
[XmlElement(ElementName="patient_weight")]
public Patient_weight Patient_weight { get; set; }
[XmlAttribute(AttributeName="patient_id")]
public string Patient_id { get; set; }
[XmlAttribute(AttributeName="patient_species")]
public string Patient_species { get; set; }
[XmlAttribute(AttributeName="patient_gender")]
public string Patient_gender { get; set; }
}
[XmlRoot(ElementName="doctor")]
public class Doctor {
[XmlElement(ElementName="first_name")]
public string First_name { get; set; }
[XmlElement(ElementName="last_name")]
public string Last_name { get; set; }
}
[XmlRoot(ElementName="work_request")]
public class Work_request {
[XmlElement(ElementName="client")]
public Client Client { get; set; }
[XmlElement(ElementName="patient")]
public Patient Patient { get; set; }
[XmlElement(ElementName="doctor")]
public Doctor Doctor { get; set; }
// I simplied this into a list of strings.
[XmlArray(ElementName="service_add")]
[XmlArrayItem("service_cd")]
public List<string> Service_add { get; set; }
[XmlAttribute(AttributeName="requisition_number")]
public string Requisition_number { get; set; }
}
[XmlRoot(ElementName="body")]
// I renamed this to WorkRequestBody
public class WorkRequestBody
{
[XmlElement(ElementName="work_request")]
public Work_request Work_request { get; set; }
}
[XmlRoot(ElementName="message")]
// I made this generic to account for multiple types of messge.
public class Message<T> where T : class, new()
{
[XmlElement(ElementName="header")]
public Header Header { get; set; }
[XmlElement(ElementName="body")]
public T Body { get; set; }
[XmlAttribute(AttributeName="message_id")]
public string Message_id { get; set; }
[XmlAttribute(AttributeName="message_dt")]
public string Message_dt { get; set; }
[XmlAttribute(AttributeName="message_type")]
public string Message_type { get; set; }
[XmlAttribute(AttributeName="message_sub_type")]
public string Message_sub_type { get; set; }
[XmlAttribute(AttributeName="message_dtd_version_number")]
public string Message_dtd_version_number { get; set; }
}
Using these types, I can now deserialize and re-serialize your XML into a Message<WorkRequestBody> and the resulting re-serialized XML is equivalent to the original XML, according to XNode.DeepEquals(). Sample fiddle.
To include a <!DOCTYPE ...> in the re-serialized XML, see this question.
Implementing IXmlSerializable for the root object is roughly the same difficulty as manually reading and writing your entire object graph with an XmlReader and XmlWriter. It's certainly possible but will require more work that using XmlSerializer. You'll still need to design POCOs to hold the data in memory, so it will be easier to use a serializer to read and write those POCOs automatically whenever possible. See here for a guide on how to do it correctly.
Reading and writing with LINQ to XML would represent an intermediate level of difficulty.
Finally, DataContractSerializer is not appropriate since there is no way to indicate that certain c# properties should be serialized as XML attributes (source).
I have a class like this:
public class Empresa
{
public string Nombre { get; set; }
public string NIT { get; set; }
public string NombreRepresentanteLegal { get; set; }
public string TelefonoRepresentanteLegal { get; set; }
public string NombreContacto { get; set; }
public string TelefonoContacto { get; set; }
}
However in my app, I want the users to be able to add custom properties, for example twitter handle, however I havent found documentation in how to do that, I heard about the EAV model, but thats not performant
You could store the additional data as XML into an XML column, and have the client deserialize / serialize the meta-data appropriately. Xml can be a viable solution for when you don't know the structure of the data, or if the structure can be altered at run-time.
You're also able to INDEX the XML to help with shredding / querying, so performance can be maintained while processing large xml documents.
Your class could contain, an ExtraPropertiesElement, that takes the XML string, and parses it into an XElement, which you could then utilize XPath, to query for the requested xml element/attribute.
One problem with this approach, is that all additional properties are stored in XML in the database, and it's not as easy to perform queries against the data. It's straightforward to do so, but it's not as simple as selecting a column name from a table.
You can read more about the XML Data Type and the uses here.
You can also read up on how to query XML column stores here.
public class Empresa
{
public string Nombre { get; set; }
public string NIT { get; set; }
public string NombreRepresentanteLegal { get; set; }
public string TelefonoRepresentanteLegal { get; set; }
public string NombreContacto { get; set; }
public string TelefonoContacto { get; set; }
[Column(TypeName="xml")]
public string ExtraProperties { get; set; }
[NotMapped]
public XElement ExtraPropertiesElement
{
get { return XElement.Parse(ExtraProperties ); }
set { ExtraProperties = value.ToString(); }
}
}
My Classes:
public class SectionDto
{
[XmlAttribute]
public int Id { get; set; }
[XmlElement("subSection1", typeof(departmentDto)),
XmlElement("subSection2", typeof(divisionDto))]
public List<CommonSubSectionDto> SubSection { get; set; }
}
public class CommonSubSectionDto
{
}
public class DepartmentDto : CommonSubSectionDto
{
[XmlAttribute]
public int Id { get; set; }
[XmlElement]
public string Summary { get; set; }
}
public class DivisionDto : CommonSubSectionDto
{
[XmlAttribute]
public int Id { get; set; }
[XmlElement]
public string Name { get; set; }
}
The XML looks like the following:
<root>
<Section>
<SubSection1 Id="123">
<Summary> Summary 123 </Summary>
<SubSection1 />
<SubSection1 Id="124">
<Summary> Summary 124 </Summary>
<SubSection1 />
<SubSection2 Id="987">
<Name> Division Name </Name>
<SubSection2 />
<section>
...
</root>
So i would like it so instead of the inherited classed being given individual names such as "SubSection1" and "SubSection2", i would like it to be that its called "SubSection".
Is this possible? If so please could someone advise?
Else is there an alternative ??
I was also thinking to remove my inherting classes and replace it with a single class called SubSection and it has both the elements, however one of the elements Summary or Name will be an empty xml element, but i wanted to see what the practices are for this scenario, and to find alternative solution.
Thank you for your help.
Kush
By design, there must be a way for the runtime to know to which type an xml element should be deserialized. If the xml tag is the same for both DTO, when deserializing, the system can't infer the appropriate target type. But you can change a little bit of it. The following definitions :
public class SectionDto
{
[XmlAttribute]
public int Id { get; set; }
public List<SubSection> SubSections { get; set; }
}
[XmlInclude(typeof(DepartmentDto))]
[XmlInclude(typeof(DivisionDto))]
public abstract class SubSection
{
[XmlAttribute]
public int Id { get; set; }
}
public class DepartmentDto : SubSection
{
[XmlElement]
public string Summary { get; set; }
}
public class DivisionDto : SubSection
{
[XmlElement]
public string Name { get; set; }
}
Give this xml :
<SectionDto xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Id="0">
<SubSections>
<SubSection xsi:type="DepartmentDto" Id="123">
<Summary>Summary 123</Summary>
</SubSection>
<SubSection xsi:type="DepartmentDto" Id="124">
<Summary>Summary 124</Summary>
</SubSection>
<SubSection xsi:type="DivisionDto" Id="987">
<Name>Division Name</Name>
</SubSection>
</SubSections>
</SectionDto>
But it's pretty much the same problem that was moved to the xsi:type attribute.
With this :
public class SubSection
{
[XmlAttribute]
public int Id { get; set; }
[XmlElement]
public string Summary { get; set; }
[XmlElement]
public string Name { get; set; }
}
You get this xml :
<SectionDto xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Id="0">
<SubSections>
<SubSection Id="123">
<Summary>Summary 123</Summary>
</SubSection>
<SubSection Id="124">
<Summary>Summary 124</Summary>
</SubSection>
<SubSection Id="987">
<Name>Division Name</Name>
</SubSection>
</SubSections>
</SectionDto>
Which was one of your suggestion but you might need to write more code when deserializing to infer by yourself the appropriate type of your objects according to which properties are set. I would personally choose the last version only if I have to produce xml for another system (so I would never have to deserialize in my application) but the strongly typed version might get my vote if I had to load the xml data afterwards.
I have the following XML:
<Root>
<EventSet>
<Event>
<id>12345</id>
<rant>
<localTime>
<dst>true</dst>
<time>7/2/2012 14:30</time>
</localtime>
<randomRant>
<random>to illustrate point</random>
<rant>help me!</rant>
</randomRant>
</rant>
</Event>
<Event>/*another event*/</Event>
<Event>/*another event*/</Event> //etc
</EventSet>
</Root>
I want to map this to:
[Serializable]
public class Events
{
public List<Event> events { get; set; }
}
[Serializable]
public class Event
{
public int id { get; set; }
public Rant rant { get; set; } //this is where I get confused
}
QUESTION: How do I serialize the tags within <rant>? Do I continue to make serialized classes of the parent until the child tags have no children? For example, below:
[Serializable]
public class Rant
{
public LocalTime localTime { get; set; }
public RandomRant randomRant { get; set; }
}
[Serializable]
public class LocalTime
{
public bool dst { get; set; }
public DateTime time { get; set; }
}
[Serializable]
public class RandomRant
{
public string random { get; set; }
public string rant { get; set; }
}
Or is there a better approach?
EDIT: A given event has one and only one id, and one and only one rant. For the sake of my question, assume my types are valid. I am looking to deserialize nested XML into an object.
The example you gave seems fine to me.
As for the time values, the date format in your example is not compatible with xsd:dateTime, so you can't just do
public DateTime time { get; set; }
This will not be serialized. Although you can hack this using a custom XmlSerializer, a more simple approach is to use:
[XmlIgnore]
public DateTime _time {
get { return DateTime.ParseExact(this.time, "MM/dd/YYYY HH:mm", CultureInfo.InvariantCulture);} // or use some specific culture here.
}
[XmlElement]
public string time { get; set; }
UPDATE:
public List<Event> events will be de/serialized as:
<events>
<Event></Event>
<Event></Event>
<Event></Event>
</events>
You can make it as:
[XmlElement("Event")]
public List<Event> events {get; set}
and it will be serialized as
<Event></Event>
<Event></Event>
<Event></Event>
without wrapper.
Or, using:
[XmlArray("EventSet")]
[XmlArrayItem("Event")]
public List<Event> events {get; set}
will be serialized as described in the example
<EventSet>
<Event></Event>
<Event></Event>
</EventSet>
And of course the root element:
[XmlRoot("Root")]
public class RootElement{
[XmlArray("EventSet")]
[XmlArrayItem("Event")]
public List<Event> events {get; set}
}