How to deserealize a List of custom object? - c#

This is my Model class:
public class ModelClass
{
public ModelClass()
{
}
public ModelClass(string operationName)
{
OperationName = operationName;
}
public string OperationName { get; set; }
public int Count { get; set; }
}
I have to serialize a list of this model class to a database table:
The table schema is:
ModelObjectContent (the serialized string)
IDModel
The method wich I use to serialize:
public static string SerializeObject(this List<ModelClass> toSerialize)
{
var xmlSerializer = new XmlSerializer(toSerialize.GetType());
var textWriter = new StringWriter();
xmlSerializer.Serialize(textWriter, toSerialize);
return textWriter.ToString();
}
When I save it to the database the string generated is like this:
<ArrayOfChartModel>
<ModelClass>
<OperationName>Chart1</OperationName>
<Count >1</Count>
</ModelClass>
<ModelClass>
<OperationName>Chart2</OperationName>
<Count >2</Count>
</ModelClass>
//etc
</ArrayOfChartModel>
The framework automattically creates a tag named ArrayOfChartModel and thats ok,
but my question is:
How to deserealize this xml to a list of ModelClass again?

This should work for you:
public static List<ModelClass> Deserialize(string xml)
{
var xmlSerializer = new XmlSerializer(typeof(ModelClass));
using (TextReader reader = new StringReader(xml))
{
return(List<ModelClass>)xmlSerializer.Deserialize(reader);
}
}

Related

XmlSerializer not deserializing int array

I have the following type:
[XmlRoot(Namespace = "http://schemas.datacontract.org/2004/07/MyNamespace")]
public class Location
{
public int Id { get; set; }
public string Name { get; set; }
public Collection<int> DataSourceIds { get; set; }
}
I'm serializing a list of Locations to XML, resulting in the following:
<ArrayOfLocation xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/MyNamespace">
<Location>
<DataSourceIds xmlns:d3p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<d3p1:int>1</d3p1:int>
</DataSourceIds>
<Id>2</Id>
<Name>First</Name>
</Location>
<Location>
<DataSourceIds xmlns:d3p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<d3p1:int>1</d3p1:int>
<d3p1:int>2</d3p1:int>
<d3p1:int>3</d3p1:int>
<d3p1:int>4</d3p1:int>
</DataSourceIds>
<Id>1</Id>
<Name>Second</Name>
</Location>
</ArrayOfLocation>
I then try to deserialize this XML as follows:
var rootAttribute = new XmlRootAttribute("ArrayOfLocation")
{
Namespace = "http://schemas.datacontract.org/2004/07/MyNamespace"
};
var serializer = new XmlSerializer(typeof(Location[]), rootAttribute);
using (var xmlReader = XmlReader.Create(new StreamReader(response.GetResponseStream())))
{
locations = (Location[])serializer.Deserialize(xmlReader);
}
This returns a list of Location objects, with every property set correctly... except DataSourceIds, which remains empty. Why isn't XmlSerializer deserializing the array of integers?
Since it was serialized with DataContractSerializer, you can deserialize it like so:
[DataContract(Namespace = "http://schemas.datacontract.org/2004/07/MyNamespace")]
public class Location
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public Collection<int> DataSourceIds { get; set; }
}
And then use it like:
using (var xmlReader = XmlReader.Create(stream))
{
DataContractSerializer serializer = new DataContractSerializer(typeof(Location[]));
var locations = (Location[])serializer.ReadObject(xmlReader);
Debug.WriteLine(DataContractSerializerHelper.GetXml(locations, serializer)); // Debug check on re-serialization, remove when not needed.
}
The XmlRoot declaration is ignored by DataContractSerializer.
Finally, a utility method for re-serializing to an XML string, for debugging purposes:
public static class DataContractSerializerHelper
{
private static MemoryStream GenerateStreamFromString(string value)
{
return new MemoryStream(Encoding.Unicode.GetBytes(value ?? ""));
}
public static string GetXml<T>(T obj, DataContractSerializer serializer) where T : class
{
using (var textWriter = new StringWriter())
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.IndentChars = " "; // For cosmetic purposes.
using (XmlWriter xmlWriter = XmlWriter.Create(textWriter, settings))
{
serializer.WriteObject(xmlWriter, obj);
}
return textWriter.ToString();
}
}
public static string GetXml<T>(T obj) where T : class
{
DataContractSerializer serializer = new DataContractSerializer(typeof(T));
return GetXml(obj, serializer);
}
}

Prepend parent node when serializing C# property

I'd like to serialize the following class to xml:
public class Survey
{
[XmlElement("edit")]
public string EditLink { get; set; }
}
As expected this serializes as (removed extra stuff not important to the question)
<Survey><edit>http://example.com/editlink</edit></Survey>
However, I'd like to prepend a parent node to the edit node, so that the resultant xml is:
<Survey><links><edit>http://example.com/editlink</edit></links></Survey>
Is there a way to do this with just the serialization attributes, without modifying the structure of the class?
You can't with that structure. If you expose EditLink as a collection then you can:
public class Survey
{
[XmlArray("links")]
[XmlArrayItem("edit")]
public string[] edit
{
get
{
return new [] {EditLink};
}
set
{
EditLink = value[0];
}
}
[XmlIgnore]
public string EditLink { get; set; }
}
Which yields:
<Survey>
<links>
<edit>http://example.com/editlink</edit>
</links>
</Survey>
You can try using the XMLSerializer class.
public class Survey
{
public string EditLink { get; set; }
}
private void SerializeSurvey()
{
XmlSerializer serializer = new XmlSerializer(typeof(Survey));
Survey survey = new Survey(){EditLink=""};
// Create an XmlTextWriter using a FileStream.
Stream fs = new FileStream(filename, FileMode.Create);
XmlWriter writer = new XmlTextWriter(fs, Encoding.Unicode);
// Serialize using the XmlTextWriter.
serializer.Serialize(writer, survey);
writer.Close();
}

How to Serialize C# Class with class name as root element

I have the following C# class
[XmlRoot("Customer")]
public class MyClass
{
[XmlElement("CustId")]
public int Id {get;set;}
[XmlElement("CustName")]
public string Name {get;set;}
}
I then use the following function serialise the class object to Xml
public static XmlDocument SerializeObjectToXML(object obj, string sElementName)
{
XmlSerializer serializer =
new XmlSerializer(obj.GetType(), new XmlRootAttribute("Response"));
using (MemoryStream ms = new MemoryStream())
{
XmlDocument xmlDoc = new XmlDocument();
serializer.Serialize(ms, obj);
ms.Position = 0;
xmlDoc.Load(ms);
}
}
My current output to XML is like;
<Response>
<CustId></CustId>
<CustName></CustName>
</Response>
But how can I get the response to look like;
<Response>
<Customer>
<CustId></CustId>
<CustName></CustName>
</Customer>
</Response>
Change the XmlElementAttribute on MyClass (it's not actually valid there according to http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlelementattribute(v=vs.110).aspx) to an XmlTypeAttribute:
[XmlType("Customer")]
public class MyClass
{
[XmlElement("CustId")]
public int Id { get; set; }
[XmlElement("CustName")]
public string Name { get; set; }
}
The serialization method can now be (identical to that in the question but without the second parameter in the constructor of XmlSerializer):
public static XmlDocument SerializeObjectToXML(object obj, string sElementName)
{
XmlSerializer serializer = new XmlSerializer(obj.GetType());
XmlDocument xmlDoc = new XmlDocument();
using (MemoryStream ms = new MemoryStream())
{
serializer.Serialize(ms, obj);
ms.Position = 0;
xmlDoc.Load(ms);
}
return xmlDoc;
}
You can create a response object containing your customer, because that is what your desired xml shows as well.
[XmlRoot("Response")]
public class ResponseClass
{
[XmlElement("Customer")]
public Myclass Customer {get;set;}
}
You could define them like this:
public class MyClass
{
[XmlElement("Customer")]
public Customer cust { get; set; }
}
public class Customer
{
[XmlElement("CustId")]
public int Id { get; set; }
[XmlElement("CustName")]
public string Name { get; set; }
}
By the way, the [XmlElement("Customer")] is not valid on your example...

Parse XML list to typed object using annotations

I have this xml that return of a web service:
<return>
<LuckNumber>
<Number>00092</Number>
<CodError>00</CodError>
<Serie>019</Serie>
<Number>00093</Number>
<CodError>00</CodError>
<Serie>019</Serie>
<Number>00094</Number>
<CodError>00</CodError>
<Serie>019</Serie>
<Number>00095</Number>
<CodError>00</CodError>
<Serie>019</Serie>
</LuckNumber>
How Can I parse this XML to a typed object using annotations?
I Tried it, but doesn't work:
protected T ProccessResult<T>(string result) {
XmlSerializer serializer = new XmlSerializer(typeof(T));
using (StringReader reader = new StringReader(result))
{
var resultDeserialize = (T)(serializer.Deserialize(reader));
return resultDeserialize;
}
}
ProccessResult<List<GenerateNumberList>>(STRING_XML_ABOVE)
CLASS TO PARSE:
[XmlRoot("LuckNumber")]
public class GenerateNumberResult
{
[XmlElement("Number")]
public string LuckNumber { get; set; }
[XmlElement("CodError")]
public string CodError{ get; set; }
[XmlElement("Serie")]
public string Serie { get; set; }
}
Can someone help me? Thanks!
The root of your XML is the "return" element. Add a wrapper class that contains your list:
[XmlRoot("return")]
public class ResultWrapper
{
[XmlElement("LuckNumber")]
public List<GenerateNumberResult> numberList;
}
And get the result:
ResultWrapper result = ProccessResult<ResultWrapper>(xml);

Why does not XmlSerializer recognize this attribute?

I have a simple class with two properties:
[XmlRoot("response")]
public class Response
{
[XmlAttribute("code")]
string Code { get; set; }
[XmlAttribute("message")]
string Message { get; set; }
}
I try to deserialize an XML string with XmlSerializer:
static void Main(string[] args)
{
string xml = "<response code=\"a\" message=\"b\" />";
using(var ms = new MemoryStream())
using(var sw = new StreamWriter(ms))
{
sw.Write(xml);
sw.Flush();
ms.Position = 0;
XmlSerializer ser = new XmlSerializer(typeof(Response));
ser.UnknownAttribute += new XmlAttributeEventHandler(ser_UnknownAttribute);
var obj = ser.Deserialize(ms);
}
}
static void ser_UnknownAttribute(object sender, XmlAttributeEventArgs e)
{
throw new NotImplementedException();
}
The UnknownAttribute event gets fired at the code attribute, it does not get deserialized.
What is the reason for this? Am I using the XmlAttributeAttribute wrong?
This is because the attributes are not public in your class:
[XmlRoot("response")]
public class Response
{
[XmlAttribute("code")]
public string Code { get; set; }
[XmlAttribute("message")]
public string Message { get; set; }
}
From the documentation of XmlAttributeAttribute (emphasis is mine):
You can assign the XmlAttributeAttribute only to public fields or public properties that return a value (or array of values) that can be mapped to one of the XML Schema definition language (XSD) simple types (including all built-in datatypes derived from the XSD anySimpleType type).

Categories