예제 #1
0
        /// <summary>
        /// Only validation whether the children elements are valid according to this type's constraint defined in schema.
        /// </summary>
        /// <param name="validationContext">The validation context.</param>
        public static void Validate(ValidationContext validationContext)
        {
            Debug.Assert(validationContext != null);
            Debug.Assert(validationContext.Element != null);

            OpenXmlElement theElement = validationContext.Element;

            Debug.Assert(!(theElement is OpenXmlUnknownElement));
            Debug.Assert(!(theElement is OpenXmlMiscNode));

            if (theElement.IsReservedElement())
            {
                // MiscElement, UnknownElement,
                // AlternateContent, AlternateContentChoice, AlternateContentFallback
                if (theElement.IsAlternateContent())
                {
                    AlternateContentValidator.Validate(validationContext);
                }

                Debug.Assert(!(theElement is AlternateContentChoice));
                Debug.Assert(!(theElement is AlternateContentFallback));

                return;
            }

            // validate Ignorable, ProcessContent, etc. compatibility-rule attributes
            CompatibilityRuleAttributesValidator.ValidateMcAttributes(validationContext);

            ValidateAttributes(validationContext);

            // validate particles
            if (theElement is OpenXmlLeafTextElement)
            {
                SimpleContentComplexTypeValidator.Validate(validationContext);
            }
            else if (theElement is OpenXmlLeafElement)
            {
                EmptyComplexTypeValidator.Validate(validationContext);
            }
            else
            {
                Debug.Assert(theElement is OpenXmlCompositeElement);

                Debug.Assert(!(theElement is AlternateContentChoice));
                Debug.Assert(!(theElement is AlternateContentFallback));

                if (theElement.ParticleConstraint != null)
                {
                    // composite element
                    CompositeComplexTypeValidator.Validate(validationContext);
                }
                else
                {
                    // special case, see O14 bug #662644
                    // A root element which does not allow any children.
                    Debug.Assert(theElement is OpenXmlPartRootElement);
                    EmptyRootComplexTypeValidator.Validate(validationContext);
                }
            }
        }
        /// <summary>
        /// Validate compatibility rule attributes - Ignorable, ProcessContent, PreserveElements, PreserveAttributes, MustUnderstand.
        /// </summary>
        /// <param name="validationContext">The validation context.</param>
        internal static void ValidateMcAttributes(ValidationContext validationContext)
        {
            var element = validationContext.Stack.Current?.Element;

            if (element?.MCAttributes is null)
            {
                return;
            }

            HashSet <string>?   ignorableNamespaces = null;
            ValidationErrorInfo errorInfo;

            if (element.MCAttributes is not null)
            {
                // validate Ignorable attribute
                if (!string.IsNullOrEmpty(element.MCAttributes.Ignorable))
                {
                    ignorableNamespaces = new HashSet <string>();

                    // rule: the prefix must already be defined.
                    var prefixes = new ListValue <StringValue>();
                    prefixes.InnerText = element.MCAttributes.Ignorable;
                    foreach (var prefix in prefixes.Items)
                    {
                        if (prefix.Value is not null)
                        {
                            var ignorableNamespace = element.LookupNamespace(prefix.Value);
                            if (ignorableNamespace.IsNullOrEmpty())
                            {
                                // error, the prefix is not defined.
                                errorInfo = validationContext.ComposeMcValidationError(element, "MC_InvalidIgnorableAttribute", element.MCAttributes.Ignorable);
                                validationContext.AddError(errorInfo);
                            }
                            else
                            {
                                ignorableNamespaces.Add(ignorableNamespace);
                            }
                        }
                    }
                }

                // validate PreserveAttributes attribute
                if (!string.IsNullOrEmpty(element.MCAttributes.PreserveAttributes))
                {
                    // The ProcessAttributes attribute value shall not reference any attribute name that does not belong to a namespace
                    // that is identified by the Ignorable attribute of the same element.
                    if (ignorableNamespaces is null)
                    {
                        // must have Ignorable on same element.
                        errorInfo = validationContext.ComposeMcValidationError(element, "MC_InvalidPreserveAttributesAttribute", element.MCAttributes.PreserveAttributes);
                        validationContext.AddError(errorInfo);
                    }
                    else
                    {
                        var errorQName = ValidateQNameList(element.MCAttributes.PreserveAttributes, ignorableNamespaces, validationContext);
                        if (!errorQName.IsNullOrEmpty())
                        {
                            errorInfo = validationContext.ComposeMcValidationError(element, "MC_InvalidPreserveAttributesAttribute", element.MCAttributes.PreserveAttributes);
                            validationContext.AddError(errorInfo);
                        }
                    }
                }

                // validate PreserveElements attribute
                if (!string.IsNullOrEmpty(element.MCAttributes.PreserveElements))
                {
                    // The ProcessAttributes attribute value shall not reference any attribute name that does not belong to a namespace
                    // that is identified by the Ignorable attribute of the same element.
                    if (ignorableNamespaces is null)
                    {
                        // must have Ignorable on same element.
                        errorInfo = validationContext.ComposeMcValidationError(element, "MC_InvalidPreserveElementsAttribute", element.MCAttributes.PreserveElements);
                        validationContext.AddError(errorInfo);
                    }
                    else
                    {
                        var errorQName = ValidateQNameList(element.MCAttributes.PreserveElements, ignorableNamespaces, validationContext);
                        if (!errorQName.IsNullOrEmpty())
                        {
                            errorInfo = validationContext.ComposeMcValidationError(element, "MC_InvalidPreserveElementsAttribute", element.MCAttributes.PreserveElements);
                            validationContext.AddError(errorInfo);
                        }
                    }
                }

                // validate ProcessContent attribute
                if (!string.IsNullOrEmpty(element.MCAttributes.ProcessContent))
                {
                    // The ProcessAttributes attribute value shall not reference any attribute name that does not belong to a namespace
                    // that is identified by the Ignorable attribute of the same element.
                    if (ignorableNamespaces is null)
                    {
                        // must have Ignorable on same element.
                        errorInfo = validationContext.ComposeMcValidationError(element, "MC_InvalidProcessContentAttribute", element.MCAttributes.ProcessContent);
                        validationContext.AddError(errorInfo);
                    }
                    else
                    {
                        var errorQName = ValidateQNameList(element.MCAttributes.ProcessContent, ignorableNamespaces, validationContext);
                        if (!errorQName.IsNullOrEmpty())
                        {
                            errorInfo = validationContext.ComposeMcValidationError(element, "MC_InvalidProcessContentAttribute", element.MCAttributes.ProcessContent);
                            validationContext.AddError(errorInfo);
                        }
                    }

                    foreach (var exAttribute in element.ExtendedAttributes)
                    {
                        // Markup consumers that encounter a non-ignored element that has an xml:lang or xml:space attribute and is also identified by a ProcessContent attribute value might generate an error.
                        if (AlternateContentValidator.IsXmlSpaceOrXmlLangAttribue(exAttribute))
                        {
                            // report error.
                            errorInfo = validationContext.ComposeMcValidationError(element, "MC_InvalidXmlAttributeWithProcessContent");
                            validationContext.AddError(errorInfo);
                        }
                    }
                }

                if (!string.IsNullOrEmpty(element.MCAttributes.MustUnderstand))
                {
                    // TODO: MustUnderstand
                    // A markup consumer that does not understand these identified namespaces shall not continue to process the markup document

                    // rule: the prefix must already be defined.
                    var prefixes = new ListValue <StringValue>();
                    prefixes.InnerText = element.MCAttributes.MustUnderstand;
                    foreach (var prefix in prefixes.Items)
                    {
                        if (prefix.Value is not null)
                        {
                            var mustunderstandNamespace = element.LookupNamespace(prefix.Value);
                            if (string.IsNullOrEmpty(mustunderstandNamespace))
                            {
                                // report error, the prefix is not defined.
                                errorInfo = validationContext.ComposeMcValidationError(element, "MC_InvalidMustUnderstandAttribute", element.MCAttributes.MustUnderstand);
                                validationContext.AddError(errorInfo);
                            }
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Only validation whether the children elements are valid according to this type's constraint defined in schema.
        /// </summary>
        /// <param name="validationContext">The validation context.</param>
        internal void Validate(ValidationContext validationContext)
        {
            Debug.Assert(validationContext != null);
            Debug.Assert(validationContext.Element != null);

            OpenXmlElement theElement = validationContext.Element;

            Debug.Assert(!(theElement is OpenXmlUnknownElement));
            Debug.Assert(!(theElement is OpenXmlMiscNode));

            if (theElement.ElementTypeId < ReservedElementTypeIds.MaxReservedId)
            {
                // MiscElement, UnknownElement,
                // AlternateContent, AlternateContentChoice, AlternateContentFallback
                if (theElement.ElementTypeId == ReservedElementTypeIds.AlternateContentId)
                {
                    AlternateContentValidator.Validate(validationContext);
                }

                Debug.Assert(!(theElement is AlternateContentChoice));
                Debug.Assert(!(theElement is AlternateContentFallback));

                return;
            }

            // validte Inorable, ProcessContent, etc. compatibility-rule attributes
            CompatibilityRuleAttributesValidator.ValidateMcAttributes(validationContext);

            SchemaTypeData schemaTypeData = this._sdbSchemaDatas.GetSchemaTypeData(theElement);

            ValidateAttributes(validationContext, schemaTypeData);

            // validate particles

            if (theElement is OpenXmlLeafTextElement)
            {
                SimpleContentComplexTypeValidator.Validate(validationContext, schemaTypeData.SimpleTypeConstraint);
            }
            else if (theElement is OpenXmlLeafElement)
            {
                EmptyComplexTypeValidator.Validate(validationContext);
            }
            else
            {
                Debug.Assert(theElement is OpenXmlCompositeElement);

                Debug.Assert(!(theElement is AlternateContentChoice));
                Debug.Assert(!(theElement is AlternateContentFallback));

                if (schemaTypeData.ParticleConstraint != null)
                {
                    // composite element
                    CompositeComplexTypeValidator.Validate(validationContext, schemaTypeData.ParticleConstraint);
                }
                else
                {
                    // special case, see O14 bug #662644
                    // A root element which does not allow any children.
                    Debug.Assert(theElement is OpenXmlPartRootElement);
                    EmptyRootComplexTypeValidator.Validate(validationContext);
                }
            }
        }