Generic XML Serializer Class for C# and an XML Serialization usage example
UPDATE: This is now part of the EasyXml NuGet package. There is also an EasyXml.Sources NuGet package.
Hey all,
Today I was working on XML Serialization.
After learning how to do it, I discovered it takes four lines of code to write an XML and four lines of code to read in an XML.
However, I prefer one line of code to four so I made a Serializer.cs class with two static functions.
After thinking about it, I made these classes generic so they work with any type. I hope this helps someone.
using System; using System.IO; using System.Xml.Serialization; namespace BlogTool { public class Serializer { #region Functions public static void SerializeToXML(T t, String inFilename) { XmlSerializer serializer = new XmlSerializer(t.GetType()); TextWriter textWriter = new StreamWriter(inFilename); serializer.Serialize(textWriter, t); textWriter.Close(); } public static T DeserializeFromXML(String inFilename) { XmlSerializer deserializer = new XmlSerializer(typeof(T)); TextReader textReader = new StreamReader(inFilename); T retVal = (T)deserializer.Deserialize(textReader); textReader.Close(); return retVal; } #endregion } }
So now if you have a class, you can easily serialize it to and from an XML with a single line.
Here is an example Project that contains these files:
- Blog.cs
- BlogList.cs
- Program.cs
- Serializer.cs
Blog.cs
using System; namespace BlogTool { [Serializable()] public class Blog { #region Member Variables String mBlogUrl; String mCategory; #endregion #region Constructors public Blog() { } public Blog(String inURL, String inCategory) { mBlogUrl = inURL; mCategory = inCategory; } #endregion #region Properties public String BlogUrl { get { return mBlogUrl; } set { mBlogUrl= value; } } public String Category { get { return mCategory; } set { mCategory= value; } } #endregion } }
BlogList.cs
using System.Collections.Generic; namespace BlogTool { [Serializable] public class BlogList { #region Member Variables List mBlogs = new List(); #endregion #region Constructors /* * The default constructor */ public BlogList() { } #endregion #region Properties public List Blogs { get { return mBlogs; } set { mBlogs = value; } } #endregion } }
Program.cs
namespace BlogTool { class Program { static void Main(string[] args) { BlogList bloglist = new BlogList(); Blog b1 = new Blog("http://rhyous.com","Software"); Blog b2 = new Blog("http://www.alittletipsy.com", "Crafts"); bloglist.Blogs.Add(b1); bloglist.Blogs.Add(b2); Serializer.SerializeToXML(bloglist, "FavoriteBlogs.xml"); } } }
Serializer.cs
using System; using System.IO; using System.Xml.Serialization; namespace BlogTool { public class Serializer { #region Functions public static void SerializeToXML(T t, String inFilename) { XmlSerializer serializer = new XmlSerializer(t.GetType()); TextWriter textWriter = new StreamWriter(inFilename); serializer.Serialize(textWriter, t); textWriter.Close(); } public static T DeserializeFromXML(String inFilename) { XmlSerializer deserializer = new XmlSerializer(typeof(T)); TextReader textReader = new StreamReader(inFilename); T retVal = (T)deserializer.Deserialize(textReader); textReader.Close(); return retVal; } #endregion } }
Ok, so now that you have the files, you can run this program.
In the bin\debug or bin\release directory where you executable is placed when you build, you will see the FavoriteBlogs.xml file. The XML should look as follows:
<!--?xml version="1.0" encoding="utf-8"?--> http://rhyous.com Software http://www.alittletipsy.com Crafts
I know, this is not written very well as a walk-thru, but I wrote it fast. Maybe I will clean it up later.
Update: 5/8/14
namespace Rhyous.EasyXml { using System; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Text; using System.Threading; using System.Xml; using System.Xml.Serialization; [ExcludeFromCodeCoverage] public static class Serializer { #region Functions /// <summary> /// This function writes the serialized XML to the file name passed in. /// </summary> /// <typeparam name="T">The object type to serialize.</typeparam> /// <param name="t">The instance of the object.</param> /// <param name="outFilename">The file name. It can be a full path.</param> /// <param name="inOmitXmlDeclaration"></param> /// <param name="inNameSpaces"></param> /// <param name="inEncoding"></param> public static void SerializeToXml<T>(T t, string outFilename, bool inOmitXmlDeclaration = false, XmlSerializerNamespaces inNameSpaces = null, Encoding inEncoding = null) { MakeDirectoryPath(outFilename); var ns = inNameSpaces; if (ns == null) { ns = new XmlSerializerNamespaces(); ns.Add("", ""); } var serializer = new XmlSerializer(t.GetType()); var textWriter = (TextWriter)new StreamWriter(outFilename); if (inEncoding != null && inEncoding.Equals(Encoding.UTF8)) textWriter = new Utf8StreamWriter(outFilename); var xmlWriter = XmlWriter.Create(textWriter, new XmlWriterSettings { OmitXmlDeclaration = inOmitXmlDeclaration }); serializer.Serialize(xmlWriter, t, ns); textWriter.Close(); } /// <summary> /// /// </summary> /// <param name="outFilename"></param> private static void MakeDirectoryPath(string outFilename) { var dir = Path.GetDirectoryName(outFilename); if (dir != null && !Directory.Exists(dir)) { Directory.CreateDirectory(dir); } } /// <summary> /// This function returns the serialized XML as a string /// </summary> /// <typeparam name="T">The object type to serialize.</typeparam> /// <param name="t">The instance of the object.</param> /// <param name="inOmitXmlDeclaration"></param> /// <param name="inNameSpaces"></param> /// <param name="inEncoding"></param> public static string SerializeToXml<T>(T t, bool inOmitXmlDeclaration = false, XmlSerializerNamespaces inNameSpaces = null, Encoding inEncoding = null) { var ns = inNameSpaces; if (ns == null) { ns = new XmlSerializerNamespaces(); ns.Add("", ""); } var serializer = new XmlSerializer(t.GetType()); var textWriter = (TextWriter)new StringWriter(); if (inEncoding != null && inEncoding.Equals(Encoding.UTF8)) textWriter = new Utf8StringWriter(); var xmlWriter = XmlWriter.Create(textWriter, new XmlWriterSettings { OmitXmlDeclaration = inOmitXmlDeclaration }); serializer.Serialize(xmlWriter, t, ns); return textWriter.ToString(); } /// <summary> /// This function deserializes the XML file passed in. /// </summary> /// <typeparam name="T">The object type to serialize.</typeparam> /// <param name="inFilename">The file or full path to the file.</param> /// <returns>The object that was deserialized from xml.</returns> public static T DeserializeFromXml<T>(String inFilename) { if (string.IsNullOrWhiteSpace(inFilename)) { return default(T); } // Wait 1 second if file doesn't exist, in case we are waiting on a // separate thread and beat it here. if (!File.Exists(inFilename)) Thread.Sleep(1000); // File should exist by now. if (File.Exists(inFilename)) { var deserializer = new XmlSerializer(typeof(T)); var textReader = (TextReader)new StreamReader(inFilename); var reader = new XmlTextReader(textReader); reader.Read(); var retVal = (T)deserializer.Deserialize(reader); textReader.Close(); return retVal; } throw new FileNotFoundException(inFilename); } /// <summary> /// This function deserializes the XML string passed in. /// </summary> /// <typeparam name="T">The object type to serialize.</typeparam> /// <param name="inString">The string containing the XML.</param> /// <returns>The object that was deserialized from xml.</returns> public static T DeserializeFromXml<T>(ref string inString) { if (string.IsNullOrWhiteSpace(inString)) { return default(T); } var deserializer = new XmlSerializer(typeof(T)); var textReader = (TextReader)new StringReader(inString); var retVal = (T)deserializer.Deserialize(textReader); textReader.Close(); return retVal; } #endregion #region UTF8StringWriter public sealed class Utf8StringWriter : StringWriter { public override Encoding Encoding { get { return Encoding.UTF8; } } } public sealed class Utf8StreamWriter : StreamWriter { public Utf8StreamWriter(string file) : base(file) { } public override Encoding Encoding { get { return Encoding.UTF8; } } } #endregion } }
Sources:
http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer.aspx
http://www.switchonthecode.com/tutorials/csharp-tutorial-xml-serialization
Wouldn't this fail since there isn't a constructor that takes 2 arguments for Blog()?
Ha ha! Your right. That is the result of writing a post over a couple days. You change something when you add more content and forget to update what is already there. I'll update it.