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

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

Related

Serializing class implementing ICollection

I have a collection class implementing ICollection<T> with a few custom attributes thrown in for completeness..
In this simplistic sample, its a simple Request/Results pattern with the request itself being passed back as an attribute of the results class.
[Serializable]
public class MyRequest
{
public int SearchID { get; set; }
}
[Serializable]
public class MyResults : ICollection<MyElement>
{
public MyRequest RequestDetails { get; set; }
private ICollection<MyElement> _list = new List<MyElement>();
/* ICollection interface methods removed */
}
[Serializable]
public class MyElement
{
public int ID { get; set; }
}
Here's the sample program to instantiate and then output a serialized string.
class Program
{
static void Main(string[] args)
{
MyResults m = new MyResults();
m.RequestDetails = new MyRequest() { SearchID = 1 };
for (int i = 1; i <= 5; i++)
{
m.Add(new MyElement { ID = i });
}
XmlDocument xmlDoc = new XmlDocument();
XmlSerializer xmlSerializer = new XmlSerializer(m.GetType());
using (MemoryStream xmlStream = new MemoryStream())
{
xmlSerializer.Serialize(xmlStream, m);
xmlStream.Position = 0;
xmlDoc.Load(xmlStream);
}
System.Diagnostics.Debug.WriteLine(xmlDoc.OuterXml);
}
}
The problem is that the output is not including the MyRequest details...
<?xml version="1.0"?>
<ArrayOfMyElement xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<MyElement>
<ID>1</ID>
</MyElement>
<MyElement>
<ID>2</ID>
</MyElement>
<MyElement>
<ID>3</ID>
</MyElement>
<MyElement>
<ID>4</ID>
</MyElement>
<MyElement>
<ID>5</ID>
</MyElement>
</ArrayOfMyElement>
XmlSerializer always ignores extra properties when serializing a collection; the only way to do it, as far as I know, is not to implement ICollection<MyElement> on your MyResults class, and instead expose the collection as a property:
public class MyResults
{
public MyRequest RequestDetails { get; set; }
public ICollection<MyElement> Items { get; set; }
}
(the Serializable attribute isn't needed for XML serialization)
Just change ICollection to Collection because XmlSerialization does not support Generic Interfaces:
public class MyResults
{
public MyResults()
{
this.Items= new Collection<MyElement>();
}
public MyRequest RequestDetails { get; set; }
public Collection<MyElement> Items { get; set; }
}

How to in general convert classes to xml nodes?

I want some Generic way to convert objects to xml nodes :
if i have some xml nodes like this:
<BusinessObject xmlns="http://xmlns.oracle.com/bpm/bpmobject/Data/BusinessObject"><?xml version="1.0" encoding="utf-16"?>
<BusinessObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<attribute1>sss</attribute1>
<attribute2>sss</attribute2>
</BusinessObject></BusinessObject>
I convert it to Json like that
{
"-xmlns": "http://xmlns.oracle.com/bpm/bpmobject/Data/BusinessObject",
"#text": "<?xml version=\"1.0\" encoding=\"utf-16\"?>
<BusinessObject xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">
<attribute1>sss</attribute1>
<attribute2>sss</attribute2>
</BusinessObject>"
}
Then to c# class:
public class Rootobject
{
public string xmlns { get; set; }
public string text { get; set; }
}
Now how to reverse it to xml nodes again after setting its value ? I want a general solution not for this example
XML serialization is what you are looking for
public class Rootobject
{
public string xmlns { get; set; }
public string text { get; set; }
}
public static void Main(string[] args)
{
Rootobject details = new Rootobject();
details.xmlns = "myNamespace";
details.text = "Value";
Serialize(details);
}
static public void Serialize(Rootobject details)
{
XmlSerializer serializer = new XmlSerializer(typeof(Rootobject));
using (TextWriter writer = new StreamWriter(#"C:\Xml.xml"))
{
serializer.Serialize(writer, details);
}
}
You can use XML Serialization for converting a Class to XML, and viceversa.
For reference, read C# Tutorial - XML Serialization.
You can also refer to XML Schema Definition Tool
Example:
[DataContract]
public class MyClass1 {
[DataMember]
public string name;
[DataMember]
public int age;
}
Serialize / Deserialize
MyClass1 obj = new MyClass1();
DataContractSerializer dcs = new DataContractSerializer(typeof(MyClass1));
using (Stream stream = new FileStream(#"C:\tmp\file.xml", FileMode.Create, FileAccess.Write))
{
using (XmlDictionaryWriter writer =
XmlDictionaryWriter.CreateTextWriter(stream, Encoding.UTF8))
{
writer.WriteStartDocument();
dcs.WriteObject(writer, obj);
}
}
I think you need to apply the Serializable attribute to your class to be able to serialize it. This makes sure that your class does not use some none serializable attributes.
[Serializable]
public class Rootobject
{
public string xmlns { get; set; }
public string text { get; set; }
}

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

How to deserealize a List of custom object?

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

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