feat: Begin implementing XmlConverters

This commit is contained in:
Chris Cameron
2018-09-09 14:21:25 -04:00
parent 7b30730ea0
commit 2ae8fa9c2d
6 changed files with 379 additions and 0 deletions

View File

@@ -0,0 +1,155 @@
using System;
using System.Xml;
using ICD.Common.Properties;
namespace ICD.Common.Utils.Xml
{
public abstract class AbstractGenericXmlConverter<T> : AbstractXmlConverter
{
/// <summary>
/// Creates a new instance of T.
/// </summary>
/// <returns></returns>
protected virtual T Instantiate()
{
return ReflectionUtils.CreateInstance<T>();
}
/// <summary>
/// Writes the XML representation of the object.
/// </summary>
/// <param name="writer"></param>
/// <param name="elementName"></param>
/// <param name="value">The value.</param>
public sealed override void WriteXml(IcdXmlTextWriter writer, string elementName, object value)
{
if (writer == null)
throw new ArgumentNullException("writer");
if (value == null)
{
writer.WriteElementString(elementName, null);
return;
}
WriteXml(writer, elementName, (T)value);
}
/// <summary>
/// Writes the XML representation of the object.
/// </summary>
/// <param name="writer"></param>
/// <param name="elementName"></param>
/// <param name="value">The value.</param>
[PublicAPI]
public void WriteXml(IcdXmlTextWriter writer, string elementName, T value)
{
if (writer == null)
throw new ArgumentNullException("writer");
if (value == null)
{
writer.WriteElementString(elementName, null);
return;
}
writer.WriteStartElement(elementName);
{
WriteAttributes(writer, value);
WriteElements(writer, value);
}
writer.WriteEndElement();
}
/// <summary>
/// Override to write attributes to the root element.
/// </summary>
/// <param name="writer"></param>
/// <param name="value"></param>
protected virtual void WriteAttributes(IcdXmlTextWriter writer, T value)
{
}
/// <summary>
/// Override to write elements to the writer.
/// </summary>
/// <param name="writer"></param>
/// <param name="value"></param>
protected virtual void WriteElements(IcdXmlTextWriter writer, T value)
{
}
/// <summary>
/// Reads the XML representation of the object.
/// </summary>
/// <param name="reader">The XmlReader to read from.</param>
/// <returns>
/// The object value.
/// </returns>
public sealed override object ReadXml(IcdXmlReader reader)
{
return ReadXmlTyped(reader);
}
/// <summary>
/// Reads the XML representation of the object.
/// </summary>
/// <param name="reader">The XmlReader to read from.</param>
/// <returns>
/// The object value.
/// </returns>
[PublicAPI]
public virtual T ReadXmlTyped(IcdXmlReader reader)
{
T output = default(T);
bool instantiated = false;
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element && reader.IsEmptyElement)
break;
if (!instantiated)
{
instantiated = true;
output = Instantiate();
}
switch (reader.NodeType)
{
case XmlNodeType.Attribute:
ReadAttribute(reader, output);
break;
case XmlNodeType.Element:
ReadElement(reader, output);
break;
}
}
return output;
}
/// <summary>
/// Override to handle the current attribute.
/// </summary>
/// <param name="reader"></param>
/// <param name="instance"></param>
protected virtual void ReadAttribute(IcdXmlReader reader, T instance)
{
// Skip the attribute
reader.Read();
}
/// <summary>
/// Override to handle the current element.
/// </summary>
/// <param name="reader"></param>
/// <param name="instance"></param>
protected virtual void ReadElement(IcdXmlReader reader, T instance)
{
// Skip the element
reader.ReadOuterXml();
}
}
}

View File

@@ -0,0 +1,25 @@
using ICD.Common.Properties;
namespace ICD.Common.Utils.Xml
{
public abstract class AbstractXmlConverter : IXmlConverter
{
/// <summary>
/// Writes the XML representation of the object.
/// </summary>
/// <param name="writer"></param>
/// <param name="elementName"></param>
/// <param name="value">The value.</param>
public abstract void WriteXml(IcdXmlTextWriter writer, string elementName, object value);
/// <summary>
/// Reads the XML representation of the object.
/// </summary>
/// <param name="reader">The XmlReader to read from.</param>
/// <returns>
/// The object value.
/// </returns>
[PublicAPI]
public abstract object ReadXml(IcdXmlReader reader);
}
}

View File

@@ -0,0 +1,32 @@
using System;
namespace ICD.Common.Utils.Xml
{
public sealed class DefaultXmlConverter : AbstractXmlConverter
{
/// <summary>
/// Writes the XML representation of the object.
/// </summary>
/// <param name="writer"></param>
/// <param name="elementName"></param>
/// <param name="value">The value.</param>
public override void WriteXml(IcdXmlTextWriter writer, string elementName, object value)
{
string elementString = IcdXmlConvert.ToString(value);
writer.WriteElementString(elementName, elementString);
}
/// <summary>
/// Reads the XML representation of the object.
/// </summary>
/// <param name="reader">The XmlReader to read from.</param>
/// <returns>
/// The object value.
/// </returns>
public override object ReadXml(IcdXmlReader reader)
{
throw new NotSupportedException();
}
}
}

View File

@@ -0,0 +1,22 @@
namespace ICD.Common.Utils.Xml
{
public interface IXmlConverter
{
/// <summary>
/// Writes the XML representation of the object.
/// </summary>
/// <param name="writer"></param>
/// <param name="elementName"></param>
/// <param name="value">The value.</param>
void WriteXml(IcdXmlTextWriter writer, string elementName, object value);
/// <summary>
/// Reads the XML representation of the object.
/// </summary>
/// <param name="reader">The XmlReader to read from.</param>
/// <returns>
/// The object value.
/// </returns>
object ReadXml(IcdXmlReader reader);
}
}

View File

@@ -1,4 +1,6 @@
using System;
using System.Text;
using ICD.Common.Utils.IO;
#if SIMPLSHARP
using Crestron.SimplSharp.CrestronXml;
#else
@@ -9,6 +11,58 @@ namespace ICD.Common.Utils.Xml
{
public static class IcdXmlConvert
{
/// <summary>
/// Serializes the given instance to an xml string.
/// </summary>
/// <param name="elementName"></param>
/// <param name="value"></param>
/// <returns></returns>
public static string SerializeObject(string elementName, object value)
{
if (value == null)
return ToString(null);
IXmlConverter converter = XmlConverterAttribute.GetConverterForInstance(value);
StringBuilder builder = new StringBuilder();
using (IcdStringWriter stringWriter = new IcdStringWriter(builder))
{
using (IcdXmlTextWriter writer = new IcdXmlTextWriter(stringWriter))
converter.WriteXml(writer, elementName, value);
}
return builder.ToString();
}
/// <summary>
/// Deserializes the given xml to an instance of the given type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="xml"></param>
/// <returns></returns>
public static object DeserializeObject<T>(string xml)
{
return (T)DeserializeObject(typeof(T), xml);
}
/// <summary>
/// Deserializes the given xml to an instance of the given type.
/// </summary>
/// <param name="type"></param>
/// <param name="xml"></param>
/// <returns></returns>
private static object DeserializeObject(Type type, string xml)
{
if (type == null)
throw new ArgumentNullException("type");
IXmlConverter converter = XmlConverterAttribute.GetConverterForInstance(type);
using (IcdXmlReader reader = new IcdXmlReader(xml))
return converter.ReadXml(reader);
}
public static string ToString(int value)
{
return XmlConvert.ToString(value);

View File

@@ -0,0 +1,91 @@
using System;
using System.Collections.Generic;
using ICD.Common.Utils.Attributes;
namespace ICD.Common.Utils.Xml
{
[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)]
public sealed class XmlConverterAttribute : AbstractIcdAttribute
{
private static readonly Dictionary<Type, IXmlConverter> s_InstanceTypeToConverter;
private static readonly Dictionary<Type, IXmlConverter> s_ConverterTypeToConverter;
private readonly Type m_ConverterType;
/// <summary>
/// Gets the converter type.
/// </summary>
public Type ConverterType { get { return m_ConverterType; } }
/// <summary>
/// Static constructor.
/// </summary>
static XmlConverterAttribute()
{
s_InstanceTypeToConverter = new Dictionary<Type, IXmlConverter>();
s_ConverterTypeToConverter = new Dictionary<Type, IXmlConverter>();
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="converterType"></param>
public XmlConverterAttribute(Type converterType)
{
m_ConverterType = converterType;
}
/// <summary>
/// Gets the XML converter for the given instance.
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static IXmlConverter GetConverterForInstance(object value)
{
return value == null ? LazyLoadConverter(typeof(DefaultXmlConverter)) : GetConverterForType(value.GetType());
}
/// <summary>
/// Gets the XML converter for the given type.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public static IXmlConverter GetConverterForType(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
IXmlConverter converter;
if (!s_InstanceTypeToConverter.TryGetValue(type, out converter))
{
XmlConverterAttribute attribute = AttributeUtils.GetClassAttribute<XmlConverterAttribute>(type);
Type converterType = attribute == null ? typeof(DefaultXmlConverter) : attribute.ConverterType;
converter = LazyLoadConverter(converterType);
s_InstanceTypeToConverter[type] = converter;
}
return converter;
}
/// <summary>
/// Lazy-loads the converter of the given type.
/// </summary>
/// <param name="converterType"></param>
/// <returns></returns>
private static IXmlConverter LazyLoadConverter(Type converterType)
{
if (converterType == null)
throw new ArgumentNullException("converterType");
IXmlConverter converter;
if (!s_ConverterTypeToConverter.TryGetValue(converterType, out converter))
{
converter = ReflectionUtils.CreateInstance(converterType) as IXmlConverter;
s_ConverterTypeToConverter[converterType] = converter;
}
return converter;
}
}
}