How to Deserialize XML with Same Attribute Name in 2 Different Element? - c#

My class definition:
[Serializable]
public class MyClass
{
[XmlAttribute(AttributeName = "ID")] //Problem is here. same attr name ID.
public int XXX_ID { get; set; }
[XmlElement(ElementName = "XXX")]
public string XXX_Value{ get; set; }
[XmlAttribute(AttributeName = "ID")] //Problem is here. same attr name ID.
public int YYY_ID { get; set; }
[XmlElement(ElementName = "YYY")]
public string YYY_Value { get; set; }
}
My XML:
<MyClass>
<XXX ID="123">Some Values</XXX>
<YYY ID="567">Some Values</YYY>
</MyClass>
My Problem:
I want to de-serialize the above XML into an object.
During the runtime, an error has occurred, it is not allowed to have same attribute name in 2 different elements and under the same root.
How to solve this problem?
P/S: I cannot change the XML, I am not the owner of it.
Thanks in advance.

To do that you either need to do the (de)serialization manually, or you need to DTO to have roughly the same layout as the xml. For example:
public class Something { // need a name here to represent what this is!
[XmlAttribute] public int ID {get;set;}
[XmlText] public string Value {get;set;}
}
then
public class MyClass {
public Something XXX {get;set;}
public Something YYY {get;set;}
}

Related

How to make JsonProperty() attribute have a dynamic propertyName?

Essentially I have a Root class to serialize/deserialize JSON data that looks like this:
public class Root
{
[JsonIgnore]
public string JoystickName { get; set; }
public Root(string joystickName)
{
JoystickName = joystickName;
}
[JsonProperty("g")]
public string G { get; set; }
[JsonProperty(PropertyName = JoystickName)] // This line produces error
public DxsJoyConfig Joystick { get; set; }
}
*EDIT:
How do I change the property name at runtime?
I'm also running into an object reference error required at the indicated line. How can I make an instance of JoystickName within the attribute?

C# XML deserialization issue

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.

XML deserialization cannot resolve attribute type

I am working on a project where I communicate with an API service through both REST and Comet semantics.
XML
So, the problem at hand.
I receive this error when I try to deserialize the following XML.
Error at resolve type "xsi:SubscriptionEvent"
NetBike.Xml.TypeResolvers.XmlTypeResolveException
Note: I use NetBike, but the error exist in the default xml formatter too
<?xml version="1.0" encoding="UTF-8"?>
<xsi:Event
xsi1:type="xsi:SubscriptionEvent"
xmlns:xsi="http://schema.broadsoft.com/xsi"
xmlns:xsi1="http://www.w3.org/2001/XMLSchema-instance">
<xsi:eventID>0787e727-e73d-43e0-a7b1-e968ba72ea53</xsi:eventID>
<xsi:sequenceNumber>1</xsi:sequenceNumber>
<xsi:userId>11111111#voip.company.domain</xsi:userId>
<xsi:externalApplicationId>NewClient</xsi:externalApplicationId>
<xsi:subscriptionId>24def51b-21fb-4d60-a1ef-67477dcafcfb</xsi:subscriptionId>
<xsi:channelId>575cfe44-2cc7-4cf5-bc05-bcc462bcbb02</xsi:channelId>
<xsi:targetId>22222222#voip.company.domain</xsi:targetId>
<xsi:eventData xsi1:type="xsi:ACDSubscriptionEvent"/>
</xsi:Event>
I'm not a XML "Jedi knight", but I know the basics.
The errors tells me I have a problem with the type xsi1:type="xsi:SubscriptionEvent" this is the attribute on the root xml (Event) element, this is the three attributes in question.
xsi1:type="xsi:SubscriptionEvent"
xmlns:xsi="http://schema.broadsoft.com/xsi"
xmlns:xsi1="http://www.w3.org/2001/XMLSchema-instance"
C# Class
I am using C#, until now I have had no problems creating equivalent classes based on the XML returned to me upon development.
If I take out the "bad data" the exception is avoided.
Event Class (I'm using this in Web API V2 environment, so technically its a model)
[XmlRoot(ElementName = "Event", Namespace = "http://schema.broadsoft.com/xsi")]
public class Event
{
[XmlElement(ElementName = "eventID", Namespace = "http://schema.broadsoft.com/xsi")]
public string EventID { get; set; }
[XmlElement(ElementName = "sequenceNumber", Namespace = "http://schema.broadsoft.com/xsi")]
public string SequenceNumber { get; set; }
[XmlElement(ElementName = "userId", Namespace = "http://schema.broadsoft.com/xsi")]
public string UserId { get; set; }
[XmlElement(ElementName = "externalApplicationId", Namespace = "http://schema.broadsoft.com/xsi")]
public string ExternalApplicationId { get; set; }
[XmlElement(ElementName = "subscriptionId", Namespace = "http://schema.broadsoft.com/xsi")]
public string SubscriptionId { get; set; }
[XmlElement(ElementName = "channelId", Namespace = "http://schema.broadsoft.com/xsi")]
public string ChannelId { get; set; }
[XmlElement(ElementName = "targetId", Namespace = "http://schema.broadsoft.com/xsi")]
public string TargetId { get; set; }
[XmlElement(ElementName = "eventData", Namespace = "http://schema.broadsoft.com/xsi")]
public EventData eventData { get; set; }
[XmlAttribute(AttributeName = "type", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
public string Type { get; set; }
[XmlAttribute(AttributeName = "xsi", Namespace = "http://www.w3.org/2000/xmlns/")]
public string xsi { get; set; }
[XmlAttribute(AttributeName = "xsi1", Namespace = "http://www.w3.org/2000/xmlns/")]
public string Xsi1 { get; set; }
[XmlRoot(ElementName = "eventData", Namespace = "http://schema.broadsoft.com/xsi")]
public class EventData
{
[XmlAttribute(AttributeName = "type", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
public string Type { get; set; }
}
}
This class was mainly generated from http://xmltocsharp.azurewebsites.net/
(that greatly speeds up this otherwise dull task)
Valid XML?
When I run the XML through different XML validators, I get different responses, some validates the XML fine, and some don't.
http://www.xmlvalidation.com: Fail
http://www.validome.org/xml/validate: Fail
http://codebeautify.org/xmlvalidate: Ok
To me, I find it hard to comprehend how exactly the structure is supposed to work.
It seems like the type attribute should be built upon the xsi1 attribute, but everything I have tried have failed.
My last resort will be to read the response as a string, then strip off the annoying XML so that it can be deserialized properly.
Best regards.
A slightly frustrated developer in dire need of help.
I think the confusion has arisen because xsi:type is part of XML schema and defines the types of various elements. You're trying to treat it as a normal attribute, and the serialiser is trying to use it to determine what objects to map the data to. The objects it's looking for aren't defined in the model.
Essentially, you need to model your classes after the type hierarchy your XML implies. So you have a base Event class with a SubscriptionEvent sub-class, and you have a base EventData class with a ACDSubscriptionEvent sub-class.
Note that (at least for XmlSerializer), you can omit a lot of your namespaces as they're inherited from the parent. You probably know more about the hierarchy than I do, so some of the properties may be able to be moved into the base class etc. Ideally, you'd have the XML schema file (.xsd) and would be able to generate the classes using xsd.exe, but this will work for the given XML:
[XmlInclude(typeof(SubscriptionEvent))]
[XmlRoot(Namespace = "http://schema.broadsoft.com/xsi")]
public abstract class Event
{
}
[XmlType(Namespace = "http://schema.broadsoft.com/xsi")]
public class SubscriptionEvent : Event
{
[XmlElement(ElementName = "eventID")]
public string EventID { get; set; }
[XmlElement(ElementName = "sequenceNumber")]
public string SequenceNumber { get; set; }
[XmlElement(ElementName = "userId")]
public string UserId { get; set; }
[XmlElement(ElementName = "externalApplicationId")]
public string ExternalApplicationId { get; set; }
[XmlElement(ElementName = "subscriptionId")]
public string SubscriptionId { get; set; }
[XmlElement(ElementName = "channelId")]
public string ChannelId { get; set; }
[XmlElement(ElementName = "targetId")]
public string TargetId { get; set; }
[XmlElement(ElementName = "eventData")]
public EventData EventData { get; set; }
}
[XmlInclude(typeof(ACDSubscriptionEvent))]
public abstract class EventData
{
}
[XmlType(Namespace = "http://schema.broadsoft.com/xsi")]
public class ACDSubscriptionEvent : EventData
{
}
See this fiddle for a working demo (using XmlSerializer).

How to define behave during serialization an object to attribute in XML

I have some problem with serialization an object to XML. At the beggining, this is class Order which have some properties of types like string, int...
public class Order
{
[XmlAttribute("ObjectType")]
public string TypeName
{
get; set;
}
[XmlAttribute("ID")]
public string ID
{
get; set;
}
[XmlAttribute("TID")]
public string TID
{
get; set;
}
[XmlAttribute("Command")]
public Command Command
{
get; set;
}
public Order()
{
}
}
As you can see, this class has also one property of type Command. Command class has one string property called Name:
public class Command
{
[XmlAttribute("Name")]
public string Name
{
get; set;
}
}
What's the problem? I need to get result like this:
<Order ObjectType="TestCase" ID="2" TID="W404" Command="SomeCommand" />
Where 'SomeCommand' is value of 'Name' property of this Command object.
With simple words: i need to define behave of how Command object should be serialized to XML attribute - return Name string. Very important thing is that also I have to be able to deserialize this XML to objects structure.
Hope my post is understandable and my problem is explained clearly. ;)
Best regards!
Assuming you have some way to reconstruct the command from the command name, you can introduce a derived property CommandName to serialize the name, and use xml serialization attributes to make XmlSerializer output the desired properties as attributes with the desired names:
public class Order
{
[XmlAttribute("ObjectType")]
public string TypeName
{
get;
set;
}
[XmlAttribute("ID")]
public string ID
{
get;
set;
}
[XmlAttribute("TID")]
public string TID
{
get;
set;
}
[XmlIgnore]
public Command Command
{
get;
set;
}
[XmlAttribute("Command")]
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
[Browsable(false)]
public string CommandName
{
get
{
return Command == null ? null : Command.Name;
}
set
{
// Logic to convert CommandName to Command, e.g.:
Command = Command.FindByName(value); // or whatever.
}
}
public Order()
{
}
}
The CommandName property must be public in order for this to work.

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