Serialize an Object to Xml

Serialize an object to XML

You have to use XmlSerializer for XML serialization. Below is a sample snippet.

 XmlSerializer xsSubmit = new XmlSerializer(typeof(MyObject));
var subReq = new MyObject();
var xml = "";

using(var sww = new StringWriter())
{
using(XmlWriter writer = XmlWriter.Create(sww))
{
xsSubmit.Serialize(writer, subReq);
xml = sww.ToString(); // Your XML
}
}

As per @kiquenet request for generic class:

public class MySerializer<T> where T : class
{
public static string Serialize(T obj)
{
XmlSerializer xsSubmit = new XmlSerializer(typeof(T));
using (var sww = new StringWriter())
{
using (XmlTextWriter writer = new XmlTextWriter(sww) { Formatting = Formatting.Indented })
{
xsSubmit.Serialize(writer, obj);
return sww.ToString();
}
}
}
}

usage:

string xmlMessage = MySerializer<MyClass>.Serialize(myObj);

How to serialize an object into XML

In VB.Net you would first add some attributes to your class (if needed)

Public Class Class1

<XmlAttribute("value")>
Public Property Value As String

<XmlElement("name")>
Public Property Name As String

End Class

And then serialize it using

Dim p As New Class1()
p.Name = "test"
Dim sw1 = New StringWriter()
Dim xs1 As New XmlSerializer(GetType(Class1))
xs1.Serialize(New XmlTextWriter(sw1), p)
Console.WriteLine(sw1.ToString())

How to store C# object data as XML using XML Serialization

As per the discussion in comments, I'll give you a basic overview of how you can quickly (de)serialize custom classes.

For reference, here's your comment to which I'm replying:

@Flater Thanks for the reply! I'm still unsure how to do serialize my objects. For example, UserAdministration contains a list of Users and has methods for adding/removing Users from the list. Say for example, I add a new user by calling the addUser method of UserAdministration. How does the new User object get added to the XML file?


I always use this helper class because it makes the code so much cleaner. I've copied it from the internet somewhere, potentially StackOverflow. I will credit the author once I know/remember who it is.

public static class SerializerHelper
{
/// <summary>
/// Serializes an object.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="serializableObject"></param>
/// <param name="fileName"></param>
public static void SerializeObject<T>(string filepath, T serializableObject)
{
if (serializableObject == null) { return; }

try
{
XmlDocument xmlDocument = new XmlDocument();
XmlSerializer serializer = new XmlSerializer(serializableObject.GetType());
using (MemoryStream stream = new MemoryStream())
{
serializer.Serialize(stream, serializableObject);
stream.Position = 0;
xmlDocument.Load(stream);
xmlDocument.Save(filepath);
stream.Close();
}
}
catch (Exception ex)
{
//Log exception here
}
}


/// <summary>
/// Deserializes an xml file into an object list
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="fileName"></param>
/// <returns></returns>
public static T DeSerializeObject<T>(string filepath)
{
T objectOut = default(T);

if (!System.IO.File.Exists(filepath)) return objectOut;

try
{
string attributeXml = string.Empty;

XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load(filepath);
string xmlString = xmlDocument.OuterXml;

using (StringReader read = new StringReader(xmlString))
{
Type outType = typeof(T);

XmlSerializer serializer = new XmlSerializer(outType);
using (XmlReader reader = new XmlTextReader(read))
{
objectOut = (T)serializer.Deserialize(reader);
reader.Close();
}

read.Close();
}
}
catch (Exception ex)
{
//Log exception here
}

return objectOut;
}
}

Before I get to the usage examples, some tips so you know how to approach this:

  • These methods will serialize a single object (of any type) to a given file. This can be a class Foo, a List<Foo>, or a custom made class that contains all the data you want to save MyFooData
  • You cannot add to an existing file. When saving a file, the old file will be overwritten. I have not yet come across a use case where I needed to add to a file and couldn't just read the file's contents, change them, and store the whole object again. But I've only used it for small scale storage.
  • XML serialization uses public properties and a parameterless constructor. So make sure the objects you want to store have both of these. It will not serialize private or protected properties; or public/private/protected class fields.
  • The XML Serializer will automatically also serialize subclasses that are contained within (if they are public properties!). As far as I'm aware, it can go as deep as you want it to go. It will save everything.
  • The XML serializer has a weakness to recursion. I will explain how to avoid recursion in the code examples.
  • XML Serialization cannot (de)serialize Dictionary<T1,T2> or any IEnumerable that uses hashes for storage. However, if you want to store a Dictionary<T1,T2>, you can store it as a List<KeyValuePair<T1,T2>>, which means it will retain your data; just not the internal hash that it uses for quick lookup.

1 - The simplest example

[Serializable]
public class User
{
public string Name { get; set; }
public string Email { get; set; }
}

public static void TestMethod()
{
var myUser = new User() { Name = "John", Email = "John@john.com" };

//Save to file
SerializerHelper.SerializeObject(@"C:\MyDir\MyFile.txt", myUser);

//Read from file
var myUserReloaded = SerializerHelper.DeSerializeObject<User>(@"C:\MyDir\MyFile.txt");
}

Take note of the [Serializable] attribute on the User class. This is usually the only change that you need to make to your classes to make this work.

2 - Avoiding recursion and stack overflows

As mentioned in the tips, this serialization has a weakness to recursion. This can happen when classes refer to eachother in both directions.

[Serializable]
public class User
{
public string Name { get; set; }
public string Email { get; set; }

public Manager Boss {get; set; }
}

[Serializable]
public class Manager
{
public string Name { get; set; }

public User FavoriteEmployee {get; set; }
}

public static void TestMethod()
{
var userJohn = new User() { Name = "John", Email = "John@john.com" };
var managerMark = new Manager() { Name = "Mark" };

managerMark.FavoriteEmployee = userJohn;
userJohn.Boss = managerMark;

//Save to file
SerializerHelper.SerializeObject(@"C:\MyDir\MyFile.txt", userJohn);

//Read from file
var userJohnReloaded = SerializerHelper.DeSerializeObject<User>(@"C:\MyDir\MyFile.txt");
}

You will get a stack overflow exception when saving the file, because the serializer gets stuck in an infinite loop.

The serializer tries to write all of userJohn's properties to the file. When it gets to the Boss property, it notices that it is a serializable object and will begin serializing all of managerMark's properties. When it gets to the FavoriteEmployee property, it notices that it is a serializable object and will begin serializing all of userJohn's properties. When it...

You can prevent this from happening by using the [XmlIgnore] attribute on one of the two properties (or both, if you want to be really secure).

[Serializable]
public class User
{
public string Name { get; set; }
public string Email { get; set; }

public Manager Boss {get; set; }
}

[Serializable]
public class Manager
{
public string Name { get; set; }

[XmlIgnore]
public User FavoriteEmployee {get; set; }
}

The serializer tries to write all of userJohn's properties to the file. When it gets to the Boss property, it notices that it is a serializable object and will begin serializing all of managerMark's properties. When it gets to the FavoriteEmployee property, it notices that this property is marked [XmlIgnore] and it will not attempt to serialize what is contained within.


I hope this answer is what you were looking for.


EDIT I forgot a big caveat.

Let's say we are storing a List<Child> with two Child objects in it. Both Child objects have a Parent property, and it just so happens that both children are referencing the same Parent (same object in memory).

If I store the Parent (including a list of its children) it will serialize our Parent which will contain both Child objects. When deserializing, you will again have a singular Parent object and the two Child objects you started with.

If I store the List<Child> (including their parent), it will serialize the Parent for both Child objects. However, when deserializing, both Parent objects will be deserialized but they will be separate objects in memory.

As you can see, there could be a potential bug here if you are expecting both children to refer to the same Parent (as an object in memory). For this reason, I have a personal rule about how to use the serialization, and where to put the [XmlIgnore] attribute.

Children (IEnumerable<Foo>) get serialized, parents (Foo) do not. This allows me to store an entire tree in one go.

This means that I have to store the parent (and automatically have its children be serialized too), and I can only store the child without its reference to its parent (unless you store a ParentId key in the Child).

By doing it this way, you ensure that you won't create a multitude of Parent objects through deserialization, because every object only gets mentioned once in the XML file.


Edit

I forgot to add the SerializerHelper. to the method calls. Fixed now.

Serialize an object to XML without using attributes

You can't (do it elegantly).

The only way to modify the way the XmlSerializer serializes classes is by using attributes (by the way SerializableAttribute is not required). The DataContractSerializer is even worse.

One possible solution is to create intermediate classes for XML serialization/desrialization and use Automapper to copy the data between the "real" class and mediator.
I've used this approach to keep the front end XML serialization concerns outside of my business logic data types.

Serialize object to XML

I've decided to go the way I wrote my question - to use XmlWriter object, which i have to use anyway, even if I go Ofer Zelig's way.

namespace System.Xml.Serialization {
public static class XmlSerializationExtensions {
public static readonly XmlSerializerNamespaces EmptyXmlSerializerNamespace = new XmlSerializerNamespaces(
new XmlQualifiedName[] {
new XmlQualifiedName("") } );

public static void WriteElementObject( this XmlWriter writer, string localName, object o ) {
writer.WriteStartElement( localName );
XmlSerializer xs = new XmlSerializer( o.GetType() );
xs.Serialize( writer, o, EmptyXmlSerializerNamespace );
writer.WriteEndElement();
}

public static T ReadElementObject< T >( this XmlReader reader ) {
XmlSerializer xs = new XmlSerializer( typeof( T ) );
reader.ReadStartElement();
T retval = (T)xs.Deserialize( reader );
reader.ReadEndElement();
return retval;
}
}
}

Convert an object to an XML string

Here are conversion method for both ways.
this = instance of your class

public string ToXML()
{
using(var stringwriter = new System.IO.StringWriter())
{
var serializer = new XmlSerializer(this.GetType());
serializer.Serialize(stringwriter, this);
return stringwriter.ToString();
}
}

public static YourClass LoadFromXMLString(string xmlText)
{
using(var stringReader = new System.IO.StringReader(xmlText))
{
var serializer = new XmlSerializer(typeof(YourClass ));
return serializer.Deserialize(stringReader) as YourClass ;
}
}

How to serialize an c# object into xml without schema info?

You need a few xml tricks...

var serializer = new XmlSerializer(typeof(List<Ticket>));

var ns = new XmlSerializerNamespaces();
ns.Add("", "");
var sw = new StringWriter();
var xmlWriter = XmlWriter.Create(sw, new XmlWriterSettings() { OmitXmlDeclaration = true });

serializer.Serialize(xmlWriter, model, ns);
string xml = sw.ToString();

Output:

<ArrayOfTicket>
<Ticket>
<CitationNumber>a</CitationNumber>
<Amount>1</Amount>
</Ticket>
<Ticket>
<CitationNumber>b</CitationNumber>
<Amount>2</Amount>
</Ticket>
</ArrayOfTicket>

PS: I added Indent = true to XmlWriterSettings to get the above output

Serializing an object to XML and appending it to XML file

Try this. Should work if data and class structure are correct.

// same code till this

// get horse element from horseXml
XmlElement horseEl = horseXml.DocumentElement; //[1] get the doc element

// assign xmldb to xml document
var xmlDb = new XmlDocument();
xmlDb.Load(xmlDbFilepath);
//XmlNode root = xmlDb.DocumentElement; [2] removed

// add horseEl to root of xmlDb
//var newRoot = root.AppendChild(clonedHorseEl); [3] removed
var xe = xmlDb.CreateElement("Horse"); //[4] Create new Horse element on xmlDb
xe.InnerXml = horseEl.InnerXml; //[5] copy horseEl content
xmlDb.DocumentElement.AppendChild(xe);

xmlDb.Save(xmlDbFilepath);

The changes are mentioned in comments.



Related Topics



Leave a reply



Submit