From 7188208b6bdac500a64991e53307236a1a041da6 Mon Sep 17 00:00:00 2001 From: Flamefire Date: Thu, 30 Oct 2014 19:21:28 +0100 Subject: [PATCH] Add documentation --- Vocaluxe/Base/CPlaylists.cs | 4 +- VocaluxeLib/Menu/CEqualizer.cs | 2 +- VocaluxeLib/Menu/CPlaylist.cs | 2 +- VocaluxeLib/VocaluxeLib.csproj | 1 + VocaluxeLib/Xml/CTypeExtensions.cs | 112 ++++++++------- VocaluxeLib/Xml/CXmlDeserializer.cs | 213 +++++++++++++++++++++------- VocaluxeLib/Xml/CXmlSerializer.cs | 105 ++++++++++---- VocaluxeLib/XmlStructs.cs | 19 ++- VocaluxeTests/XmlSerializerTest.cs | 7 +- 9 files changed, 330 insertions(+), 135 deletions(-) diff --git a/Vocaluxe/Base/CPlaylists.cs b/Vocaluxe/Base/CPlaylists.cs index fac2f20c..f2f84ed8 100644 --- a/Vocaluxe/Base/CPlaylists.cs +++ b/Vocaluxe/Base/CPlaylists.cs @@ -78,8 +78,8 @@ namespace Vocaluxe.Base foreach (string file in files) { CPlaylistFile playlist = new CPlaylistFile(); - if(playlist._Load(file)) - _Playlists.Add(playlist); + if (playlist._Load(file)) + _Playlists.Add(playlist); } } diff --git a/VocaluxeLib/Menu/CEqualizer.cs b/VocaluxeLib/Menu/CEqualizer.cs index aa9e76da..010b8e80 100644 --- a/VocaluxeLib/Menu/CEqualizer.cs +++ b/VocaluxeLib/Menu/CEqualizer.cs @@ -149,7 +149,7 @@ namespace VocaluxeLib.Menu _ThemeLoaded &= xmlReader.TryGetFloatValue(item + "/Reflection/Space", ref ReflectionSpace); _ThemeLoaded &= xmlReader.TryGetFloatValue(item + "/Reflection/Height", ref ReflectionHeight); - _Theme.Reflection = new SReflection( ReflectionHeight, ReflectionSpace); + _Theme.Reflection = new SReflection(ReflectionHeight, ReflectionSpace); } else { diff --git a/VocaluxeLib/Menu/CPlaylist.cs b/VocaluxeLib/Menu/CPlaylist.cs index 11e0c052..d3dc8906 100644 --- a/VocaluxeLib/Menu/CPlaylist.cs +++ b/VocaluxeLib/Menu/CPlaylist.cs @@ -52,7 +52,7 @@ namespace VocaluxeLib.Menu CSong song = CBase.Songs.GetSongByID(SongID); if (song == null) throw new Exception("Can't find Song. This should never happen!"); - return new SPlaylistSong{Artist = song.Artist, Title = song.Title, GameMode = GameMode}; + return new SPlaylistSong {Artist = song.Artist, Title = song.Title, GameMode = GameMode}; } } diff --git a/VocaluxeLib/VocaluxeLib.csproj b/VocaluxeLib/VocaluxeLib.csproj index 1dcf7041..de99965a 100644 --- a/VocaluxeLib/VocaluxeLib.csproj +++ b/VocaluxeLib/VocaluxeLib.csproj @@ -145,6 +145,7 @@ + diff --git a/VocaluxeLib/Xml/CTypeExtensions.cs b/VocaluxeLib/Xml/CTypeExtensions.cs index 2d937752..15a3c564 100644 --- a/VocaluxeLib/Xml/CTypeExtensions.cs +++ b/VocaluxeLib/Xml/CTypeExtensions.cs @@ -1,4 +1,21 @@ -using System; +#region license +// This file is part of Vocaluxe. +// +// Vocaluxe is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Vocaluxe is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Vocaluxe. If not, see . +#endregion + +using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; @@ -9,6 +26,9 @@ using System.Xml.Serialization; namespace VocaluxeLib.Xml { // ReSharper disable InconsistentNaming + /// + /// Attribute containing an alternative name in the xml files during deserialization + /// [AttributeUsage(AttributeTargets.Field)] public class XmlAltNameAttribute : Attribute { @@ -20,9 +40,15 @@ namespace VocaluxeLib.Xml } } + /// + /// Attribute for float fields to enforce normalized (0<=x<=1) values + /// [AttributeUsage(AttributeTargets.Field)] public class XmlNormalizedAttribute : Attribute {} + /// + /// Attribute for int fields to enforce values in the given range + /// [AttributeUsage(AttributeTargets.Field)] public class XmlRangedAttribute : Attribute { @@ -38,58 +64,9 @@ namespace VocaluxeLib.Xml // ReSharper restore InconsistentNaming - public struct SFieldInfo - { - private readonly FieldInfo _Field; - private readonly PropertyInfo _Property; - - public Type Type - { - get { return _Field != null ? _Field.FieldType : _Property.PropertyType; } - } - public string Name; - public string AltName; - public object DefaultValue; - public bool HasDefaultValue; - public bool IsAttribute; - public bool IsList; //List with child elements () - public bool IsEmbeddedList; //List w/o child elements() - public bool IsDictionary; //List where the element names are the keys - public bool IsByteArray; // Byte arrays w/o XmlArrayAttribute are serialized as Base64-Encoded strings - public bool IsNullable; - public bool IsNormalized; - public XmlRangedAttribute Ranged; - public Type SubType; - public string ArrayItemName; - - public SFieldInfo(FieldInfo field) - : this() - { - _Field = field; - } - - public SFieldInfo(PropertyInfo property) - : this() - { - _Property = property; - } - - public void SetValue(object o, object value) - { - if (_Field != null) - _Field.SetValue(o, value); - else - _Property.SetValue(o, value, new object[] {}); - } - - public object GetValue(object o) - { - return (_Field != null) ? _Field.GetValue(o) : _Property.GetValue(o, new object[] {}); - } - } - public static class CTypeExtensions { + // Cache for fields to speed up access to common types private static readonly Dictionary> _CacheFields = new Dictionary>(); private static readonly Dictionary _CacheTypeName = new Dictionary(); @@ -110,6 +87,11 @@ namespace VocaluxeLib.Xml return subType.GetTypeName(); } + /// + /// Fills the struct with information about the field + /// + /// Struct to fill + /// Field descrived by the struct private static void _FillInfo(ref SFieldInfo info, MemberInfo field) { XmlAttributeAttribute attribute = field.GetAttribute(); @@ -193,6 +175,11 @@ namespace VocaluxeLib.Xml } } + /// + /// Returns a collection with infos about all fields and properties of the type that can be (xml-)serialized + /// + /// Type to get information about + /// public static IEnumerable GetFieldInfos(this Type type) { List result; @@ -221,11 +208,22 @@ namespace VocaluxeLib.Xml return result; } + /// + /// Returns a collection with infos about all fields and properties of the type that can be (xml-)serialized but limits it to those which are (xml)-nodes or attributes + /// + /// Type to get information about + /// True to return infos about attributes, false for nodes + /// public static List GetFields(this Type type, bool attributes) { return GetFieldInfos(type).Where(f => f.IsAttribute == attributes).ToList(); } + /// + /// Gets the (xml)-type name for the type (influenced by XmlTypeAttributes) + /// + /// + /// public static string GetTypeName(this Type type) { string name; @@ -244,11 +242,23 @@ namespace VocaluxeLib.Xml return name; } + /// + /// Returns true if the field has the attribute + /// + /// Attribute type + /// + /// public static bool HasAttribute(this ICustomAttributeProvider field) { return field.GetCustomAttributes(typeof(T), false).Length > 0; } + /// + /// Gets the first attribute with the given type or null if none found + /// + /// Attribute type + /// + /// public static T GetAttribute(this ICustomAttributeProvider field) where T : class { object[] attributes = field.GetCustomAttributes(typeof(T), false); diff --git a/VocaluxeLib/Xml/CXmlDeserializer.cs b/VocaluxeLib/Xml/CXmlDeserializer.cs index 6b1beb59..a6299991 100644 --- a/VocaluxeLib/Xml/CXmlDeserializer.cs +++ b/VocaluxeLib/Xml/CXmlDeserializer.cs @@ -1,4 +1,21 @@ -using System; +#region license +// This file is part of Vocaluxe. +// +// Vocaluxe is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Vocaluxe is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Vocaluxe. If not, see . +#endregion + +using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; @@ -14,6 +31,11 @@ namespace VocaluxeLib.Xml public class CXmlDeserializer { #region Debug Helpers + /// + /// Returns the xPath from root to the node + /// + /// + /// private string _GetXPath(XmlNode node) { StringBuilder builder = new StringBuilder(); @@ -39,6 +61,11 @@ namespace VocaluxeLib.Xml throw new ArgumentException("Node was not in a document"); } + /// + /// Returns an index as a string or empty string if the node name is sufficient to identify the node + /// + /// + /// private string _FindElementIndex(XmlNode element) { XmlNode parentNode = element.ParentNode; @@ -60,7 +87,15 @@ namespace VocaluxeLib.Xml } #endregion Debug Helpers - private object _GetValue(XmlNode node, Type type, string arrayItemName = null, object result = null) + /// + /// Returns the value if the given node + /// + /// Node to process + /// Type of the object at that node + /// Name of the sub nodes for array types(Array,List,Dictionary), can be set by XmlArrayItemAttribute and defaults to the type name + /// If given, no new class is created and value is used instead + /// + private object _GetValue(XmlNode node, Type type, string subName = null, object value = null) { if (type.IsEnum) { @@ -83,12 +118,13 @@ namespace VocaluxeLib.Xml if (!node.HasChildNodes) return null; Type subType = type.GetGenericArguments()[0]; - return _GetValue(node, subType, arrayItemName, result); + return _GetValue(node, subType, subName, value); } if (type.IsList() || type.IsArray) { Type subType = type.IsArray ? type.GetElementType() : type.GetGenericArguments()[0]; - String subName = arrayItemName ?? subType.GetTypeName(); + if (subName == null) + subName = subType.GetTypeName(); subName = subName.ToLowerInvariant(); List subValues = new List(); foreach (XmlNode subNode in node.ChildNodes) @@ -100,56 +136,64 @@ namespace VocaluxeLib.Xml object subValue = _GetValue(subNode, subType); subValues.Add(subValue); } - if (result == null) + if (value == null) return _CreateList(type, subValues); - _FillList(result, type, subValues); - return result; + _FillList(value, type, subValues); + return value; } if (type.IsDictionary()) { Type subType = type.GetGenericArguments()[1]; - object dict = result ?? Activator.CreateInstance(type); + object dict = value ?? Activator.CreateInstance(type); MethodInfo add = type.GetMethod("Add"); - if (arrayItemName != null) - arrayItemName = arrayItemName.ToLowerInvariant(); + if (subName != null) + subName = subName.ToLowerInvariant(); foreach (XmlNode subNode in node.ChildNodes) { if (subNode is XmlComment) continue; object subValue = _GetValue(subNode, subType); - string subName; - if (arrayItemName != null) + string key; + if (subName != null) { - if (arrayItemName != subNode.Name.ToLowerInvariant() && !subNode.Name.ToLowerInvariant().StartsWith(arrayItemName)) - throw new XmlException("Invalid dictionary entry '" + subNode.Name + "' in " + _GetXPath(node) + "; Expected: " + arrayItemName); + if (subName != subNode.Name.ToLowerInvariant() && !subNode.Name.ToLowerInvariant().StartsWith(subName)) + throw new XmlException("Invalid dictionary entry '" + subNode.Name + "' in " + _GetXPath(node) + "; Expected: " + subName); if (subNode.Attributes == null) throw new XmlException("'name' attribute is missing in " + _GetXPath(subNode)); XmlNode nameAtt = subNode.Attributes.GetNamedItem("name"); if (nameAtt == null) throw new XmlException("'name' attribute is missing in " + _GetXPath(subNode)); - subName = nameAtt.Value; + key = nameAtt.Value; } else - subName = subNode.Name; - add.Invoke(dict, new object[] { subName, subValue }); + key = subNode.Name; + add.Invoke(dict, new object[] {key, subValue}); } return dict; } - object value; - try + if (value == null) { - value = result ?? Activator.CreateInstance(type); + try + { + value = Activator.CreateInstance(type); + } + catch (Exception) + { + throw new XmlException("Could not create instance of " + _GetXPath(node) + "(Type=" + type.Name + ")"); + } } - catch (Exception) - { - throw new XmlException("Could not create instance of " + _GetXPath(node) + "(Type=" + type.Name + ")"); - } - _ReadChildNodes(node, ref value, true); - _ReadChildNodes(node, ref value, false); + _ReadChildNodes(node, value, true); + _ReadChildNodes(node, value, false); return value; } + /// + /// Gets the node's value assuming it is a primitive (int,float,...) + /// + /// + /// + /// private object _GetPrimitiveValue(XmlNode node, Type type) { object value; @@ -177,6 +221,12 @@ namespace VocaluxeLib.Xml return value; } + /// + /// Sets the field to its default value if it has one (specified as DefaultValueAttribute or an empty collection if it is an embedded one) + /// + /// + /// + /// True if default value was set private static bool _CheckAndSetDefaultValue(object result, SFieldInfo field) { if (field.IsEmbeddedList) @@ -190,6 +240,12 @@ namespace VocaluxeLib.Xml return true; } + /// + /// Fills the specified collection (array or list) with the values + /// + /// List to fill + /// Type of the list + /// Collection of values private static void _FillList(object list, Type type, ICollection values) { if (values.Count <= 0) @@ -205,23 +261,41 @@ namespace VocaluxeLib.Xml { MethodInfo addMethod = type.GetMethod("Add"); foreach (object value in values) - addMethod.Invoke(list, new object[] { value }); + addMethod.Invoke(list, new object[] {value}); } } + /// + /// Creates a collection (array or list) and fills it with the values + /// + /// Type of the collection to be created + /// Collection of values + /// Newly created collection private static object _CreateList(Type type, ICollection values) { - object list = type.IsArray ? Array.CreateInstance(type.GetElementType(), values.Count) : Activator.CreateInstance(type, new object[] { values.Count }); + object list = type.IsArray ? Array.CreateInstance(type.GetElementType(), values.Count) : Activator.CreateInstance(type, new object[] {values.Count}); _FillList(list, type, values); return list; } - private static void _AddList(object result, SFieldInfo listField, ICollection list) + /// + /// Creates a collection (array or list) and puts it into the specified field + /// + /// Object which listField belongs to + /// Field that will contain the list + /// Collection of values that are used to fill the list + private static void _AddList(object o, SFieldInfo listField, ICollection values) { - listField.SetValue(result, _CreateList(listField.Type, list)); + listField.SetValue(o, _CreateList(listField.Type, values)); } - private void _ReadChildNodes(XmlNode parent, ref object result, bool attributes) + /// + /// Reads childnodes of the given node (either nodes or attributes) + /// + /// Node to process + /// Object to put the values in + /// True for processing attributes, false for nodes + private void _ReadChildNodes(XmlNode parent, object o, bool attributes) { IEnumerable nodes; if (attributes) @@ -229,7 +303,7 @@ namespace VocaluxeLib.Xml else nodes = parent.ChildNodes; - List fields = result.GetType().GetFields(attributes); + List fields = o.GetType().GetFields(attributes); if (nodes != null) { @@ -258,7 +332,7 @@ namespace VocaluxeLib.Xml if (field.IsByteArray) { - field.SetValue(result, Convert.FromBase64String(node.InnerText)); + field.SetValue(o, Convert.FromBase64String(node.InnerText)); fields.RemoveAt(curField); } else if (field.IsEmbeddedList) @@ -298,29 +372,35 @@ namespace VocaluxeLib.Xml ")"); } } - field.SetValue(result, value); + field.SetValue(o, value); fields.RemoveAt(curField); } } //Add embedded lists foreach (Tuple> entry in embLists.Values) { - _AddList(result, entry.Item1, entry.Item2); + _AddList(o, entry.Item1, entry.Item2); fields.Remove(entry.Item1); } } foreach (SFieldInfo field in fields) { - if (!_CheckAndSetDefaultValue(result, field)) + if (!_CheckAndSetDefaultValue(o, field)) throw new XmlException("element: " + field.Name + " is missing in " + _GetXPath(parent)); } } - - private T _Deserialize(XmlReader reader, object result) where T : new() + /// + /// Deserializes the content of read into the given object + /// + /// + /// + /// + /// Deserialized object + private T _Deserialize(XmlReader reader, object o) where T : new() { if (reader.IsEmptyElement) - return (T)result; + return (T)o; XmlDocument xDoc = new XmlDocument(); xDoc.Load(reader); @@ -328,28 +408,42 @@ namespace VocaluxeLib.Xml throw new XmlException("No root element found!"); try { - result = _GetValue(xDoc.DocumentElement, typeof(T), typeof(T).GetSubTypeName(), result); + o = _GetValue(xDoc.DocumentElement, o.GetType(), o.GetType().GetSubTypeName(), o); } catch (TargetInvocationException e) { throw e.InnerException ?? e; } - return (T)result; + return (T)o; } + /// + /// Deserializes the given xml string and returns the resulting object + /// + /// Type of the object contained in the xml + /// xml string + /// New object of type T public T DeserializeString(string xml) where T : new() { return DeserializeString(xml, new T()); } + /// + /// Deserializes the given xml string and returns the resulting object
+ /// Does not create a new object but reuses the given one overwriting its values + ///
+ /// Type of the object contained in the xml + /// xml string + /// Existing object + /// New object of type T public T DeserializeString(string xml, T o) where T : new() { var reader = new XmlTextReader(new StringReader(xml)) - { - WhitespaceHandling = WhitespaceHandling.Significant, - Normalization = true, - XmlResolver = null - }; + { + WhitespaceHandling = WhitespaceHandling.Significant, + Normalization = true, + XmlResolver = null + }; try { return _Deserialize(reader, o); @@ -360,21 +454,35 @@ namespace VocaluxeLib.Xml } } + /// + /// Deserializes the given file and returns the resulting object + /// + /// Type of the object contained in the xml + /// Full path to the file + /// New object of type T public T Deserialize(string filePath) where T : new() { return Deserialize(filePath, new T()); } + /// + /// Deserializes the given file and returns the resulting object
+ /// Does not create a new object but reuses the given one overwriting its values + ///
+ /// Type of the object contained in the xml + /// Full path to the file + /// Existing object + /// New object of type T public T Deserialize(string filePath, T o) where T : new() { if (!File.Exists(filePath)) throw new FileNotFoundException(filePath); var reader = new XmlTextReader(filePath) - { - WhitespaceHandling = WhitespaceHandling.Significant, - Normalization = true, - XmlResolver = null - }; + { + WhitespaceHandling = WhitespaceHandling.Significant, + Normalization = true, + XmlResolver = null + }; try { return _Deserialize(reader, o); @@ -384,6 +492,5 @@ namespace VocaluxeLib.Xml reader.Close(); } } - } -} +} \ No newline at end of file diff --git a/VocaluxeLib/Xml/CXmlSerializer.cs b/VocaluxeLib/Xml/CXmlSerializer.cs index c0282457..ed790901 100644 --- a/VocaluxeLib/Xml/CXmlSerializer.cs +++ b/VocaluxeLib/Xml/CXmlSerializer.cs @@ -1,4 +1,21 @@ -using System; +#region license +// This file is part of Vocaluxe. +// +// Vocaluxe is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Vocaluxe is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Vocaluxe. If not, see . +#endregion + +using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; @@ -17,6 +34,11 @@ namespace VocaluxeLib.Xml private readonly GetCommentDelegate _GetCommentCallback; private readonly bool _WriteDefaults; + /// + /// Creates a new serializer + /// + /// When true, also nodes with default values will be written + /// Callback that is called for each node and should return a string that will be used as a comment public CXmlSerializer(bool writeDefaults = false, GetCommentDelegate getCommentCallback = null) { _WriteDefaults = writeDefaults; @@ -33,7 +55,17 @@ namespace VocaluxeLib.Xml ConformanceLevel = ConformanceLevel.Document }; - private void _WriteNode(XmlWriter writer, string name, Type type, object value, bool isAttribute, string arrayItemName = null, string nameAttribute = null) + /// + /// Writes a value as a node or attribute + /// + /// XmlWriter to use + /// Name of the node/attribute + /// Type of the value + /// Object to write + /// When true, value will be written as an attribute to the currently open node, otherwhise it will create a new node + /// >Name of the sub nodes for array types(Array,List,Dictionary), can be set by XmlArrayItemAttribute and defaults to the type name + /// If set, an attribute 'name' with this value will be written + private void _WriteValue(XmlWriter writer, string name, Type type, object value, bool isAttribute, string arrayItemName = null, string nameAttribute = null) { if (!isAttribute && _GetCommentCallback != null) { @@ -65,7 +97,7 @@ namespace VocaluxeLib.Xml } } else if (type.IsNullable()) - _WriteNode(writer, name, type.GetGenericArguments()[0], value, isAttribute, arrayItemName, nameAttribute); + _WriteValue(writer, name, type.GetGenericArguments()[0], value, isAttribute, arrayItemName, nameAttribute); else if (type.IsList() || type.IsArray) { Debug.Assert(!isAttribute, "Lists cannot be attributes"); @@ -76,7 +108,7 @@ namespace VocaluxeLib.Xml String subName = arrayItemName ?? subType.GetTypeName(); IEnumerable list = (IEnumerable)value; foreach (object subValue in list) - _WriteNode(writer, subName, subType, subValue, false); + _WriteValue(writer, subName, subType, subValue, false); writer.WriteEndElement(); } else if (type.IsDictionary()) @@ -101,7 +133,7 @@ namespace VocaluxeLib.Xml subName = arrayItemName; subNameAttribute = (string)entry.Key; } - _WriteNode(writer, subName, subType, entry.Value, false, null, subNameAttribute); + _WriteValue(writer, subName, subType, entry.Value, false, null, subNameAttribute); } writer.WriteEndElement(); } @@ -112,12 +144,17 @@ namespace VocaluxeLib.Xml if (nameAttribute != null) writer.WriteAttributeString("name", nameAttribute); if (value != null) - _WriteChildNodes(writer, value); + _WriteFields(writer, value); writer.WriteEndElement(); } } - private void _WriteChildNodes(XmlWriter writer, object o) + /// + /// Writes the fields of the given object, does not write the node tags itself + /// + /// XmlWriter to use + /// Object to process + private void _WriteFields(XmlWriter writer, object o) { IEnumerable fields = o.GetType().GetFieldInfos(); foreach (SFieldInfo field in fields) @@ -129,33 +166,41 @@ namespace VocaluxeLib.Xml { IEnumerable values = (IEnumerable)value; foreach (object subValue in values) - _WriteNode(writer, field.Name, field.SubType, subValue, field.IsAttribute); + _WriteValue(writer, field.Name, field.SubType, subValue, field.IsAttribute); } else if (field.IsByteArray) writer.WriteElementString(field.Name, Convert.ToBase64String((byte[])value)); else - _WriteNode(writer, field.Name, field.Type, value, field.IsAttribute, field.ArrayItemName); + _WriteValue(writer, field.Name, field.Type, value, field.IsAttribute, field.ArrayItemName); } } - private void _Serialize(object o, XmlWriter writer) + /// + /// Serializes the given object using the writer + /// + /// XmlWriter to use + /// Object to serialize + /// (optional) Name of the root node (overwrites default value specified by XmlRoot/XmlTypeAttributes which defaults to "root") + private void _Serialize(XmlWriter writer, object o, string rootNodeName) { - XmlRootAttribute root = o.GetType().GetAttribute(); - string name; - if (root != null && !string.IsNullOrEmpty(root.ElementName)) - name = root.ElementName; - else + if (string.IsNullOrEmpty(rootNodeName)) { - XmlTypeAttribute typeAtt = o.GetType().GetAttribute(); - if (typeAtt != null && !string.IsNullOrEmpty(typeAtt.TypeName)) - name = typeAtt.TypeName; + XmlRootAttribute root = o.GetType().GetAttribute(); + if (root != null && !string.IsNullOrEmpty(root.ElementName)) + rootNodeName = root.ElementName; else - name = "root"; + { + XmlTypeAttribute typeAtt = o.GetType().GetAttribute(); + if (typeAtt != null && !string.IsNullOrEmpty(typeAtt.TypeName)) + rootNodeName = typeAtt.TypeName; + else + rootNodeName = "root"; + } } try { writer.WriteStartDocument(); - _WriteNode(writer, name, o.GetType(), o, false, o.GetType().GetSubTypeName()); + _WriteValue(writer, rootNodeName, o.GetType(), o, false, o.GetType().GetSubTypeName()); writer.WriteEndDocument(); } finally @@ -164,17 +209,29 @@ namespace VocaluxeLib.Xml } } - public void Serialize(string filePath, object o) + /// + /// Serializes the given object to the file + /// + /// Full path to file + /// Object to serialize + /// Name of the root node (overwrites default value specified by XmlRoot/XmlTypeAttributes which defaults to "root") + public void Serialize(string filePath, object o, string rootNodeName = null) { using (XmlWriter writer = XmlWriter.Create(filePath, _XMLSettings)) - _Serialize(o, writer); + _Serialize(writer, o, rootNodeName); } - public string Serialize(object o) + /// + /// Serializes the given object and returns the resulting xml as a string + /// + /// Object to serialize + /// Name of the root node (overwrites default value specified by XmlRoot/XmlTypeAttributes which defaults to "root") + /// Serialized object + public string Serialize(object o, string rootNodeName = null) { MemoryStream result = new MemoryStream(); using (XmlWriter writer = XmlWriter.Create(result, _XMLSettings)) - _Serialize(o, writer); + _Serialize(writer, o, rootNodeName); result.Position = 0; return new StreamReader(result).ReadToEnd(); } diff --git a/VocaluxeLib/XmlStructs.cs b/VocaluxeLib/XmlStructs.cs index 234ceda1..c999193a 100644 --- a/VocaluxeLib/XmlStructs.cs +++ b/VocaluxeLib/XmlStructs.cs @@ -1,4 +1,21 @@ -using System.ComponentModel; +#region license +// This file is part of Vocaluxe. +// +// Vocaluxe is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Vocaluxe is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Vocaluxe. If not, see . +#endregion + +using System.ComponentModel; using System.Xml.Serialization; namespace VocaluxeLib diff --git a/VocaluxeTests/XmlSerializerTest.cs b/VocaluxeTests/XmlSerializerTest.cs index 3ef04f77..791ecf0e 100644 --- a/VocaluxeTests/XmlSerializerTest.cs +++ b/VocaluxeTests/XmlSerializerTest.cs @@ -420,7 +420,8 @@ namespace VocaluxeTests [TestMethod] public void TestRealFiles() { - Type[] types = new Type[] {typeof(SThemeCover), typeof(CConfig.SConfig), typeof(SThemeScreen), typeof(SDefaultFonts), typeof(SSkin), typeof(STheme)}; + Type[] types = new Type[] + {typeof(SThemeCover), typeof(CConfig.SConfig), typeof(SThemeScreen), typeof(SDefaultFonts), typeof(SSkin), typeof(STheme), typeof(Dictionary)}; string filePath = Path.Combine(new string[] {AppDomain.CurrentDomain.BaseDirectory, "..", "..", "..", "TestXmlFiles"}); foreach (Type type in types) { @@ -437,7 +438,9 @@ namespace VocaluxeTests } Assert.IsInstanceOfType(foo, type, "Wrong type with " + type.Name); var ser = new CXmlSerializer(type == typeof(CConfig.SConfig)); - string newXml = ser.Serialize(foo); + string newXml = ser.Serialize(type == typeof(Dictionary) ? "resources" : foo); + // Typename will be uppercase but input is lowercase + newXml = newXml.Replace("