C# XML deserialization issue - c#

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.

Related

Collect serialized items of multiple enumerable members to a same parent

Consider the following class:
[Serializable]
public class MyClass
{
[XmlAttribute("id")]
public int ID { get; set; }
[XmlArrayItem("User")]
public List<string> Users { get; set; }
[XmlArrayItem("Role")]
public List<string> Roles { get; set; }
}
Now I want to transform the class definition to get following expected result of XML serialization for an instance of the class:
<MyClass id="123">
<Access>
<User>User A</User>
<User>User B</User>
<User>User C</User>
<Role>Role A</Role>
<Role>Role B</Role>
<Role>Role C</Role>
</Access>
</MyClass>
Moreover it must be deserializable. I tried to apply [Xml Array("Access")] attribute to both Users and Roles properties, but an InvalidOperationException occurs.
It would be great if the question can be solved without IXmlSerializable implementation.
It looks like you just need to make an "Access" class to nest your Users/Roles.
[XmlRoot(ElementName="Access")]
public class Access {
[XmlElement(ElementName="User")]
public List<string> User { get; set; }
[XmlElement(ElementName="Role")]
public List<string> Role { get; set; }
}
[XmlRoot(ElementName="MyClass")]
public class MyClass {
[XmlElement(ElementName="Access")]
public Access Access { get; set; }
[XmlAttribute(AttributeName="id")]
public string Id { get; set; }
}

Simplest way to duplicate a pre-existing XML format in C#

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).

Is there a way to control the order of properties in JSON objects?

I'm using Entity Framework Core, and the generated class has its own properties, i.e.
DataModel.Agent.cs
public partial class Agent {
public virtual decimal Id
{
get;
set;
}
public virtual string Name
{
get;
set;
}
}
But I need other properties, so I declare them in another file:
Agent.cs
public partial class Agent
{
[NotMapped]
public dynamic Custom { get; set; }
}
The problem is that Agent.cs is compiled before DataModel.Agent.cs, so the compiler generates properties in this order: Custom, Id, Name, and the resulting JSON is weird.
I want it to be: Id, Name, Custom. In other words, I always want the DataModel class to come first.
EDIT: Just to clarify, the only objective is to make the JSON prettier by always putting the Id first, which is a very common pattern. This has absolutely no impact on how the application works.
Is there a way to force the compiler to always compile one of the files first?
Well you really shouldn't count on JSON property order BUT if using json.net
public class Account
{
public string EmailAddress { get; set; }
// appear last
[JsonProperty(Order = 1)]
public bool Deleted { get; set; }
[JsonProperty(Order = 2)]
public DateTime DeletedDate { get; set; }
public DateTime CreatedDate { get; set; }
public DateTime UpdatedDate { get; set; }
// appear first
[JsonProperty(Order = -2)]
public string FullName { get; set; }
}
http://www.newtonsoft.com/json/help/html/JsonPropertyOrder.htm

Dynamically adding a property to an entity framework object

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(); }
}
}

Deserialize an XML in C# generated by XStream from java

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.

Categories

Resources