<commit_before>﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using NMF.Utilities;

namespace NMF.Serialization.Xmi
{
    public class XmiSerializer : XmlSerializer
    {
        /// <summary>
        /// Creates a new XmiSerializer with default settings and no preloaded types
        /// </summary>
        public XmiSerializer() : this(XmlSerializationSettings.Default) { }

        /// <summary>
        /// Creates a new XmiSerializer with default settings
        /// </summary>
        /// <param name="additionalTypes">Set of types to preload into the serializer</param>
        /// <remarks>Types will be loaded with default settings</remarks>
        public XmiSerializer(IEnumerable<Type> additionalTypes) : this(XmlSerializationSettings.Default, additionalTypes) { }

        /// <summary>
        /// Creates a new XmiSerializer with the specified settings
        /// </summary>
        /// <param name="settings">Serializer-settings for the serializer. Can be null or Nothing in Visual Basic. In this case, the default settings will be used.</param>
        public XmiSerializer(XmlSerializationSettings settings) : base(settings) {}

        /// <summary>
        /// Creates a new XmiSerializer with the specified settings and the given preloaded types
        /// </summary>
        /// <param name="additionalTypes">Set of types to load into the serializer</param>
        /// <param name="settings">The settings to use for the serializer</param>
        /// <remarks>The types will be loaded with the specified settings</remarks>
        public XmiSerializer(XmlSerializationSettings settings, IEnumerable<Type> additionalTypes) : base(settings, additionalTypes) { }

        private static readonly string TypeField = "type";
        public static readonly string XMLSchemaInstanceNamespace = "http://www.w3.org/2001/XMLSchema-instance";
        public static readonly string XMLSchemaInstancePrefix = "xsi";

        public static readonly string XMIPrefix = "xmi";
        public static readonly string XMINamespace = "http://www.omg.org/XMI";

        public string RootPrefix { get; set; }

        protected override bool GoToPropertyContent(System.Xml.XmlReader reader)
        {
            //do not move forward
            return true;
        }

        protected override XmlSerializationContext CreateSerializationContext(object root)
        {
            return new XmiSerializationContext(root);
        }

        protected override ITypeSerializationInfo GetElementTypeInfo(XmlReader reader, IPropertySerializationInfo property)
        {
            string attr = reader.GetAttribute(TypeField, XMLSchemaInstanceNamespace);
            if (attr != null)
            {
                int separator = attr.IndexOf(':');
                if (separator == -1) return GetTypeInfo(reader.LookupNamespace(string.Empty), attr);
                var prefix = attr.Substring(0, separator);
                var localName = attr.Substring(separator + 1);
                return GetTypeInfo(reader.LookupNamespace(prefix), localName);
            }
            else
            {
                if (property.PropertyType.IsCollection)
                {
                    return property.PropertyType.CollectionItemType;
                }
                else
                {
                    return property.PropertyType;
                }
            }
        }

        protected override void WriteBeginElement(System.Xml.XmlWriter writer, object obj, ITypeSerializationInfo info)
        {
            string prefix = info.NamespacePrefix;
            if (prefix == null)
            {
                prefix = writer.LookupPrefix(info.Namespace);
            }
            else if (writer.LookupPrefix(info.Namespace) == null)
            {
                writer.WriteAttributeString("xmlns", prefix, null, info.Namespace);
            }
            string value = prefix + ":" + info.ElementName;
            writer.WriteAttributeString(XMLSchemaInstancePrefix, TypeField, XMLSchemaInstanceNamespace, value);
        }

        protected override void WriteEndElement(System.Xml.XmlWriter writer, object obj, ITypeSerializationInfo info)
        {
        }

        protected override void WriteBeginRootElement(System.Xml.XmlWriter writer, object root, ITypeSerializationInfo info)
        {
            writer.WriteStartElement(info.NamespacePrefix ?? RootPrefix, info.ElementName, info.Namespace);

            writer.WriteAttributeString(XMIPrefix, "version", XMINamespace, "2.0");
            writer.WriteAttributeString("xmlns", XMLSchemaInstancePrefix, null, XMLSchemaInstanceNamespace);
        }

        protected override void WriteEndRootElement(System.Xml.XmlWriter writer, object root, ITypeSerializationInfo info)
        {
            writer.WriteEndElement();
        }

        protected override bool WriteIdentifiedObject(XmlWriter writer, object obj, XmlIdentificationMode identificationMode, ITypeSerializationInfo info, XmlSerializationContext context)
        {
            return false;
        }

        protected override void WriteElementProperties(System.Xml.XmlWriter writer, object obj, ITypeSerializationInfo info, XmlSerializationContext context)
        {
            if (info.DefaultProperty != null)
            {
                var content = info.DefaultProperty.GetValue(obj, context);
                if (info.DefaultProperty.ShouldSerializeValue(obj, content))
                {
                    writer.WriteString(GetAttributeValue(content, info.DefaultProperty.PropertyType, false, context));
                }
            }
            foreach (XmlPropertySerializationInfo pi in info.ElementProperties)
            {
                var value = pi.GetValue(obj, context);
                if (pi.ShouldSerializeValue(obj, value))
                {
                    if (pi.PropertyType.IsCollection)
                    {
                        var collectionType = pi.PropertyType.CollectionItemType.Type;
                        foreach (object item in value as IEnumerable)
                        {
                            writer.WriteStartElement(pi.NamespacePrefix, pi.ElementName, pi.Namespace);
                            var itemType = item.GetType();
                            var itemInfo = GetSerializationInfo(itemType, true);
                            if (itemType != collectionType)
                            {
                                WriteTypeQualifier(writer, itemInfo);
                            }
                            if (itemInfo.IsStringConvertible)
                            {
                                writer.WriteString(itemInfo.ConvertToString(item));
                            }
                            else
                            {
                                Serialize(item, writer, pi, false, pi.IdentificationMode, context);
                            }
                            writer.WriteEndElement();
                        }
                    }
                    else
                    {
                        writer.WriteStartElement(pi.NamespacePrefix, pi.ElementName, pi.Namespace);
                        if (value != null)
                        {
                            var type = value.GetType();
                            if (type != pi.PropertyType.Type.GetImplementationType())
                            {
                                WriteTypeQualifier(writer, GetSerializationInfo(type, true));
                            }
                        }
                        else
                        {
                            throw new NotImplementedException();
                        }
                        Serialize(value, writer, pi, false, pi.IdentificationMode, context);
                        writer.WriteEndElement();
                    }
                }
            }
        }

        private void WriteTypeQualifier(XmlWriter writer, ITypeSerializationInfo type)
        {
            if (type.NamespacePrefix != null)
            {
                if (writer.LookupPrefix(type.Namespace) != type.NamespacePrefix)
                {
                    writer.WriteAttributeString("xmlns", type.NamespacePrefix, null, type.Namespace);
                }
                 writer.WriteAttributeString(XMLSchemaInstancePrefix, TypeField, XMLSchemaInstanceNamespace,
                     type.NamespacePrefix + ":" + type.ElementName);
            }
            else
            {
                writer.WriteStartAttribute(XMLSchemaInstancePrefix, TypeField, XMLSchemaInstanceNamespace);
                writer.WriteQualifiedName(type.ElementName, type.Namespace);
                writer.WriteEndAttribute();
            }
        }

        protected override void InitializeElementProperties(System.Xml.XmlReader reader, ref object obj, ITypeSerializationInfo info, XmlSerializationContext context)
        {
            int currentDepth = reader.Depth;
            while (reader.Depth < currentDepth || reader.Read())
            {
                if (reader.Depth == currentDepth)
                {
                    break;
                }
                else if (reader.Depth < currentDepth)
                {
                    return;
                }
                if (reader.NodeType == XmlNodeType.Element)
                {
                    var found = false;
                    foreach (IPropertySerializationInfo p in info.ElementProperties)
                    {
                        if (IsPropertyElement(reader, p))
                        {
                            ReadElementFromProperty(reader, obj, context, p);
                            found = true;
                            break;
                        }
                    }
                    if (!found)
                    {
                        foreach (IPropertySerializationInfo p in info.AttributeProperties)
                        {
                            if (IsPropertyElement(reader, p))
                            {
                                ReadElementFromProperty(reader, obj, context, p);
                                found = true;
                                break;
                            }
                        }
                        if (!found)
                        {
                            OnUnknownElement(new UnknownElementEventArgs(obj, reader.ReadOuterXml()));
                        }
                    }
                }
                else if ((reader.NodeType == XmlNodeType.Text || reader.NodeType == XmlNodeType.CDATA))
                {
                    if (info.DefaultProperty == null)
                    {
                        throw new InvalidOperationException("Simple content unexpected for type " + info.Type.FullName);
                    }
                    InitializePropertyFromText(info.DefaultProperty, obj, reader.Value, context);
                }
            }
        }

        protected override bool OverrideIdentifiedObject(object obj, XmlReader reader, XmlSerializationContext context)
        {
            return false;
        }

        protected override void HandleUnknownAttribute(XmlReader reader, object obj, ITypeSerializationInfo info, XmlSerializationContext context)
        {
            if (reader.NamespaceURI == XmiArtificialIdAttribute.Instance.Namespace && reader.LocalName == XmiArtificialIdAttribute.Instance.ElementName)
            {
                XmiArtificialIdAttribute.Instance.SetValue(obj, reader.Value, context);
            }
            else
            {
                base.HandleUnknownAttribute(reader, obj, info, context);
            }
        }

        protected virtual void OnUnknownElement(UnknownElementEventArgs e)
        {
            if (UnknownElement != null) UnknownElement(this, e);
        }

        public event EventHandler<UnknownElementEventArgs> UnknownElement;

        private void ReadElementFromProperty(XmlReader reader, object obj, XmlSerializationContext context, IPropertySerializationInfo p)
        {
            var href = reader.GetAttribute("href");
            if (href == null)
            {
                if (p.PropertyType.IsStringConvertible || (p.PropertyType.IsCollection && p.PropertyType.CollectionItemType.IsStringConvertible))
                {
                    string content = reader.ReadElementContentAsString();
                    if (p.PropertyType.IsCollection)
                    {
                        p.AddToCollection(obj, p.PropertyType.CollectionItemType.ConvertFromString(content), context);
                    }
                    else
                    {
                        p.SetValue(obj, p.ConvertFromString(content), context);
                    }
                }
                else
                {
                    object current = DeserializeInternal(reader, p, context);
                    if (p.PropertyType.IsCollection)
                    {
                        p.AddToCollection(obj, current, context);
                    }
                    else
                    {
                        p.SetValue(obj, current, context);
                    }
                }
            }
            else
            {
                if (p.PropertyType.IsCollection)
                {
                    EnqueueAddToPropertyDelay(p, obj, href, context);
                }
                else
                {
                    EnqueueSetPropertyDelay(p, obj, href, context);
                }
            }
        }

        protected override void InitializeTypeSerializationInfo(ITypeSerializationInfo serializationInfo)
        {
            base.InitializeTypeSerializationInfo(serializationInfo);

            if (!serializationInfo.IsIdentified && !serializationInfo.IsCollection && serializationInfo is XmlTypeSerializationInfo)
            {
                XmlTypeSerializationInfo info = serializationInfo as XmlTypeSerializationInfo;
                var id = IdAttribute;
                if (id != null && info != null)
                {
                    if (!info.AttributeProperties.Contains(id))
                    {
                        info.DeclaredAttributeProperties.Add(id);
                    }
                    info.IdentifierProperty = id;
                }
            }
        }

        protected virtual IPropertySerializationInfo IdAttribute
        {
            get
            {
                return XmiArtificialIdAttribute.Instance;
            }
        }
    }
}
<commit_msg>Support XMI types as well<commit_after>﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using NMF.Utilities;

namespace NMF.Serialization.Xmi
{
    public class XmiSerializer : XmlSerializer
    {
        /// <summary>
        /// Creates a new XmiSerializer with default settings and no preloaded types
        /// </summary>
        public XmiSerializer() : this(XmlSerializationSettings.Default) { }

        /// <summary>
        /// Creates a new XmiSerializer with default settings
        /// </summary>
        /// <param name="additionalTypes">Set of types to preload into the serializer</param>
        /// <remarks>Types will be loaded with default settings</remarks>
        public XmiSerializer(IEnumerable<Type> additionalTypes) : this(XmlSerializationSettings.Default, additionalTypes) { }

        /// <summary>
        /// Creates a new XmiSerializer with the specified settings
        /// </summary>
        /// <param name="settings">Serializer-settings for the serializer. Can be null or Nothing in Visual Basic. In this case, the default settings will be used.</param>
        public XmiSerializer(XmlSerializationSettings settings) : base(settings) {}

        /// <summary>
        /// Creates a new XmiSerializer with the specified settings and the given preloaded types
        /// </summary>
        /// <param name="additionalTypes">Set of types to load into the serializer</param>
        /// <param name="settings">The settings to use for the serializer</param>
        /// <remarks>The types will be loaded with the specified settings</remarks>
        public XmiSerializer(XmlSerializationSettings settings, IEnumerable<Type> additionalTypes) : base(settings, additionalTypes) { }

        private static readonly string TypeField = "type";
        public static readonly string XMLSchemaInstanceNamespace = "http://www.w3.org/2001/XMLSchema-instance";
        public static readonly string XMLSchemaInstancePrefix = "xsi";

        public static readonly string XMIPrefix = "xmi";
        public static readonly string XMINamespace = "http://www.omg.org/XMI";

        public string RootPrefix { get; set; }

        protected override bool GoToPropertyContent(System.Xml.XmlReader reader)
        {
            //do not move forward
            return true;
        }

        protected override XmlSerializationContext CreateSerializationContext(object root)
        {
            return new XmiSerializationContext(root);
        }

        protected override ITypeSerializationInfo GetElementTypeInfo(XmlReader reader, IPropertySerializationInfo property)
        {
            string attr = reader.GetAttribute(TypeField, XMLSchemaInstanceNamespace)
                ?? reader.GetAttribute(TypeField, XMINamespace);
            if (attr != null)
            {
                int separator = attr.IndexOf(':');
                if (separator == -1) return GetTypeInfo(reader.LookupNamespace(string.Empty), attr);
                var prefix = attr.Substring(0, separator);
                var localName = attr.Substring(separator + 1);
                return GetTypeInfo(reader.LookupNamespace(prefix), localName);
            }
            else
            {
                if (property.PropertyType.IsCollection)
                {
                    return property.PropertyType.CollectionItemType;
                }
                else
                {
                    return property.PropertyType;
                }
            }
        }

        protected override void WriteBeginElement(System.Xml.XmlWriter writer, object obj, ITypeSerializationInfo info)
        {
            string prefix = info.NamespacePrefix;
            if (prefix == null)
            {
                prefix = writer.LookupPrefix(info.Namespace);
            }
            else if (writer.LookupPrefix(info.Namespace) == null)
            {
                writer.WriteAttributeString("xmlns", prefix, null, info.Namespace);
            }
            string value = prefix + ":" + info.ElementName;
            writer.WriteAttributeString(XMLSchemaInstancePrefix, TypeField, XMLSchemaInstanceNamespace, value);
        }

        protected override void WriteEndElement(System.Xml.XmlWriter writer, object obj, ITypeSerializationInfo info)
        {
        }

        protected override void WriteBeginRootElement(System.Xml.XmlWriter writer, object root, ITypeSerializationInfo info)
        {
            writer.WriteStartElement(info.NamespacePrefix ?? RootPrefix, info.ElementName, info.Namespace);

            writer.WriteAttributeString(XMIPrefix, "version", XMINamespace, "2.0");
            writer.WriteAttributeString("xmlns", XMLSchemaInstancePrefix, null, XMLSchemaInstanceNamespace);
        }

        protected override void WriteEndRootElement(System.Xml.XmlWriter writer, object root, ITypeSerializationInfo info)
        {
            writer.WriteEndElement();
        }

        protected override bool WriteIdentifiedObject(XmlWriter writer, object obj, XmlIdentificationMode identificationMode, ITypeSerializationInfo info, XmlSerializationContext context)
        {
            return false;
        }

        protected override void WriteElementProperties(System.Xml.XmlWriter writer, object obj, ITypeSerializationInfo info, XmlSerializationContext context)
        {
            if (info.DefaultProperty != null)
            {
                var content = info.DefaultProperty.GetValue(obj, context);
                if (info.DefaultProperty.ShouldSerializeValue(obj, content))
                {
                    writer.WriteString(GetAttributeValue(content, info.DefaultProperty.PropertyType, false, context));
                }
            }
            foreach (XmlPropertySerializationInfo pi in info.ElementProperties)
            {
                var value = pi.GetValue(obj, context);
                if (pi.ShouldSerializeValue(obj, value))
                {
                    if (pi.PropertyType.IsCollection)
                    {
                        var collectionType = pi.PropertyType.CollectionItemType.Type;
                        foreach (object item in value as IEnumerable)
                        {
                            writer.WriteStartElement(pi.NamespacePrefix, pi.ElementName, pi.Namespace);
                            var itemType = item.GetType();
                            var itemInfo = GetSerializationInfo(itemType, true);
                            if (itemType != collectionType)
                            {
                                WriteTypeQualifier(writer, itemInfo);
                            }
                            if (itemInfo.IsStringConvertible)
                            {
                                writer.WriteString(itemInfo.ConvertToString(item));
                            }
                            else
                            {
                                Serialize(item, writer, pi, false, pi.IdentificationMode, context);
                            }
                            writer.WriteEndElement();
                        }
                    }
                    else
                    {
                        writer.WriteStartElement(pi.NamespacePrefix, pi.ElementName, pi.Namespace);
                        if (value != null)
                        {
                            var type = value.GetType();
                            if (type != pi.PropertyType.Type.GetImplementationType())
                            {
                                WriteTypeQualifier(writer, GetSerializationInfo(type, true));
                            }
                        }
                        else
                        {
                            throw new NotImplementedException();
                        }
                        Serialize(value, writer, pi, false, pi.IdentificationMode, context);
                        writer.WriteEndElement();
                    }
                }
            }
        }

        private void WriteTypeQualifier(XmlWriter writer, ITypeSerializationInfo type)
        {
            if (type.NamespacePrefix != null)
            {
                if (writer.LookupPrefix(type.Namespace) != type.NamespacePrefix)
                {
                    writer.WriteAttributeString("xmlns", type.NamespacePrefix, null, type.Namespace);
                }
                 writer.WriteAttributeString(XMLSchemaInstancePrefix, TypeField, XMLSchemaInstanceNamespace,
                     type.NamespacePrefix + ":" + type.ElementName);
            }
            else
            {
                writer.WriteStartAttribute(XMLSchemaInstancePrefix, TypeField, XMLSchemaInstanceNamespace);
                writer.WriteQualifiedName(type.ElementName, type.Namespace);
                writer.WriteEndAttribute();
            }
        }

        protected override void InitializeElementProperties(System.Xml.XmlReader reader, ref object obj, ITypeSerializationInfo info, XmlSerializationContext context)
        {
            int currentDepth = reader.Depth;
            while (reader.Depth < currentDepth || reader.Read())
            {
                if (reader.Depth == currentDepth)
                {
                    break;
                }
                else if (reader.Depth < currentDepth)
                {
                    return;
                }
                if (reader.NodeType == XmlNodeType.Element)
                {
                    var found = false;
                    foreach (IPropertySerializationInfo p in info.ElementProperties)
                    {
                        if (IsPropertyElement(reader, p))
                        {
                            ReadElementFromProperty(reader, obj, context, p);
                            found = true;
                            break;
                        }
                    }
                    if (!found)
                    {
                        foreach (IPropertySerializationInfo p in info.AttributeProperties)
                        {
                            if (IsPropertyElement(reader, p))
                            {
                                ReadElementFromProperty(reader, obj, context, p);
                                found = true;
                                break;
                            }
                        }
                        if (!found)
                        {
                            OnUnknownElement(new UnknownElementEventArgs(obj, reader.ReadOuterXml()));
                        }
                    }
                }
                else if ((reader.NodeType == XmlNodeType.Text || reader.NodeType == XmlNodeType.CDATA))
                {
                    if (info.DefaultProperty == null)
                    {
                        throw new InvalidOperationException("Simple content unexpected for type " + info.Type.FullName);
                    }
                    InitializePropertyFromText(info.DefaultProperty, obj, reader.Value, context);
                }
            }
        }

        protected override bool OverrideIdentifiedObject(object obj, XmlReader reader, XmlSerializationContext context)
        {
            return false;
        }

        protected override void HandleUnknownAttribute(XmlReader reader, object obj, ITypeSerializationInfo info, XmlSerializationContext context)
        {
            if (reader.NamespaceURI == XmiArtificialIdAttribute.Instance.Namespace && reader.LocalName == XmiArtificialIdAttribute.Instance.ElementName)
            {
                XmiArtificialIdAttribute.Instance.SetValue(obj, reader.Value, context);
            }
            else
            {
                base.HandleUnknownAttribute(reader, obj, info, context);
            }
        }

        protected virtual void OnUnknownElement(UnknownElementEventArgs e)
        {
            if (UnknownElement != null) UnknownElement(this, e);
        }

        public event EventHandler<UnknownElementEventArgs> UnknownElement;

        private void ReadElementFromProperty(XmlReader reader, object obj, XmlSerializationContext context, IPropertySerializationInfo p)
        {
            var href = reader.GetAttribute("href");
            if (href == null)
            {
                if (p.PropertyType.IsStringConvertible || (p.PropertyType.IsCollection && p.PropertyType.CollectionItemType.IsStringConvertible))
                {
                    string content = reader.ReadElementContentAsString();
                    if (p.PropertyType.IsCollection)
                    {
                        p.AddToCollection(obj, p.PropertyType.CollectionItemType.ConvertFromString(content), context);
                    }
                    else
                    {
                        p.SetValue(obj, p.ConvertFromString(content), context);
                    }
                }
                else
                {
                    object current = DeserializeInternal(reader, p, context);
                    if (p.PropertyType.IsCollection)
                    {
                        p.AddToCollection(obj, current, context);
                    }
                    else
                    {
                        p.SetValue(obj, current, context);
                    }
                }
            }
            else
            {
                if (p.PropertyType.IsCollection)
                {
                    EnqueueAddToPropertyDelay(p, obj, href, context);
                }
                else
                {
                    EnqueueSetPropertyDelay(p, obj, href, context);
                }
            }
        }

        protected override void InitializeTypeSerializationInfo(ITypeSerializationInfo serializationInfo)
        {
            base.InitializeTypeSerializationInfo(serializationInfo);

            if (!serializationInfo.IsIdentified && !serializationInfo.IsCollection && serializationInfo is XmlTypeSerializationInfo)
            {
                XmlTypeSerializationInfo info = serializationInfo as XmlTypeSerializationInfo;
                var id = IdAttribute;
                if (id != null && info != null)
                {
                    if (!info.AttributeProperties.Contains(id))
                    {
                        info.DeclaredAttributeProperties.Add(id);
                    }
                    info.IdentifierProperty = id;
                }
            }
        }

        protected virtual IPropertySerializationInfo IdAttribute
        {
            get
            {
                return XmiArtificialIdAttribute.Instance;
            }
        }
    }
}

{'fraction_non_alphanumeric': 0.07351146073511461, 'fraction_numerical': 0.0006781500067815, 'mean_word_length': 1.4324123711340206, 'pattern_counts': {'":': 4, '<': 53, '<?xml version=': 0, '>': 49, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 6}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6875607', 'n_tokens_mistral': 6487, 'n_tokens_neox': 6197, 'n_words': 1408}