questions/49932706/deserialize-portion-of-xmldocument-into-object

CSharp · Console

/Program.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Xml.Serialization;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
using System.IO;
using System.Data;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO.Compression;

using NUnit.Framework; // Throws NUnit.Framework.AssertionException

// https://stackoverflow.com/questions/49932706/deserialize-portion-of-xmldocument-into-object?noredirect=1#49932706

	public class ReportParameterValuesXDto 
	{
		[XmlElement(ElementName="value")]
		public string Value { get; set; }
		[XmlElement(ElementName="used")]
		public string Used { get; set; }
	}

	public class ReportParametersXDto 
	{
		[XmlElement(ElementName="dataType")]
		public string DataType { get; set; }
		[XmlElement(ElementName="title")]
		public string Title { get; set; }
		[XmlElement(ElementName="index")]
		public string Index { get; set; }
		[XmlElement(ElementName="allowMulti")]
		public string AllowMulti { get; set; }
		[XmlElement(ElementName="selectSql")]
		public string SelectSql { get; set; }
		[XmlElement(ElementName="values")]
		public List<ReportParameterValuesXDto> Values { get; set; }
	}

	public class ReportXDto 
	{
		[XmlElement(ElementName="id")]
		public string Id { get; set; }
		[XmlElement(ElementName="reportTitle")]
		public string ReportTitle { get; set; }
		[XmlElement(ElementName="hasParameters")]
		public string HasParameters { get; set; }
		[XmlElement(ElementName="parameters")]
		public ReportParametersXDto Parameters { get; set; }
		[XmlElement(ElementName="sourceSql")]
		public string SourceSql { get; set; }
		[XmlElement(ElementName="report")]
		public string Report { get; set; }
	}

    public static partial class XmlExtensions
    {
		public static IEnumerable<T> DeserializeElements<T>(this XmlNode root, string localName, string namespaceUri)
		{
			return new XmlNodeReader(root).DeserializeElements<T>(localName, namespaceUri);
		}
		
		public static IEnumerable<T> DeserializeElements<T>(this XmlReader reader, string localName, string namespaceUri)
		{
            var serializer = XmlSerializerFactory.Create(typeof(T), localName, namespaceUri);
			while (!reader.EOF)
			{
				if (!(reader.NodeType == XmlNodeType.Element && reader.LocalName == localName && reader.NamespaceURI == namespaceUri))
					reader.ReadToFollowing(localName, namespaceUri);
				
				if (!reader.EOF)
				{
					yield return (T)serializer.Deserialize(reader);
					// Note that the serializer will advance the reader past the end of the node
				}				
			}
		}
    }

    public static class XmlSerializerFactory
    {
        // To avoid a memory leak the serializer must be cached.
        // https://stackoverflow.com/questions/23897145/memory-leak-using-streamreader-and-xmlserializer
        // This factory taken from 
        // https://stackoverflow.com/questions/34128757/wrap-properties-with-cdata-section-xml-serialization-c-sharp/34138648#34138648

        readonly static Dictionary<Tuple<Type, string, string>, XmlSerializer> cache;
        readonly static object padlock;

        static XmlSerializerFactory()
        {
            padlock = new object();
            cache = new Dictionary<Tuple<Type, string, string>, XmlSerializer>();
        }

        public static XmlSerializer Create(Type serializedType, string rootName, string rootNamespace)
        {
            if (serializedType == null)
                throw new ArgumentNullException();
            if (rootName == null && rootNamespace == null)
                return new XmlSerializer(serializedType);
            lock (padlock)
            {
                XmlSerializer serializer;
                var key = Tuple.Create(serializedType, rootName, rootNamespace);
                if (!cache.TryGetValue(key, out serializer))
                    cache[key] = serializer = new XmlSerializer(serializedType, new XmlRootAttribute { ElementName = rootName, Namespace = rootNamespace });
                return serializer;
            }
        }
    }

    public class TestClass
    {
        public static void Test()
        {
			var doc = new XmlDocument();
			doc.LoadXml(GetXml());

			var modelData = doc.DeserializeElements<ReportXDto>("modelData", "").FirstOrDefault();

			Assert.IsTrue(modelData != null);
			var node = doc.SelectSingleNode("/root/data/modelData");
			Assert.IsTrue(node != null);
			Assert.IsTrue(node.SelectSingleNode("id").InnerText == modelData.Id);
			Assert.IsTrue(node.SelectNodes("parameters/values").Count == modelData.Parameters.Values.Count);
			
			var newXml = modelData.GetXml(true);
						
			Console.WriteLine(newXml);
        }
		
		static string GetXml()
		{
			var xml = @"<?xml version=""1.0""?>
<root>
  <status>
      <apiErrorCode>0</apiErrorCode>
      <apiErrorMessage/>
      <dbErrorCode>0</dbErrorCode>
      <dbErrorMessage/>
      <dbErrorList/>
  </status>
<data>
    <modelName>ReportXDTO</modelName>
    <modelData>
        <id>1780</id>
        <reportTitle>Access Level (select) with Door Assignment</reportTitle>
        <hasParameters>true</hasParameters>
        <parameters>
            <dataType>STRING</dataType>
            <title>Access Level:</title>
            <index>1</index>
            <allowMulti>true</allowMulti>
            <selectSql>SELECT DISTINCT [Name] FROM dbo.[Levels] WHERE [PrecisionFlag] = '0' ORDER BY [Name] </selectSql>
            <values>
                <value>Door 1</value>
                <used>1</used>
            </values>
            <values>
                <value>Door 2</value>
                <used>1</used>
            </values>
            <values>
                <value>Door 3</value>
                <used>1</used>
            </values>
       </parameters>
       <sourceSql>SELECT [Name], [SData] FROM [Schedules]</sourceSql>
       <report/>
   </modelData><modelData></modelData><modelData><id>-1</id></modelData>
   <itemReturned>1</itemReturned>
   <itemTotal>1</itemTotal>
</data>
<listInfo>
    <pageIdRequested>1</pageIdRequested>
    <pageIdCurrent>1</pageIdCurrent>
    <pageIdFirst>1</pageIdFirst>
    <pageIdPrev>1</pageIdPrev>
    <pageIdNext>1</pageIdNext>
    <pageIdLast>1</pageIdLast>
    <itemRequested>1</itemRequested>
    <itemReturned>1</itemReturned>
    <itemStart>1</itemStart>
    <itemEnd>1</itemEnd>
    <itemTotal>1</itemTotal>
</listInfo>
</root>
";
			return xml;
		}
    }

    public static class XmlSerializationHelper
    {
        public static T LoadFromXml<T>(this string xmlString, XmlSerializer serial = null)
        {
            serial = serial ?? new XmlSerializer(typeof(T));
            using (var reader = new StringReader(xmlString))
            {
				return (T)serial.Deserialize(reader);
            }
        }

        public static string GetXml<T>(this T obj, bool omitStandardNamespaces)
        {
			return obj.GetXml(null, omitStandardNamespaces);
        }
		
        public static string GetXml<T>(this T obj, XmlSerializer serializer = null, bool omitStandardNamespaces = false)
        {
            XmlSerializerNamespaces ns = null;
            if (omitStandardNamespaces)
            {
                ns = new XmlSerializerNamespaces();
                ns.Add("", ""); // Disable the xmlns:xsi and xmlns:xsd lines.
            }			
            using (var textWriter = new StringWriter())
            {
                var settings = new XmlWriterSettings() { Indent = true }; // For cosmetic purposes.
                using (var xmlWriter = XmlWriter.Create(textWriter, settings))
                    (serializer ?? new XmlSerializer(obj.GetType())).Serialize(xmlWriter, obj, ns);
                return textWriter.ToString();
            }
        }
		
		public static string GetOuterXml(this XmlNode node, bool indent = true)
		{
			if (node == null)
				return null;
			using (var textWriter = new StringWriter())
			{
				var settings = new XmlWriterSettings
				{
					Indent = indent,
					OmitXmlDeclaration = true,
				};
				using (var xmlWriter = XmlWriter.Create(textWriter, settings))
				{
					node.WriteTo(xmlWriter);
				}
				return textWriter.ToString();
			}
		}
    }
				
	public class Program
	{
		public static void Main()
		{
			Console.WriteLine("Roslyn 2.0 Compiler; Environment version: " + Environment.Version);
			Console.WriteLine();

			try
			{
				TestClass.Test();
			}
			catch (Exception ex)
			{
				Console.WriteLine("Uncaught exception: ");
				Console.WriteLine(ex);
				throw;
			}
		}
	}
;