Click here to Skip to main content
15,886,741 members
Articles / Mobile Apps / Windows Mobile

XML Serialization of Generic Dictionary, Multidimensional Array, and Inherited Type, with sharpSerializer .NET

Rate me:
Please Sign up or sign in to vote.
4.92/5 (48 votes)
9 Nov 2011CPOL8 min read 250.8K   2.9K   122  
How to serialize to XML, any generic, derived, or other complex type, which XMLSerializer cannot serialize
#region Copyright � 2010 Pawel Idzikowski [idzikowski@sharpserializer.com]

//  ***********************************************************************
//  Project: sharpSerializer
//  Web: http://www.sharpserializer.com
//  
//  This software is provided 'as-is', without any express or implied warranty.
//  In no event will the author(s) be held liable for any damages arising from
//  the use of this software.
//  
//  Permission is granted to anyone to use this software for any purpose,
//  including commercial applications, and to alter it and redistribute it
//  freely, subject to the following restrictions:
//  
//      1. The origin of this software must not be misrepresented; you must not
//        claim that you wrote the original software. If you use this software
//        in a product, an acknowledgment in the product documentation would be
//        appreciated but is not required.
//  
//      2. Altered source versions must be plainly marked as such, and must not
//        be misrepresented as being the original software.
//  
//      3. This notice may not be removed or altered from any source distribution.
//  
//  ***********************************************************************

#endregion

using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using Polenter.Serialization.Advanced.Serializing;
using Polenter.Serialization.Advanced.Xml;

namespace Polenter.Serialization.Advanced
{
    /// <summary>
    ///   Reads data which was stored with DefaultXmlWriter
    /// </summary>
    public sealed class DefaultXmlReader : IXmlReader
    {
        private readonly XmlReaderSettings _settings;
        private readonly ITypeNameConverter _typeNameConverter;
        private readonly ISimpleValueConverter _valueConverter;
        private XmlReader _currentReader;
        private Stack<XmlReader> _readerStack;


        ///<summary>
        ///</summary>
        ///<param name = "typeNameConverter"></param>
        ///<param name = "valueConverter"></param>
        ///<param name = "settings"></param>
        ///<exception cref = "ArgumentNullException"></exception>
        public DefaultXmlReader(ITypeNameConverter typeNameConverter, ISimpleValueConverter valueConverter,
                                XmlReaderSettings settings)
        {
            if (typeNameConverter == null) throw new ArgumentNullException("typeNameConverter");
            if (valueConverter == null) throw new ArgumentNullException("valueConverter");
            if (settings == null) throw new ArgumentNullException("settings");

            _typeNameConverter = typeNameConverter;
            _valueConverter = valueConverter;
            _settings = settings;
        }

        #region IXmlReader Members

        /// <summary>
        ///   Reads next valid element
        /// </summary>
        /// <returns>null if nothing was found</returns>
        public string ReadElement()
        {
            while (_currentReader.Read())
            {
                if (_currentReader.NodeType != XmlNodeType.Element) continue;

                return _currentReader.Name;
            }
            return null;
        }

        /// <summary>
        ///   Reads all sub elements of the current element
        /// </summary>
        /// <returns></returns>
        public IEnumerable<string> ReadSubElements()
        {
            // Position the reader on an element
            _currentReader.MoveToElement();

            // create the subReader
            XmlReader subReader = _currentReader.ReadSubtree();

            // positions the new XmlReader on the node that was current before the call to ReadSubtree method
            // http://msdn.microsoft.com/query/dev10.query?appId=Dev10IDEF1&l=EN-US&k=k%28SYSTEM.XML.XMLREADER.READSUBTREE%29;k%28TargetFrameworkMoniker-%22.NETFRAMEWORK%2cVERSION%3dV2.0%22%29;k%28DevLang-CSHARP%29&rd=true
            subReader.Read();

            pushCurrentReader(subReader);

            try
            {
                // read the first valid element
                string name = ReadElement();

                // read further elements
                while (!string.IsNullOrEmpty(name))
                {
                    yield return name;
                    name = ReadElement();
                }
            }
            finally
            {
                // Close the current reader,
                // it positions the parent reader on the last node of the subReader
                subReader.Close();
                // aktualise the current Reader
                popCurrentReader();
            }
        }


        /// <summary>
        ///   Reads attribute as string
        /// </summary>
        /// <param name = "attributeName"></param>
        /// <returns>null if nothing was found</returns>
        public string GetAttributeAsString(string attributeName)
        {
            if (!_currentReader.MoveToAttribute(attributeName)) return null;
            return _currentReader.Value;
        }

        /// <summary>
        ///   Reads attribute and converts it to type
        /// </summary>
        /// <param name = "attributeName"></param>
        /// <returns>null if nothing found</returns>
        public Type GetAttributeAsType(string attributeName)
        {
            string typeName = GetAttributeAsString(attributeName);
            return _typeNameConverter.ConvertToType(typeName);
        }

        /// <summary>
        ///   Reads attribute and converts it to integer
        /// </summary>
        /// <param name = "attributeName"></param>
        /// <returns>0 if nothing found</returns>
        public int GetAttributeAsInt(string attributeName)
        {
            if (!_currentReader.MoveToAttribute(attributeName)) return 0;
            return _currentReader.ReadContentAsInt();
        }

        /// <summary>
        ///   Reads attribute and converts it as array of int
        /// </summary>
        /// <param name = "attributeName"></param>
        /// <returns>empty array if nothing found</returns>
        public int[] GetAttributeAsArrayOfInt(string attributeName)
        {
            if (!_currentReader.MoveToAttribute(attributeName)) return null;
            return getArrayOfIntFromText(_currentReader.Value);
        }

        /// <summary>
        ///   Reads attribute and converts it to object of the expectedType
        /// </summary>
        /// <param name = "attributeName"></param>
        /// <param name = "expectedType"></param>
        /// <returns></returns>
        public object GetAttributeAsObject(string attributeName, Type expectedType)
        {
            string objectAsText = GetAttributeAsString(attributeName);
            return _valueConverter.ConvertFromString(objectAsText, expectedType);
        }

        /// <summary>
        ///   Open the stream
        /// </summary>
        /// <param name = "stream"></param>
        public void Open(Stream stream)
        {
            _readerStack = new Stack<XmlReader>();

            XmlReader reader = XmlReader.Create(stream, _settings);

            // set the main reader
            pushCurrentReader(reader);
        }

        /// <summary>
        ///   Stream can be further used
        /// </summary>
        public void Close()
        {
            _currentReader.Close();
        }

        #endregion

        /// <summary>
        ///   Remove one reader from stack and reset the current reader
        /// </summary>
        private void popCurrentReader()
        {
            // Remove one reader from the stack
            if (_readerStack.Count > 0)
            {
                _readerStack.Pop();
            }

            if (_readerStack.Count > 0)
            {
                _currentReader = _readerStack.Peek();
                return;
            }

            _currentReader = null;
        }

        /// <summary>
        ///   Add reader to stack and set it the current reader
        /// </summary>
        /// <param name = "reader"></param>
        private void pushCurrentReader(XmlReader reader)
        {
            _readerStack.Push(reader);

            _currentReader = reader;
        }

        /// <summary>
        ///   Converts text in form "1,2,3,4,5" to int[] {1,2,3,4,5}
        /// </summary>
        /// <param name = "text"></param>
        /// <returns>null if no items are recognized or the text is null or empty</returns>
        private static int[] getArrayOfIntFromText(string text)
        {
            if (string.IsNullOrEmpty(text)) return null;

            string[] splittedString = text.Split(new[] {','});
            if (splittedString.Length == 0) return null;

            var result = new List<int>();
            foreach (string s in splittedString)
            {
                int i = int.Parse(s);
                result.Add(i);
            }
            return result.ToArray();
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Polenter - Software Solutions
Germany Germany
I'm C# developer from Cologne, Germany. Here I owe a small software company. My hobby is general optimization - natural talent of all lazy people Wink | ;-)

Comments and Discussions