/// <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); } } }