/// <summary>
        /// Initializes a new instance of the <see cref="XmlParserContext"/> class.
        /// </summary>
        /// <param name="parserSettings">Parser settings.</param>
        /// <param name="schema">Schema to use for parsing.</param>
        /// <param name="messages">Optional message list.</param>
        /// <param name="parsersCache">Optional parsers cache.</param>
        /// <param name="schemaCache">Optional schemas cache.</param>
        /// <param name="validatorsCache">Optional validators cache.</param>
        public XmlParserContext(
            IXmlParserSettings parserSettings,
            ISchema?schema,
            IMutableMessageList <Message>?messages = null,
            ConcurrentDictionary <IProperty, IValueParser>?parsersCache = null,
            ConcurrentDictionary <IProperty, ISchema>?schemaCache       = null,
            ConcurrentDictionary <IProperty, IPropertyValidationRules>?validatorsCache = null)
        {
            parserSettings.AssertArgumentNotNull(nameof(parserSettings));

            ParserSettings = parserSettings;
            Schema         = schema ?? new MutableObjectSchema();

            Messages = messages ?? new MutableMessageList <Message>();

            ParsersCache    = parsersCache ?? new ConcurrentDictionary <IProperty, IValueParser>(comparer: parserSettings.PropertyComparer);
            SchemaCache     = schemaCache ?? new ConcurrentDictionary <IProperty, ISchema>(comparer: parserSettings.PropertyComparer);
            ValidatorsCache = validatorsCache ?? new ConcurrentDictionary <IProperty, IPropertyValidationRules>(comparer: parserSettings.PropertyComparer);
        }
        private static IPropertyContainer?ParseXmlElement(
            XElement objectElement,
            IObjectSchema objectSchema,
            IXmlParserSettings settings,
            IXmlParserContext context,
            IMutablePropertyContainer?container = null)
        {
            if (objectElement.HasElements)
            {
                container ??= new MutablePropertyContainer();

                foreach (XElement propertyElement in objectElement.Elements())
                {
                    string    elementName  = settings.GetElementName(propertyElement);
                    string    propertyName = settings.StringProvider.GetString(elementName);
                    IProperty?property     = objectSchema.GetProperty(propertyName);

                    if (propertyElement.HasElements)
                    {
                        IObjectSchema propertyInternalSchema = context.GetOrCreateNewSchemaCached(property).ToObjectSchema();

                        IPropertyContainer?internalObject = ParseXmlElement(propertyElement, propertyInternalSchema, settings, context);
                        if (internalObject != null && internalObject.Count > 0)
                        {
                            if (settings.SetSchemaForObjects)
                            {
                                internalObject.SetSchema(propertyInternalSchema);
                            }

                            if (property == null)
                            {
                                property = new Property <IPropertyContainer>(propertyName)
                                           .SetIsNotFromSchema()
                                           .SetSchema(propertyInternalSchema);

                                if (objectSchema is IMutableObjectSchema mutableObjectSchema)
                                {
                                    property = mutableObjectSchema.AddProperty(property);
                                }
                            }

                            IPropertyValue propertyValue = settings.PropertyValueFactory.CreateUntyped(property, internalObject);
                            container.Add(propertyValue);

                            // Validate property.
                            if (settings.ValidateOnParse)
                            {
                                ValidateProperty(context, container, property, propertyElement);
                            }
                        }
                    }
                    else
                    {
                        if (property != null && property.Type == typeof(IPropertyContainer))
                        {
                            // Composite object, no value.
                            bool isNullAllowed = property.GetOrEvaluateNullability().IsNullAllowed;
                            if (!isNullAllowed)
                            {
                                context.Messages.AddError(
                                    $"Property '{property.Name}' can not be null but xml element has no value.{GetXmlLineInfo(propertyElement)}");
                            }

                            continue;
                        }

                        if (property == null)
                        {
                            property = new Property <string>(propertyName)
                                       .SetIsNotFromSchema();

                            if (objectSchema is IMutableObjectSchema mutableObjectSchema)
                            {
                                property = mutableObjectSchema.AddProperty(property);
                            }
                        }

                        IValueParser valueParser = context.GetParserCached(property);
                        if (valueParser != EmptyParser.Instance)
                        {
                            string elementValue = propertyElement.Value;

                            // Parse value.
                            IParseResult parseResult = valueParser.ParseUntyped(elementValue);

                            if (parseResult.IsSuccess)
                            {
                                // Add property to container.
                                object?        parsedValue   = parseResult.ValueUntyped;
                                IPropertyValue propertyValue = settings.PropertyValueFactory.CreateUntyped(property, parsedValue);
                                container.Add(propertyValue);

                                // Validate property.
                                if (settings.ValidateOnParse)
                                {
                                    ValidateProperty(context, container, property, propertyElement);
                                }
                            }
                            else
                            {
                                string?parseResultErrorMessage = parseResult.Error?.FormattedMessage;
                                string parseResultError        = parseResultErrorMessage != null ? $" Error: '{parseResultErrorMessage}'." : string.Empty;
                                string errorMessage            = $"Property '{property.Name}' failed to parse from string '{elementValue}'.{parseResultError}{GetXmlLineInfo(propertyElement)}";
                                context.Messages.AddError(errorMessage);
                            }
                        }
                        else
                        {
                            string errorMessage = $"Property '{property.Name}' can not be parsed because no parser found for type {property.Type}.{GetXmlLineInfo(propertyElement)}";
                            context.Messages.AddError(errorMessage);
                        }
                    }
                }

                return(container);
            }

            return(null);
        }