Exemplo n.º 1
0
        private void WriteElement(IElement element, XmlWriter writer, FileStream stream)
        {
            writer.WriteStartElement(null, element.ElementName, null);

            Type         elementType = element.GetType();
            BindingFlags flags       = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;

            MemberInfo[] members = elementType.GetMembers(flags).
                                   Where(x => x.GetCustomAttribute <Attr>() != null).ToArray();

            foreach (MemberInfo member in members)
            {
                Attr   attr  = member.GetCustomAttribute <Attr>();
                object value = member is PropertyInfo prop?prop.GetValue(element) : (member is FieldInfo field ? field.GetValue(element) : null);

                if (!attr.Required && value == elementType.GetDefaultValue())
                {
                    continue;
                }

                writer.WriteAttributeString(null, attr.AttributeName, null, value.ToString());
            }
            if (element is IStringElement stringEntry)
            {
                string value = stringEntry.GenericStringContent.WriteToString();
                writer.WriteString(value);
            }
            else
            {
                IOrderedEnumerable <IElement> orderedChildren = element.ChildElements.Values.SelectMany(x => x).OrderBy(x => x.ElementIndex);
                foreach (IElement child in orderedChildren)
                {
                    WriteElement(child, writer, stream);
                }
            }
            writer.WriteEndElement();
        }
Exemplo n.º 2
0
        private IElement ParseElement(
            IElement entry,
            IElement parent,
            XmlReader reader,
            string version,
            ulong ignoreFlags,
            string parentTree,
            int elementIndex,
            FileStream stream)
        {
            Type elementType = entry.GetType();

            entry.Parent       = parent;
            entry.ElementIndex = elementIndex;
            entry.PreRead();

            string parentElementName = reader.Name;

            if (string.IsNullOrEmpty(parentElementName))
            {
                throw new Exception("Null parent element name.");
            }

            parentTree += parentElementName + "/";
            entry.Tree  = parentTree;

            if (reader.NodeType != XmlNodeType.Element)
            {
                WriteLine($"Encountered an unexpected node: {reader.Name} '{reader.NodeType.ToString()}'");
                reader.Skip();
                entry.PostRead();
                return(entry);
            }

            if (entry.ParentType != typeof(IElement) && !entry.ParentType.IsAssignableFrom(parent.GetType()))
            {
                WriteLine($"Parent mismatch. {elementType.GetFriendlyName()} expected {entry.ParentType.GetFriendlyName()}, but got {parent.GetType().GetFriendlyName()}");
                reader.Skip();
                entry.PostRead();
                return(entry);
            }

            if ((ignoreFlags & entry.TypeFlag) != 0)
            {
                reader.Skip();
                entry.PostRead();
                return(entry);
            }

            #region Read attributes

            MemberInfo[] members = entry.WantsManualRead ? null : elementType.GetMembers(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
            if (reader.HasAttributes)
            {
                while (reader.MoveToNextAttribute())
                {
                    string name  = reader.Name;
                    string value = reader.Value;
                    if (entry.WantsManualRead)
                    {
                        entry.ManualReadAttribute(name, value);
                    }
                    else
                    {
                        MemberInfo info = members.FirstOrDefault(x =>
                        {
                            Attr a = x.GetCustomAttribute <Attr>();
                            return(a == null ? false : string.Equals(a.AttributeName, name, StringComparison.InvariantCultureIgnoreCase));
                        });

                        if (info == null)
                        {
                            WriteLine($"Attribute '{parentTree}[{name}]' not supported by parser. Value = '{value}'");
                        }
                        else if (info is FieldInfo field)
                        {
                            field.SetValue(entry, value.ParseAs(field.FieldType));
                        }
                        else if (info is PropertyInfo property)
                        {
                            property.SetValue(entry, value.ParseAs(property.PropertyType));
                        }
                    }
                }
            }

            #endregion

            if (entry is IVersion v)
            {
                version = v.Version;
            }

            entry.OnAttributesRead();

            #region Read child elements

            reader.MoveToElement();
            if (entry is IStringElement stringEntry)
            {
                stringEntry.GenericStringContent = Activator.CreateInstance(stringEntry.GenericStringType) as BaseElementString;
                stringEntry.GenericStringContent.ReadFromString(reader.ReadElementContentAsString());
            }
            else
            {
                if (reader.IsEmptyElement)
                {
                    reader.Read();
                }
                else
                {
                    reader.ReadStartElement();
                    int childIndex = 0;

                    ChildInfo[] childElements = entry.WantsManualRead ? null :
                                                elementType.GetCustomAttributesExt <Child>().Select(x => new ChildInfo(x)).ToArray();

                    MultiChildInfo[] multiChildElements = entry.WantsManualRead ? null :
                                                          elementType.GetCustomAttributesExt <MultiChild>().Select(x => new MultiChildInfo(x)).ToArray();

                    //Read all child elements
                    while (reader.NodeType != XmlNodeType.EndElement)
                    {
                        if (reader.NodeType != XmlNodeType.Element)
                        {
                            reader.Skip();
                            continue;
                        }

                        string elementName = reader.Name;
                        if (string.IsNullOrEmpty(elementName))
                        {
                            throw new Exception("Null element name.");
                        }

                        if (entry.WantsManualRead)
                        {
                            IElement e = entry.ManualReadChildElement(elementName, version);
                            if (e == null)
                            {
                                //Console.WriteLine("Element '{0}' not supported by parser.", parentTree + elementName + "/");
                                reader.Skip();
                            }
                            else
                            {
                                ParseElement(e, entry, reader, version, ignoreFlags, parentTree, childIndex, stream);
                            }
                        }
                        else
                        {
                            bool isUnsupported = elementType.GetCustomAttributesExt <UnsupportedChild>().
                                                 Any(x => string.Equals(x.ElementName, elementName, StringComparison.InvariantCultureIgnoreCase));

                            if (isUnsupported)
                            {
                                WriteLine($"Element '{parentTree + elementName}/' not supported by parser.");
                                reader.Skip();
                            }
                            else
                            {
                                int typeIndex = -1;
                                foreach (ChildInfo child in childElements)
                                {
                                    typeIndex = Array.FindIndex(child.ElementNames, name => name.Matches(elementName, version));

                                    //If no exact name matches, find a null name child element.
                                    //This means the class is for an element with ANY name.
                                    if (typeIndex < 0)
                                    {
                                        typeIndex = Array.FindIndex(child.ElementNames, name => name.Name == null && name.VersionMatches(version));
                                    }

                                    if (typeIndex >= 0)
                                    {
                                        if (++child.Occurrences > child.Data.MaxCount && child.Data.MaxCount >= 0)
                                        {
                                            WriteLine($"Element '{parentTree}' has occurred more times than expected.");
                                        }

                                        IElement elem = ParseElement(child.Types[typeIndex], entry, reader, version, ignoreFlags, parentTree, childIndex, stream);
                                        elem.ElementName = elementName;
                                        break;
                                    }
                                }
                                if (typeIndex < 0)
                                {
                                    int i = 0;
                                    MultiChildInfo[] infos = multiChildElements.Where(attribInfo =>
                                    {
                                        for (i = 0; i < attribInfo.Attrib.Types.Length; ++i)
                                        {
                                            ElementName name = attribInfo.ElementNames[i];
                                            if (name.Matches(elementName, version))
                                            {
                                                ++attribInfo.Occurrences[i];
                                                return(true);
                                            }
                                        }
                                        return(false);
                                    }).ToArray();

                                    if (infos.Length == 0)
                                    {
                                        //Console.WriteLine("Element '{0}' not supported by parser.", parentTree + elementName + "/");
                                        reader.Skip();
                                    }
                                    else
                                    {
                                        //TODO: verify the multi child type
                                        IElement elem = ParseElement(infos[0].Attrib.Types[i], entry, reader, version, ignoreFlags, parentTree, childIndex, stream);
                                        elem.ElementName = elementName;
                                    }
                                }
                            }
                        }
                        ++childIndex;
                    }

                    if (!entry.WantsManualRead)
                    {
                        ElementName[] underCounted = childElements.
                                                     Where(x => x.Occurrences < x.Data.MinCount).
                                                     SelectMany(x => x.ElementNames).
                                                     Where(x => x.VersionMatches(version)).ToArray();

                        if (underCounted.Length > 0)
                        {
                            foreach (ElementName elem in underCounted)
                            {
                                WriteLine($"Element '{elem.Name}' has occurred less times than expected.");
                            }
                        }
                    }

                    if (reader.Name == parentElementName)
                    {
                        reader.ReadEndElement();
                    }
                    else
                    {
                        throw new Exception("Encountered an unexpected node: " + reader.Name);
                    }
                }
            }

            #endregion

            entry.PostRead();

            return(entry);
        }
Exemplo n.º 3
0
        private async Task WriteElementAsync(
            IElement element,
            XmlWriter writer,
            CancellationToken cancel)
        {
            if (cancel.IsCancellationRequested)
            {
                return;
            }

            Type              elementType = element.GetType();
            BindingFlags      flags       = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
            List <MemberInfo> members     = elementType.GetMembers(flags).Where(x => x.GetCustomAttribute <Attr>() != null).ToList();

            int xmlnsIndex = members.FindIndex(x => x.GetCustomAttribute <Attr>().AttributeName == "xmlns");

            if (xmlnsIndex >= 0)
            {
                MemberInfo member = members[xmlnsIndex];
                object     value  = member is PropertyInfo prop?prop.GetValue(element) : (member is FieldInfo field ? field.GetValue(element) : null);

                members.RemoveAt(xmlnsIndex);
                await writer.WriteStartElementAsync(null, element.ElementName, value.ToString());
            }
            else
            {
                await writer.WriteStartElementAsync(null, element.ElementName, null);
            }

            foreach (MemberInfo member in members)
            {
                Attr   attr  = member.GetCustomAttribute <Attr>();
                object value = member is PropertyInfo prop?prop.GetValue(element) : (member is FieldInfo field ? field.GetValue(element) : null);

                if (!attr.Required && value == elementType.GetDefaultValue())
                {
                    continue;
                }

                await writer.WriteAttributeStringAsync(null, attr.AttributeName, null, value.ToString());

                if (cancel.IsCancellationRequested)
                {
                    return;
                }
            }
            if (element is IStringElement stringEntry)
            {
                string value = stringEntry.GenericStringContent.WriteToString();
                await writer.WriteStringAsync(value);
            }
            else
            {
                var orderedChildren = element.ChildElements.Values.SelectMany(x => x).OrderBy(x => x.ElementIndex);
                foreach (IElement child in orderedChildren)
                {
                    await WriteElementAsync(child, writer, cancel);
                }
            }
            await writer.WriteEndElementAsync();
        }