Custom Array Item Name for DTO - c#

One of my clients has XML data he wants to send to a service we are creating. A sample message might look like:
<SomeRootElement>
<Dates>
<Date>2012-05-20T00:00:00</Date>
<Date>2012-05-21T00:00:00</Date>
</Dates>
</SomeRootElement>
I have a corresponding type defined as a DataContract on my WCF service application:
[DataContract]
public class SomeRootElement {
[DataMember]
public ICollection<DateTime> Dates { get; set; }
}
The trouble is that based on this definition, WCF wants the Dates collection to look like:
<Dates>
<dateTime>2012-05-20T00:00:00</dateTime>
<dateTime>2012-05-21T00:00:00</dateTime>
</Dates>
Is there any way to influence the array item's serialized element name? This used to be easy using XML serialization attributes, but the DataContractSerializer ignores those.

This should do the trick:
[DataContract]
[KnownType(typeof(DateList))]
public class SomeRootElement {
[DataMember]
public ICollection<DateTime> Dates { get; set; }
}
[CollectionDataContract(ItemName="date")]
public class DateList : Collection<DateTime> {}
You are overriding the type it can use for deserializing the ICollection for a customized one.

Related

Deserialize objects with RestSharp where the class is in a type attribute

I'm trying to consume data from a rest api.
I need to deserialize objects from a rest API using RestSharp.
The all objects in lists are an "object" element where the object's class is the value of a "type" attribute.
Here is an example of what I mean:
<list>
<object type="cat">
<id>107</id>
<name>Garry</name>
</object>
<object type="dog">
<id>83</id>
<name>Fluffy</name>
</object>
</list>
And partially implemented classes for the example:
public class Animal
{
public long Id { get; set; }
public string Name { get; set; }
}
[DeserializeAs(Name = "cat")]
public class Cat : Animal
{
}
[DeserializeAs(Name = "dog")]
public class Dog : Animal
{
}
It seems like the wrong way to go, but tried defining all of my classes using the attribute:
[DeserializeAs(Name = "object")]
This allows them to deserialize properly, as long as I know what type of object to expect in the list, and obviously the list only contains one type of object.
The problem comes in if I get a list containing different types of objects.
Is there a way to handle this well using the standard deserializer?
If not, I am open to ways to handle this effectively with a large number of different object types.
I looked at the standard deserializer. I am pretty sure it was not designed to handle this. I ended up making my own fork.
I added another attribute for describing the object in lists:
[DeserializeElementAs(Name = "", Attribute = "", Value = "")]
The attribute name might not be the best, but I was not sure what to call it.
So the classes for the xml from the question would be defined as:
public class Animal
{
public long Id { get; set; }
public string Name { get; set; }
}
[DeserializeElementAs(Name = "object", Attribute = "type", Value = "cat")]
[DeserializeAs(Name = "cat")]
public class Cat : Animal
{
}
[DeserializeElementAs(Name = "object", Attribute = "type", Value = "dog")]
[DeserializeAs(Name = "dog")]
public class Dog : Animal
{
}
I posted the code of fork to github if anyone else needs it.
https://github.com/comless/RestSharp/commit/1fea0fd97cadc7035dbea99c17b7423ca14b5267

Deserialize multiple XML elements have same name

i have an XML form look like this:
<Myset>
<element>1A</element>
<element>2B</element>
<element>3C</element>
<element>AB</element>
..........
<element>AA</element>
What should structure class, variables should i use to deserialize it. I want to read and update value of each element. I have try this, but it doesn't work:
public class Myset
{
public List<string> element {get; set;}
// or public string[] element { get; set; }
}
XmlElementAttribute will allow you specify element name.
public class case_id_list
{
[XmlElement("case_id")]
public List<string> case_id {get; set;}
}
You should use this service. It converts your xml structure to valid c# model structure. It's a very useful tool.
*In case you ever want to convert your JSON to C# this is another useful service.
Cheers!

How to Deserialize XML elements to generic list with unknown element names

I am retrieving and successfully deserializing an xml string from a database table column for the known element names (these do not change) but there are also some nested XML Elements called "Other Attributes" which are not always going to be known. I'm having some trouble deserialising these unknown element names to a generic list so I can display them in html once deserialised.
The XML is as follows:
<Detail>
<DetailAttributes>
<Name>Name_123</Name>
<Type>Type_123</Type>
</DetailAttributes>
<OtherAttributes>
<SummaryKey AttributeName="SummaryKey">SummaryKey_123</SummaryKey>
<Account AttributeName="Account">Account_123</Account>
</OtherAttributes>
</Detail>
I have no problem deserialising the 'Name' and 'Type' elements and I can deserialise the 'SummaryKey' and 'Account' elements but only if I explicitly specify their element names - which is not the desired approach because the 'OtherAttributes' are subject to change.
My classes are as follows:
[XmlRoot("Detail")]
public class objectDetailsList
{
[XmlElement("DetailAttributes"), Type = typeof(DetailAttribute))]
public DetailAttribute[] detailAttributes { get; set; }
[XmlElement("OtherAttributes")]
public List<OtherAttribute> otherAttributes { get; set; }
public objectDetailsList()
{
}
}
[Serializable]
public class Detail Attribute
{
[XmlElement("Type")]
public string Type { get;set; }
[XmlElement("Name")]
public string Name { get;set; }
public DetailAttribute()
{
}
}
[Serializable]
public class OtherAttribute
{
//The following will deserialise ok
//[XmlElement("SummaryKey")]
//public string sumKey { get; set; }
//[XmlElement("Account")]
//public string acc { get; set; }
//What I want to do below is create a list of all 'other attributes' without known names
[XmlArray("OtherAttributes")]
public List<Element> element { get; set; }
}
[XmlRoot("OtherAttributes")]
public class Element
{
[XmlAttribute("AttributeName")]
public string aName { get; set; }
[XmlText]
public string aValue { get; set; }
}
When I try to retrieve the deserialised list of OtherAttribute elements the count is zero so it's not able to access the elements nested within "Other Attributes".
Can anybody help me with this please?
With concrete classes and dynamic data like this, you won't be able to lean on the standard XmlSerializer to serialize / deserialize for you - as it reflects on your classes, and the properties you want to populate simply don't exist. You could provide a class with all possible properties if your set of 'OtherAttributes' is known and finite, and not subject to future change, but that would give you an ugly bloated class (and I think you've already decided this is not the solution).
Practical options therefore:
Do it manually. Use the XmlDocument class, load your data with .Load(), and iterate the nodes using .SelectNodes() using an XPath query (something like "/Detail/OtherAttributes/*"). You will have to write the lot yourself, but this gives you complete control over the serialization / deserialization. You won't have to cover your code in (arguably superfluous!) attributes either.
Use Json.NET (http://james.newtonking.com/json), it allows for far greater control over serialization and deserialization. It's fast, has good docs and is overall pretty nifty really.

attribute not being serialized by XmlSerializer

I'd like to serialize a class to XML, assigning an XML attribute to it. Snippet:
[XmlType(TypeName = "classmy")]
public class MyClass2 : List<object>
{
[XmlAttribute(AttributeName = "myattr")]
public string Name { get; set; }
}
public class MyConst
{
public MyConst()
{
MyClass2 myClass2 = new MyClass2 { 10, "abc" };
myClass2.Name = "nomm";
XmlSerializer serializer = new XmlSerializer(typeof(MyClass2));
serializer.Serialize(Console.Out, myClass2);
}
}
But the resulting XML looks like this
<?xml version="1.0" encoding="IBM437"?>
<classmy xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<anyType xsi:type="xsd:int">10</anyType>
<anyType xsi:type="xsd:string">abc</anyType>
</classmy>
All well and good, with the only exception being that myClass2.Name is not serialized. I was expecting something in the line of
<classmy myattr="nomm" [...]>[...]</classmy>
... Why isn't that serialized, and how can it be?
dont derive List<T>, create class with member List
[XmlType(TypeName = "classmy")]
public class MyClass2
{
[XmlAttribute(AttributeName = "Items")]
List<object> Items { get; set; } //need to change type in `<>`
[XmlAttribute(AttributeName = "myattr")]
public string Name { get; set; }
}
Alternative solution: use an array instead of a list and XmlElement
[XmlType(TypeName = "classmy")]
public class MyClass2
{
[XmlElement(ElementName = "Items")]
public object[] Items { get; set; }
[XmlAttribute(AttributeName = "myattr")]
public string Name { get; set; }
}
XmlSerializer treats List<> in special way:
XmlSerializer can process classes that implement IEnumerable or ICollection differently if they meet certain requirements. A class that implements IEnumerable must implement a public Add method that takes a single parameter. The Add method's parameter must be consistent (polymorphic) with the type returned from the IEnumerator.Current property returned from the GetEnumerator method. A class that implements ICollection in addition to IEnumerable (such as CollectionBase) must have a public Item indexed property (an indexer in C#) that takes an integer, and it must have a public Count property of type integer. The parameter passed to the Add method must be the same type as that returned from the Item property, or one of that type's bases. For classes implementing ICollection, values to be serialized will be retrieved from the indexed Item property rather than by calling GetEnumerator. Also note that public fields and properties will not be serialized, with the exception of public fields that return another collection class (one that implements ICollection). MSDN - scroll to XML Serialization Considerations
That why it serialized Your class as a list of objects only, without Your property. The best solution is to include List as class public property and mark it as XmlElement.

C# XML Serialization of Attribute

I have some XML which I would like to serialize into a class.
<MasterData>
<Data>
<SomeInnerData>
some inner data
</SomeInnerData>
</Data>
</MasterData>
<MoreData>
<SubMoreData>moredate</SubMoreData>
</MoreDate>
and
[System.SerializableAttribute()]
public class MasterData
{
public string SomeInnnerData {get;set;}
public string SubMoreDate {get;set;}
}
How do I set the string member variables to serialize the appropriate data in the XML? My issue arises in that the element is not a child of the MasterData element.
The simplest way is to work backwards, get your class setup to serialize into the format you want, so that you can deserialize into it with ease.
Note: Your xml didn't validate, so I changed it to this for an example
<MasterData>
<Data>
<SomeInnerData>some inner data</SomeInnerData>
</Data>
<MoreData>
<SubMoreData>moredate</SubMoreData>
</MoreDate>
</MasterData>
Currently, your problem is that you have Data and MoreData elements that don't map to anything
You'd need to create classes like
public class MasterData {
public Data Data {get; set;}
public MoreData Data {get; set;}
}
public class Data {
public string SomeInnerData {get; set;}
}
public class MoreData {
public string SubMoreData {get; set;}
}
You can have your properties named other things, and use the [XmlElement(ElementName="SubMoreData")] to map the property, to the correct Element.
Or, you could implement the IXmlSerializable interface, and write custom serialization code in a single class to map your class to xml however you want
The XML example you provided is not valid XML thus you will not be able to directly serialize it. You need a root node for it work this way.
Such that:
<AllData>
<MasterData>
<Data>
<SomeInnerData>
some inner data
</SomeInnerData>
</Data>
</MasterData>
<MoreData>
<SubMoreData>moredate</SubMoreData>
</MoreDate>
<AllData>
[System.SerializableAttribute()]
public class AllData
{
public MasterData MasterData {get;set;}
public MoreData MoreData {get;set;}
}
[System.SerializableAttribute()]
public class Data
{
public string SomeInnnerData {get;set;}
}
[System.SerializableAttribute()]
public class MasterData
{
public string SomeInnnerData {get;set;}
}
[System.SerializableAttribute()]
public class MasterData
{
public Data Data {get;set;}
}
[System.SerializableAttribute()]
public class MoreData
{
public string SubMoreDate {get;set;}
}
Implement ixmlserializable for custom serialization
With the normal .NET XMLSerializer class, public properties are serialized by default. You have to explicitly attribute properties not to be serialized:
[System.Xml.Serialization.XmlIgnoreAttribute]
Here's the documentation: XmlSerializer
...
Now that you've revised your question, the answer is that you will no longer be able to use the XMLSerializer class. (Or you will have to have some intermediary class which matches the structure of your XML, to facilitate the serialization and deserialization.) If you have a very specific XML structure that you want transform arbitrarily, use an XmlReader.
How about using XSL to transform from/to the XML format that your C# class directly serializes to?

Categories