DouglasDwyer.RoyalXml 1.1.0.2

RoyalXml is a simple, highly customizable XML serializer for .NET. Though it can be configured in almost any way, the default serialization ruleset supports polymorphism, multidimensional arrays, and collections.

Install-Package DouglasDwyer.RoyalXml -Version 1.1.0.2
dotnet add package DouglasDwyer.RoyalXml --version 1.1.0.2
<PackageReference Include="DouglasDwyer.RoyalXml" Version="1.1.0.2" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add DouglasDwyer.RoyalXml --version 1.1.0.2
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: DouglasDwyer.RoyalXml, 1.1.0.2"
#r directive can be used in F# Interactive, C# scripting and .NET Interactive. Copy this into the interactive tool or source code of the script to reference the package.
// Install DouglasDwyer.RoyalXml as a Cake Addin
#addin nuget:?package=DouglasDwyer.RoyalXml&version=1.1.0.2

// Install DouglasDwyer.RoyalXml as a Cake Tool
#tool nuget:?package=DouglasDwyer.RoyalXml&version=1.1.0.2
The NuGet Team does not provide support for this client. Please contact its maintainers for support.

Nuget Downloads

RoyalXml

RoyalXml is a simple XML serializer for .NET that supports polymorphism, multidimensional arrays, and collections.

Installation

RoyalXml can be obtained as a Nuget package. To import it into your project, either download DouglasDwyer.RoyalXml from the Visual Studio package manager or run the command Install-Package DouglasDwyer.RoyalXml using the package manager console.

How to use

Usage of RoyalXml with the default ruleset is quite simple. The following code snippet serializes and then deserializes an object using the default serialization ruleset:

RoyalXmlSerializer serializer = new RoyalXmlSerializer();
Dictionary<string, string> c = new Dictionary<string, string>() { { "hi", "bye" }, { "why", "cry" } };
string xml = serializer.Serialize(c);
Dictionary<string, string> d = serializer.Deserialize<Dictionary<string, string>>(xml);

Because different serializers can have different rulesets, it is necessary that serializers be instance-based and not static or singletons.

The default serialization ruleset

By default, RoyalXml comes with a builtin serialization ruleset. The default ruleset supports primitive types, objects in hierarchies, polymorphism, multidimensional arrays, collections, and dictionaries. Object references are not preserved during serialization, though it is possible to implement such behavior. This means that cyclical references are also unsupported.

Serialization rulesets

To perform serialization/deserialization in a configurable manner, RoyalXml centers around the use of serialization rulesets, which are passed into the constructor of RoyalXmlSerializer. If no ruleset is specified, then RoyalXmlSerializer.DefaultRuleset is used. Serialization rulesets are collections of RoyalSerializationRules which specify how to convert various types (and potentially their derived types). An example of a serialization rule, the ICollectionSerializationRule class, is given below:

public class ICollectionSerializationRule : RoyalSerializationRule
{
    public override Type SupportedType => typeof(ICollection<>);

    public override object Deserialize(XElement node, Type type, RoyalXmlSerializer serializer)
    {
        Type collectionType = type.GetInterfaces().Where(generic => generic.IsGenericType && generic.GetGenericTypeDefinition() == typeof(ICollection<>)).Single();
        object collection = Activator.CreateInstance(type);
        MethodInfo addToCollectionMethod = collectionType.GetMethod("Add", BindingFlags.Public | BindingFlags.Instance);
        foreach(XElement subnode in node.Nodes())
        {
            string subType = subnode.Attribute("Type").Value;
            if (subType == "null")
            {
                addToCollectionMethod.Invoke(collection, new object[] { null });
            }
            else
            {
                addToCollectionMethod.Invoke(collection, new object[] { ReadObjectXml(subnode, Type.GetType(subType), serializer) });
            }
        }
        return collection;
    }

    public override void Serialize(object data, XmlWriter writer, RoyalXmlSerializer serializer)
    {
        foreach(object o in (IEnumerable)data)
        {
            writer.WriteStartElement("ICollectionElement");
            if(o is null)
            {
                writer.WriteAttributeString("Type", "null");
            }
            else
            {
                writer.WriteAttributeString("Type", o.GetType().AssemblyQualifiedName);
                WriteObjectXml(o, writer, serializer);
            }
            writer.WriteEndElement();
        }
    }
}

The SupportedType property specifies that this rule can be applied to any ICollection<>. Note that this is a generic type - generic types like these are supported. During serialization/deseriation, the elements of the collection are enumerated, and WriteObjectXml and ReadObjectXml are called to serialize/deserialize subobjects. These methods make calls to the RoyalXmlSerializer, which determines the best serialization rule to use for any given object/type.

The best-fitting serialization rule

When a RoyalXmlSerializer is asked to serialize/deserialize a given type, it iterates through the type's inheritance hierarchy, attempting to find a type contained in the serialization ruleset. The serializer attempts to match a best-fitting rule by checking the given type's inheritance chain in the following order:

  • If the given type matches a rule's type, that rule is used
  • If the given type is generic, and a rule's type matches the generic definition, that rule is used
  • If one of the given type's interfaces matches a rule's type, that rule is used
  • If one of the given type's interfaces is generic, and a rule's type matches the generic definition, that rule is used
  • For each of the given type's base types, if the base type matches a rule, then that rule is used. If the base type is generic, and the generic type definition matches a rule, then that rule is used.

These rules make RoyalXml quite powerful, as it is easy to customize or extend behavior to various classes.

Nuget Downloads

RoyalXml

RoyalXml is a simple XML serializer for .NET that supports polymorphism, multidimensional arrays, and collections.

Installation

RoyalXml can be obtained as a Nuget package. To import it into your project, either download DouglasDwyer.RoyalXml from the Visual Studio package manager or run the command Install-Package DouglasDwyer.RoyalXml using the package manager console.

How to use

Usage of RoyalXml with the default ruleset is quite simple. The following code snippet serializes and then deserializes an object using the default serialization ruleset:

RoyalXmlSerializer serializer = new RoyalXmlSerializer();
Dictionary<string, string> c = new Dictionary<string, string>() { { "hi", "bye" }, { "why", "cry" } };
string xml = serializer.Serialize(c);
Dictionary<string, string> d = serializer.Deserialize<Dictionary<string, string>>(xml);

Because different serializers can have different rulesets, it is necessary that serializers be instance-based and not static or singletons.

The default serialization ruleset

By default, RoyalXml comes with a builtin serialization ruleset. The default ruleset supports primitive types, objects in hierarchies, polymorphism, multidimensional arrays, collections, and dictionaries. Object references are not preserved during serialization, though it is possible to implement such behavior. This means that cyclical references are also unsupported.

Serialization rulesets

To perform serialization/deserialization in a configurable manner, RoyalXml centers around the use of serialization rulesets, which are passed into the constructor of RoyalXmlSerializer. If no ruleset is specified, then RoyalXmlSerializer.DefaultRuleset is used. Serialization rulesets are collections of RoyalSerializationRules which specify how to convert various types (and potentially their derived types). An example of a serialization rule, the ICollectionSerializationRule class, is given below:

public class ICollectionSerializationRule : RoyalSerializationRule
{
    public override Type SupportedType => typeof(ICollection<>);

    public override object Deserialize(XElement node, Type type, RoyalXmlSerializer serializer)
    {
        Type collectionType = type.GetInterfaces().Where(generic => generic.IsGenericType && generic.GetGenericTypeDefinition() == typeof(ICollection<>)).Single();
        object collection = Activator.CreateInstance(type);
        MethodInfo addToCollectionMethod = collectionType.GetMethod("Add", BindingFlags.Public | BindingFlags.Instance);
        foreach(XElement subnode in node.Nodes())
        {
            string subType = subnode.Attribute("Type").Value;
            if (subType == "null")
            {
                addToCollectionMethod.Invoke(collection, new object[] { null });
            }
            else
            {
                addToCollectionMethod.Invoke(collection, new object[] { ReadObjectXml(subnode, Type.GetType(subType), serializer) });
            }
        }
        return collection;
    }

    public override void Serialize(object data, XmlWriter writer, RoyalXmlSerializer serializer)
    {
        foreach(object o in (IEnumerable)data)
        {
            writer.WriteStartElement("ICollectionElement");
            if(o is null)
            {
                writer.WriteAttributeString("Type", "null");
            }
            else
            {
                writer.WriteAttributeString("Type", o.GetType().AssemblyQualifiedName);
                WriteObjectXml(o, writer, serializer);
            }
            writer.WriteEndElement();
        }
    }
}

The SupportedType property specifies that this rule can be applied to any ICollection<>. Note that this is a generic type - generic types like these are supported. During serialization/deseriation, the elements of the collection are enumerated, and WriteObjectXml and ReadObjectXml are called to serialize/deserialize subobjects. These methods make calls to the RoyalXmlSerializer, which determines the best serialization rule to use for any given object/type.

The best-fitting serialization rule

When a RoyalXmlSerializer is asked to serialize/deserialize a given type, it iterates through the type's inheritance hierarchy, attempting to find a type contained in the serialization ruleset. The serializer attempts to match a best-fitting rule by checking the given type's inheritance chain in the following order:

  • If the given type matches a rule's type, that rule is used
  • If the given type is generic, and a rule's type matches the generic definition, that rule is used
  • If one of the given type's interfaces matches a rule's type, that rule is used
  • If one of the given type's interfaces is generic, and a rule's type matches the generic definition, that rule is used
  • For each of the given type's base types, if the base type matches a rule, then that rule is used. If the base type is generic, and the generic type definition matches a rule, then that rule is used.

These rules make RoyalXml quite powerful, as it is easy to customize or extend behavior to various classes.

Release Notes

Fixed a glitch with the serialization of arrays.

  • .NETStandard 2.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version History

Version Downloads Last updated
1.1.0.2 245 10/10/2020
1.1.0.1 271 10/10/2020
1.1.0 254 8/2/2020