I'm trying to deserialize the XML below into class, with the Components deserialized into a List<string>, but can't figure out how to do so. The deserializer is working fine for all the other properties, but not Components. Anyone know how to do this?
<ArsAction>
<CustomerName>Joe Smith</CustomerName>
<LoginID>jdsmith</LoginID>
<TicketGroup>DMS</TicketGroup>
<Software>Visio 2007 Pro</Software>
<Components>
<Component>Component 1</Component>
<Component>Component 2</Component>
</Components>
<Bldg>887</Bldg>
<Room>1320p</Room>
</ArsAction>
Add a property like this to hold the list of Components:
[XmlArray()]
public List<Component> Components { get; set; }
Edit: Sorry I misread that. You want to read it into a collection of strings. I just tried this below and it worked on your sample. The key is just to setup the correct xml serialization attributes.
public class ArsAction
{
[XmlArray]
[XmlArrayItem(ElementName="Component")]
public List<string> Components { get; set; }
}
Related
I'm trying to deserialize a JSON object array in C#. The array represents a row of a table, mainly consisting of plain strings. However, one or more of the items in the array may not be a string but infact a JSON object in itself, e.g.
"rows":[[{"date":"20140521","category":"one"},"data","moredata","evenmoredata"],...]
or on a different response from the server, the order may be different
"rows":[["data","moredata",{"date":"20140521","category":"one"},"evenmoredata"],...]
I'm trying to just treat this as a list of objects, with a known type called RowObject below:
[DataContract]
[KnownType(typeof(RowObject))]
public class Table
{
// other members to deserialize
[DataMember(Name = "rows")]
public List<List<object>> Rows { get; set; }
}
[DataContract]
public class RowObject
{
[DataMember(Name = "date")]
public DateTime date { get; set; }
[DataMember(Name = "category")]
public string category { get; set; }
}
This approach kind of worked in that the plain strings in the row were deserialized, however the RowObjects do not seem to be recognised even though I have tried to put them down as a KnownType. When I look at my deserialized List<object> Row, the RowObject just seems to be a blank object shown as {object} in the debugger.
I've managed to do this with known types and derived types elsewhere in the project but this problem dealing with plain strings has got me stuck. I've had a look at this question which seems pretty similar, but my problem with this answer is that I don't know which elements in the list are going to be the complex type. Also, I'm just using the .Net DataContractJsonSerializer throughout the project so would like to avoid third party libraries if at all possible.
Is it possible to deserialize a JSON array of different types like this?
Set EmitTypeInformation in DataContractJsonSerializerSettings to EmitTypeInformation.Always on the server side. That way you will get information about the types of your objexts, inside the json string.
I need to deserialize some JavaScript object represented in JSON to an appropriate C# class. Given the nice features of automatic properties, I would prefer having them in these classes as opposed to just having fields. Unfortunately, the .NET serialization engine (at least, by default) totally ignores automatic properties on deserialization and only cares about the backing field, which is obviously not present in the JavaScript object.
Given that there's no standard way to name backing fields and to be honest I don't even want to bother with the "let's create a JavaScript object that looks like it had C# backing fields" approach as it sounds a bit dirty, the only way I could serialize JavaScript fields to C# auto-properties if I could force the serialization engine to somehow ignore the backing field and use the property directly. Unfortunately, I can't figure out how this is done or if this can be done at all. Any ideas would be appreciated.
EDIT: Here's an example:
Javascript:
function Cat()
{
this.Name = "Whiskers";
this.Breed = "Tabby";
}
var cat = new Cat();
This is then serialized to "{Name: 'Whiskers'}".
The C# class:
[Serializable()]
public class Cat
{
public string Name { get; set; }
public string Breed { get; set; }
}
And the deserialization code, that fails:
new DataContractJsonSerializer(typeof(Cat)).ReadObject(inputStream);
And it is apparent from the exception that it fails because it is looking for the backing field.
EDIT2: Here's the exception, if that helps (no inner exceptions):
System.Runtime.Serialization.SerializationException
"The data contract type 'Test.Cat'
cannot be deserialized because the
required data members
'<Name>k__BackingField, <Breed>k__BackingField' were not
found."
What's happening here is the deserializer is trying to guess the name of your backing fields.
You can solve this by adding explicit mappings (DataContract/DataMember attributes) like this:
[DataContract]
public class Cat
{
[DataMember]
public string Name { get; set; }
[DataMember]
public string Breed { get; set; }
}
You can do this with JavaScriptSerializer found in the System.Web.Script.Serialization namespace:
JavaScriptSerializer serializer = new JavaScriptSerializer();
Cat c = serializer.Deserialize<Cat>(jsonString);
I have POCO objects with automatic properties and this works just fine.
EDIT: I wrote about JSON Serializers in .NET which compares this serializer with DataContractJsonSerializer.
baretta's answer solved the k__BackingField bloat for me. Just a tiny addendum that you can decorate this class to auto serialize into either XML or JSON in a similar way:
[Serializable, XmlRoot, DataContract]
public class Cat
{
[XmlElement]
[DataMember]
public string Name { get; set; }
[XmlElement]
[DataMember]
public string Breed { get; set; }
}
... and then use a DataContractJsonSerializer or XmlSerializer to prepare it for your endpoint.
I'm assuming you are passing data via a web service. If you are using the WebService class with the ScriptMethod attribute uncommented-out, the web service methods can read JSON natively. They even use the same JavaScriptSerializer that was mentioned above. If you are using WCF I'm a little more fuzzy on the logic.
But make sure your JSON object are returning data for EVERY property in your class. In your error, there is mention of a Breed property that is not in your example.
Also, on the JavaScript side, do to the dynamic nature of JavaScript it is easy to add new properties to your objects. This can sometimes lead to circular references. You should remove any extra data that you might have added (just as you are sending data via the web method, then add it again once you are done).
I haven't found any information on this, maybe someone could help.
I have an XML (simplified for convenience):
<content>
<field1>value</field1>
<field2>
<field3>value</field3>
</field2>
</content>
I try to deserialize it using such classes:
[XmlRoot("content")]
public class Content
{
[XmlElement]
public List<Item> Fields { get; set; }
}
public class Item
{
[XmlElement]
public List<Item> Fields { get; set; }
[XmlText]
public String Value { get; set; }
}
I have two questions:
Can I get the actual name of the field? Like [XmlName] string name; in the Item class? Or some kind of an attribute for the class itself? It is not possible to set the node name to "field" and add "type" attribute, for some reasons ;-) While the actual class and serialization process is really complicated, I'd prefer not to implement my own serializer.
Can I add a wildcard like [XmlElement("field*")]? I can't test it until I know the answer to the first question, so if there is a better option, I'd love to know it as well.
Thanks.
You can set the name of the matching XMl- Element or Attribute in the Constructor of the Attribute
[XmlAttribute("FieldAsAttribute")]
--> Will Serialize / Deserialize the Property to the Xml Attribute FieldAsAttribute
or
[XmlElement("FieldAsElement")]
--> Will Serialize / Deserialize the Property to the Xml Element FieldAsElement
The only answer here is that it's, unfortunately, not possible.
As a result we have written our own serialization routine.
I have a fairly simple DAL assembly that consists of an SalesEnquiry Class which contains a List<T> of another Vehicle class.
We'll be receiving XML files by email that I'm wanting to use to populate instances of my SalesEnquiry class, so I'm trying to use de-serialization.
I've added XMLRoot/XMLElement/XMLIgnore attributes to both classes as I think is appropriate. However, when I try de-serializing, the parent SalesEnquiry object is populated but no child Vehicle objects.
I understand that de-serializing List<T> can be tricky, but I'm not sure why, how to avoid problems, or even if this is why I'm struggling.
While debugging, I've successfully serialized a Vehicle object on it's own, so I'm assuming that I'm heading in the right direction, but when I de-serialize the SalesEnquiry XML (which contains one or more child Vehicles), the List<Vehicle> isn't populated.
Where am I going wrong?
Update:
In a test project, I serialized an SalesEnquiry containing two vehicles and save to a file. I then loaded the file up an de-serialized it back into a different SalesEnquiry object. It worked!
So what was the difference? The vehicles were recorded as follows:
<?xml version="1.0" encoding="utf-8"?>
<enquiry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<enquiry_no>100001</enquiry_no>
<vehicles>
<Vehicle>
<vehicle_type>Car</vehicle_type>
<vehicle_make>Ford</vehicle_make>
<vehicle_model>C-Max</vehicle_model>
...
The thing to note is that Vehicle has a an initial capital, whereas my incoming XML doesn't. In my Vehicle class, I gave the class an [XmlRoot("vehicle")] attribute, which I though would make the link, but clearly it doesn't. This makes sense, I guess, because although Vehicle is a class in it's own right, it's merely an array item within a List inside my SalesEnquiry.
In which case, the question is - How do I annotate the Vehicle class such that I can map the incoming XML elements (<vehicle>) to my list items (Vehicle)? [XmlArrayItem] (or [XmlElement] for that matter) are 'not valid on this declaration type'.
In this example, I can request that the people who generate the XML use <Vehicle> rather than <vehicle>, but there may be situations where I don't have this freedom, so I'd rather learn a solution than apply a workaround.
Conclusion:
By adding [XmlArrayItem("vehicle", typeof(Vehicle))] to the existing decoration for my List, the XML is now able to de-serialize fully. Phew!
Here's a working pair of classes with appropriate decorations:
(Note: The XmlAnyElement and XmlAnyAttribute are optional. It's a habit I'm in to promote the flexibility of the entity.)
[XmlType("enquiry")]
[XmlRoot("enquiry")]
public class Enquiry
{
private List<Vehicle> vehicles = new List<Vehicle>();
[XmlElement("enquiry_no")]
public int EnquiryNumber { get; set; }
[XmlArray("vehicles")]
[XmlArrayItem("Vehicle", typeof(Vehicle))]
public List<Vehicle> Vehicles
{
get { return this.vehicles; }
set { this.vehicles = value ?? new List<Vehicle>(); }
}
[XmlAnyElement]
public XmlElement[] AnyElements;
[XmlAnyAttribute]
public XmlAttribute[] AnyAttributes;
}
public class Vehicle
{
[XmlElement("vehicle_type")]
public string VehicleType { get; set; }
[XmlElement("vehicle_make")]
public string VehicleMake { get; set; }
[XmlElement("vehicle_model")]
public string VehicleModel { get; set; }
}
I have XML that is returned by a 3rd party web service in the following form:
<object>
<list name="subscriptions">
<object>
<string name="id">something</string>
<string name="title">something else</string>
<list name="categories" />
<number name="timestamp">1252707770116</number>
</object>
...more 'object'...
</list>
</object>
I'm having a lot of issues trying to deserialize this data to an object. I wasn't able to generate a schema using xsd.exe, so I generated the following classes by hand to try and fit this data:
[XmlRoot("object")]
public class ListOfSubscriptions
{
[XmlElement("list")]
public Subscription[] items;
}
[XmlRoot("object")]
public class Subscription
{
[XmlAttribute()]
public string id;
[XmlAttribute()]
public string title;
[XmlAttribute()]
public string[] categories;
[XmlAttribute()]
public string timestamp;
}
I'm trying to deserialize this with the following code:
XmlSerializer s = new XmlSerializer(typeof(ListOfSubscriptions));
StreamReader r = new StreamReader("out.xml");
ListOfSubscriptions listSubscribe = (ListOfSubscriptions)s.Deserialize(r);
r.Close();
However, when it finishes, listSubscribe has one member and all its fields are null.
How should I be creating my template for deserializing?
Thanks
Update - 2010/01/28
Thanks to everybody's comments I've revised my classes to the following:
[XmlRoot("object")]
public class ListOfSubscriptions
{
[XmlElement("list")]
public SubscriptionList[] items;
}
[XmlRoot("list")]
public class SubscriptionList
{
[XmlElement("object")]
public Subscription[] items;
}
[XmlRoot("object")]
public class Subscription
{
[XmlElement("string")]
public string id;
[XmlElement("string")]
public string title;
[XmlElement("list")]
public string[] categories;
[XmlElement("number")]
public string timestamp;
}
If I comment out the [XmlElement(...)] lines in Subscription, and run, I get that listSubscribe has one SubscriptionList item which has the correct number of Subscriptions, however, all the elements of the subscriptions are null.
If I uncomment the XmlElement lines, I get an error reflecting a Subscription. I imagine its getting confused because there are multiple elements with the same name.
How do I tie the attribute name to the class member?
You're on the right track. However, you are only defining two classes. There are actually three classes to define:
The single root object, with an XML name of "object". This will have only one member:
The list of objects (with an XML name of "list"). This will have one member, an array of:
Subscriptions, with an XML name of "object".
Another problem is that you are defining the Subscription fields as attributes. They aren't attributes, they're elements.
You're never going to get anywhere with XML like this:
<string name="id">something</string>
That's just created by someone who doesn't know XML. The equivalent:
<id>something</id>
would be easy to deserialize.
The only way I can think of for you to deserialize that is by implementing the IXmlSerializable interface on your class(es).
You will want to change out XmlArry and XMLArrayItem.
Here is an example. It should look something like this:
[XmlArray("FullNames")]
[XmlArrayItem("Name")]
public string[] Names{get;set;}
will give you
<FullNames>
<Name>Michael Jackson</Name>
<Name>Paris Hilton</Name>
</FullNames>
I believe you can use XSD.exe .Net framework utility to generate a class that can be used a memory representation of your XML document.