private void ValidateElement(ValidationContext context) { if (_curReg != null) { foreach (var error in _curReg.CheckConstraints(context)) { context.EmitError(error); } } }
/// <summary> /// Validate ACB syntax - AlternateContent, Choice, Fallback and their attributes. /// </summary> /// <param name="validationContext"></param> internal static void Validate(ValidationContext validationContext) { AlternateContent acElement = (AlternateContent)validationContext.Element; // Validate MC attribute on AlternateContent ValidateMcAttributesOnAcb(validationContext, acElement); int status = 0; ValidationErrorInfo errorInfo; if (acElement.ChildElements.Count == 0) { // Rule: An AlternateContent element shall contain one or more Choice child elements errorInfo = validationContext.ComposeMcValidationError(acElement, "Sch_IncompleteContentExpectingComplex", ValidationResources.MC_ShallContainChoice); validationContext.EmitError(errorInfo); } OpenXmlElement child; child = acElement.GetFirstNonMiscElementChild(); while (child != null) { if (child is AlternateContent) { // Rule: An AlternateContent element shall not be the child of an AlternateContent element. errorInfo = validationContext.ComposeMcValidationError(acElement, "Sch_InvalidElementContentExpectingComplex", child.XmlQualifiedName.ToString(), ValidationResources.MC_ShallNotContainAlternateContent); validationContext.EmitError(errorInfo); } else { switch (status) { case 0: // expect a Choice if (child is AlternateContentChoice) { // validate the MC attributes on Choice ValidateMcAttributesOnAcb(validationContext, child); status = 1; } else { // Rule: An AlternateContent element shall contain one or more Choice child elements errorInfo = validationContext.ComposeMcValidationError(acElement, "Sch_IncompleteContentExpectingComplex", ValidationResources.MC_ShallContainChoice); validationContext.EmitError(errorInfo); if (child is AlternateContentFallback) { // validate the MC attributes on Fallback ValidateMcAttributesOnAcb(validationContext, child); } } break; case 1: // Already one Choice, expect Choice or Fallback if (child is AlternateContentChoice) { // validate the MC attributes on Choice ValidateMcAttributesOnAcb(validationContext, child); status = 1; } else if (child is AlternateContentFallback) { // validate the MC attributes on Fallback ValidateMcAttributesOnAcb(validationContext, child); status = 2; } else { errorInfo = validationContext.ComposeMcValidationError(acElement, "Sch_InvalidElementContentExpectingComplex", child.XmlQualifiedName.ToString(), ValidationResources.MC_ShallContainChoice); validationContext.EmitError(errorInfo); } break; case 2: // Already one Fallback. Can not have more than one Fallback errorInfo = validationContext.ComposeMcValidationError(acElement, "Sch_InvalidElementContentExpectingComplex", child.XmlQualifiedName.ToString(), ValidationResources.MC_ShallContainChoice); validationContext.EmitError(errorInfo); break; } } child = child.GetNextNonMiscElementSibling(); } return; }
/// <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.Element; if (element.MCAttributes == null) { return; } HashSet<string> ignorableNamespaces = null; ValidationErrorInfo errorInfo; if (element.MCAttributes != 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) { var ignorableNamespace = element.LookupNamespace(prefix); if (string.IsNullOrEmpty(ignorableNamespace)) { // error, the prefix is not defined. errorInfo = validationContext.ComposeMcValidationError(element, "MC_InvalidIgnorableAttribute", element.MCAttributes.Ignorable); validationContext.EmitError(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 == null) { // must have Ignorable on same element. errorInfo = validationContext.ComposeMcValidationError(element, "MC_InvalidPreserveAttributesAttribute", element.MCAttributes.PreserveAttributes); validationContext.EmitError(errorInfo); } else { string errorQName = ValidateQNameList(element.MCAttributes.PreserveAttributes, ignorableNamespaces, validationContext); if (!string.IsNullOrEmpty(errorQName)) { errorInfo = validationContext.ComposeMcValidationError(element, "MC_InvalidPreserveAttributesAttribute", element.MCAttributes.PreserveAttributes); validationContext.EmitError(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 == null) { // must have Ignorable on same element. errorInfo = validationContext.ComposeMcValidationError(element, "MC_InvalidPreserveElementsAttribute", element.MCAttributes.PreserveElements); validationContext.EmitError(errorInfo); } else { string errorQName = ValidateQNameList(element.MCAttributes.PreserveElements, ignorableNamespaces, validationContext); if (!string.IsNullOrEmpty(errorQName)) { errorInfo = validationContext.ComposeMcValidationError(element, "MC_InvalidPreserveElementsAttribute", element.MCAttributes.PreserveElements); validationContext.EmitError(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 == null) { // must have Ignorable on same element. errorInfo = validationContext.ComposeMcValidationError(element, "MC_InvalidProcessContentAttribute", element.MCAttributes.ProcessContent); validationContext.EmitError(errorInfo); } else { string errorQName = ValidateQNameList(element.MCAttributes.ProcessContent, ignorableNamespaces, validationContext); if (!string.IsNullOrEmpty(errorQName)) { errorInfo = validationContext.ComposeMcValidationError(element, "MC_InvalidProcessContentAttribute", element.MCAttributes.ProcessContent); validationContext.EmitError(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.EmitError(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) { var mustunderstandNamespace = element.LookupNamespace(prefix); if (string.IsNullOrEmpty(mustunderstandNamespace)) { // report error, the prefix is not defined. errorInfo = validationContext.ComposeMcValidationError(element, "MC_InvalidMustUnderstandAttribute", element.MCAttributes.MustUnderstand); validationContext.EmitError(errorInfo); } } } } }
/// <summary> /// Validate attributes on AlternateContent, Choice and Fallback element. /// </summary> /// <param name="validationContext"></param> /// <param name="acElement">The element to be validated.</param> private static void ValidateMcAttributesOnAcb(ValidationContext validationContext, OpenXmlElement acElement) { ValidationErrorInfo errorInfo; // AlternateContent elements might include the attributes Ignorable, MustUnderstand, ProcessContent, PreserveElements, and PreserveAttributes // These attributes’ qualified names shall be prefixed when associated with an AlternateContent / Choice / Fallback element. // A markup consumer shall generate an error if it encounters an unprefixed attribute name associated with an AlternateContent element. if (acElement.ExtendedAttributes != null) { foreach (var exAttribute in acElement.ExtendedAttributes) { if (string.IsNullOrEmpty(exAttribute.Prefix)) { // error on any unprefixed attributes errorInfo = validationContext.ComposeMcValidationError(acElement, ValidationResources.MC_ErrorOnUnprefixedAttributeName, exAttribute.XmlQualifiedName.ToString()); validationContext.EmitError(errorInfo); } // Markup consumers shall generate an error if they encounter the xml:lang or xml:space attributes on an AlternateContent element. // Markup consumers shall generate an error if they encounter the xml:lang or xml:space attributes on a Choice element, regardless of whether the element is preceded by a selected Choice element. // Markup consumers shall generate an error if they encounter the xml:lang or xml:space attributes on a Fallback element, regardless of whether the element is preceded by a selected Choice element. if (IsXmlSpaceOrXmlLangAttribue(exAttribute)) { // report error. errorInfo = validationContext.ComposeMcValidationError(acElement, "MC_InvalidXmlAttribute", acElement.LocalName); validationContext.EmitError(errorInfo); } } } // validate MC attribues (Ignorable, PreserveElements, etc.) of this element. CompatibilityRuleAttributesValidator.ValidateMcAttributes(validationContext); AlternateContentChoice choice = acElement as AlternateContentChoice; if (choice != null) { // All Choice elements shall have a Requires attribute whose value contains a whitespace-delimited list of namespace prefixes if (choice.Requires == null) { // report error errorInfo = validationContext.ComposeMcValidationError(acElement, "MC_MissedRequiresAttribute"); validationContext.EmitError(errorInfo); } else { var prefixes = new ListValue<StringValue>(); prefixes.InnerText = choice.Requires; foreach (var prefix in prefixes.Items) { var ignorableNamespace = choice.LookupNamespace(prefix); if (string.IsNullOrEmpty(ignorableNamespace)) { // report error, the prefix is not defined. errorInfo = validationContext.ComposeMcValidationError(choice, "MC_InvalidRequiresAttribute", choice.Requires); validationContext.EmitError(errorInfo); } } } } }
internal static void Validate(ValidationContext validationContext) { var element = (OpenXmlCompositeElement)validationContext.Element; ValidationErrorInfo errorInfo; foreach (var child in element.ChildElements) { if (!(child is OpenXmlMiscNode)) { errorInfo = validationContext.ComposeSchemaValidationError(element, null, "Sch_InvalidChildinLeafElement", element.XmlQualifiedName.ToString()); validationContext.EmitError(errorInfo); return; // just return one error is enough. } } }
internal static void ValidateValue(ValidationContext validationContext, SimpleTypeRestriction simpleTypeConstraint, OpenXmlSimpleType value, string qname, bool isAttribute) { var element = validationContext.Element; string errorMessageResourceId; ValidationErrorInfo errorInfo; string subMessage; // special case, the type is different in Office2007 and Office2010. var redirectRestriction = simpleTypeConstraint as RedirectedRestriction; if (redirectRestriction != null) { var targetValue = redirectRestriction.ConvertValue(value); ValidateValue(validationContext, redirectRestriction.TargetRestriction, targetValue, qname, isAttribute); return; } if (isAttribute) { errorMessageResourceId = "Sch_AttributeValueDataTypeDetailed"; } else { errorMessageResourceId = "Sch_ElementValueDataTypeDetailed"; } // first, check whether the string is valid accoding the primitive type if (!simpleTypeConstraint.ValidateValueType(value)) { if (simpleTypeConstraint.IsEnum) { // enum is wrong errorInfo = validationContext.ComposeSchemaValidationError(element, null, errorMessageResourceId, qname, value.InnerText, ValidationResources.Sch_EnumerationConstraintFailed); errorInfo.SetDebugField(isAttribute? qname : null, "Sch_EnumerationConstraintFailed"); } else if (simpleTypeConstraint.XsdType == XsdType.Union) { errorInfo = validationContext.ComposeSchemaValidationError(element, null, isAttribute ? "Sch_AttributeUnionFailedEx" : "Sch_ElementUnionFailedEx", qname, value.InnerText); errorInfo.SetDebugField(isAttribute? qname : null, null); } else if (string.IsNullOrEmpty(value.InnerText)) { errorInfo = validationContext.ComposeSchemaValidationError(element, null, errorMessageResourceId, qname, value.InnerText, isAttribute ? ValidationResources.Sch_EmptyAttributeValue : ValidationResources.Sch_EmptyElementValue); errorInfo.SetDebugField(isAttribute? qname : null, isAttribute ? "Sch_EmptyAttributeValue" : "Sch_EmptyElementValue"); } else if (simpleTypeConstraint.XsdType == XsdType.SpecialBoolean) { // special boolean is ST_OnOff which is enum in the schema. errorInfo = validationContext.ComposeSchemaValidationError(element, null, errorMessageResourceId, qname, value.InnerText, ValidationResources.Sch_EnumerationConstraintFailed); errorInfo.SetDebugField(isAttribute ? qname : null, "Sch_EnumerationConstraintFailed"); } else if (simpleTypeConstraint.IsList) { // List errorInfo = validationContext.ComposeSchemaValidationError(element, null, errorMessageResourceId, qname, value.InnerText, string.Empty); errorInfo.SetDebugField(isAttribute? qname : null, null); } else { subMessage = string.Format(CultureInfo.CurrentUICulture, ValidationResources.Sch_StringIsNotValidValue, value.InnerText, simpleTypeConstraint.ClrTypeName); errorInfo = validationContext.ComposeSchemaValidationError(element, null, errorMessageResourceId, qname, value.InnerText, subMessage); errorInfo.SetDebugField(isAttribute? qname : null, "Sch_StringIsNotValidValue"); } validationContext.EmitError(errorInfo); } else { bool validateConstraints = true; switch (simpleTypeConstraint.XsdType) { case XsdType.Enum: case XsdType.Boolean: case XsdType.DateTime: case XsdType.SpecialBoolean: Debug.Assert(simpleTypeConstraint.Pattern == null); Debug.Assert(simpleTypeConstraint.RestrictionField == RestrictionField.None); // no other facets. validateConstraints = false; break; case XsdType.NonNegativeInteger: case XsdType.PositiveInteger: case XsdType.Byte: case XsdType.UnsignedByte: case XsdType.Short: case XsdType.UnsignedShort: case XsdType.Int: case XsdType.UnsignedInt: case XsdType.Long: case XsdType.UnsignedLong: case XsdType.Float: case XsdType.Double: case XsdType.Decimal: case XsdType.Integer: // TODO: integer should be decimal, while in current the CodeGen generate Int32 instead. Debug.Assert(simpleTypeConstraint.Pattern == null); Debug.Assert((simpleTypeConstraint.RestrictionField & RestrictionField.LengthRestriction) == RestrictionField.None); break; case XsdType.String: case XsdType.Token: case XsdType.HexBinary: case XsdType.Base64Binary: case XsdType.AnyURI: case XsdType.QName: case XsdType.ID: // no pattern defined for numeric type in Ecma376 case XsdType.NCName: case XsdType.IDREF: case XsdType.Language: Debug.Assert((simpleTypeConstraint.RestrictionField & RestrictionField.MinMaxRestriction) == RestrictionField.None); break; case XsdType.List: Debug.Assert(simpleTypeConstraint.Pattern == null); Debug.Assert(simpleTypeConstraint.RestrictionField == RestrictionField.None); // no other facets in current Ecma376. validateConstraints = false; break; case XsdType.Union: Debug.Assert(simpleTypeConstraint.Pattern == null); Debug.Assert(simpleTypeConstraint.RestrictionField == RestrictionField.None); // no other facets. validateConstraints = false; break; default: Debug.Assert(false); break; } if (validateConstraints) { var errorRestriction = simpleTypeConstraint.Validate(value); if (errorRestriction != RestrictionField.None) { if ((errorRestriction & RestrictionField.MinInclusive) == RestrictionField.MinInclusive) { subMessage = string.Format(CultureInfo.CurrentUICulture, ValidationResources.Sch_MinInclusiveConstraintFailed, simpleTypeConstraint.GetRestrictionValue(RestrictionField.MinInclusive)); errorInfo = validationContext.ComposeSchemaValidationError(element, null, errorMessageResourceId, qname, value.InnerText, subMessage); errorInfo.SetDebugField(isAttribute? qname : null, "Sch_MinInclusiveConstraintFailed"); validationContext.EmitError(errorInfo); } if ((errorRestriction & RestrictionField.MinExclusive) == RestrictionField.MinExclusive) { subMessage = string.Format(CultureInfo.CurrentUICulture, ValidationResources.Sch_MinExclusiveConstraintFailed, simpleTypeConstraint.GetRestrictionValue(RestrictionField.MinExclusive)); errorInfo = validationContext.ComposeSchemaValidationError(element, null, errorMessageResourceId, qname, value.InnerText, subMessage); errorInfo.SetDebugField(isAttribute? qname : null, "Sch_MinExclusiveConstraintFailed"); validationContext.EmitError(errorInfo); } if ((errorRestriction & RestrictionField.MaxInclusive) == RestrictionField.MaxInclusive) { subMessage = string.Format(CultureInfo.CurrentUICulture, ValidationResources.Sch_MaxInclusiveConstraintFailed, simpleTypeConstraint.GetRestrictionValue(RestrictionField.MaxInclusive)); errorInfo = validationContext.ComposeSchemaValidationError(element, null, errorMessageResourceId, qname, value.InnerText, subMessage); errorInfo.SetDebugField(isAttribute? qname : null, "Sch_MaxInclusiveConstraintFailed"); validationContext.EmitError(errorInfo); } if ((errorRestriction & RestrictionField.MaxExclusive) == RestrictionField.MaxExclusive) { subMessage = string.Format(CultureInfo.CurrentUICulture, ValidationResources.Sch_MaxExclusiveConstraintFailed, simpleTypeConstraint.GetRestrictionValue(RestrictionField.MaxExclusive)); errorInfo = validationContext.ComposeSchemaValidationError(element, null, errorMessageResourceId, qname, value.InnerText, subMessage); errorInfo.SetDebugField(isAttribute? qname : null, "Sch_MaxExclusiveConstraintFailed"); validationContext.EmitError(errorInfo); } if ((errorRestriction & RestrictionField.Length) == RestrictionField.Length) { // length is not ok. if (string.IsNullOrEmpty(value.InnerText)) { errorInfo = validationContext.ComposeSchemaValidationError(element, null, errorMessageResourceId, qname, value.InnerText, isAttribute ? ValidationResources.Sch_EmptyAttributeValue : ValidationResources.Sch_EmptyElementValue); errorInfo.SetDebugField(isAttribute? qname : null, isAttribute ? "Sch_EmptyAttributeValue" : "Sch_EmptyElementValue"); validationContext.EmitError(errorInfo); } else { subMessage = string.Format(CultureInfo.CurrentUICulture, ValidationResources.Sch_LengthConstraintFailed, simpleTypeConstraint.XsdType.GetXsdDataTypeName(), simpleTypeConstraint.GetRestrictionValue(RestrictionField.Length)); errorInfo = validationContext.ComposeSchemaValidationError(element, null, errorMessageResourceId, qname, value.InnerText, subMessage); errorInfo.SetDebugField(isAttribute? qname : null, "Sch_LengthConstraintFailed"); validationContext.EmitError(errorInfo); } } if ((errorRestriction & RestrictionField.MinLength) == RestrictionField.MinLength) { // min length is not ok. if (string.IsNullOrEmpty(value.InnerText)) { errorInfo = validationContext.ComposeSchemaValidationError(element, null, errorMessageResourceId, qname, value.InnerText, isAttribute ? ValidationResources.Sch_EmptyAttributeValue : ValidationResources.Sch_EmptyElementValue); errorInfo.SetDebugField(isAttribute? qname : null, isAttribute ? "Sch_EmptyAttributeValue" : "Sch_EmptyElementValue"); validationContext.EmitError(errorInfo); } else { subMessage = string.Format(CultureInfo.CurrentUICulture, ValidationResources.Sch_MinLengthConstraintFailed, simpleTypeConstraint.XsdType.GetXsdDataTypeName(), simpleTypeConstraint.GetRestrictionValue(RestrictionField.MinLength)); errorInfo = validationContext.ComposeSchemaValidationError(element, null, errorMessageResourceId, qname, value.InnerText, subMessage); errorInfo.SetDebugField(isAttribute? qname : null, "Sch_MinLengthConstraintFailed"); validationContext.EmitError(errorInfo); } } if ((errorRestriction & RestrictionField.MaxLength) == RestrictionField.MaxLength) { // max length is not ok. subMessage = string.Format(CultureInfo.CurrentUICulture, ValidationResources.Sch_MaxLengthConstraintFailed, simpleTypeConstraint.XsdType.GetXsdDataTypeName(), simpleTypeConstraint.GetRestrictionValue(RestrictionField.MaxLength)); errorInfo = validationContext.ComposeSchemaValidationError(element, null, errorMessageResourceId, qname, value.InnerText, subMessage); errorInfo.SetDebugField(isAttribute? qname : null, "Sch_MaxLengthConstraintFailed"); validationContext.EmitError(errorInfo); } if ((errorRestriction & RestrictionField.Pattern) == RestrictionField.Pattern) { // pattern is not ok. subMessage = string.Format(CultureInfo.CurrentUICulture, ValidationResources.Sch_PatternConstraintFailed, simpleTypeConstraint.GetRestrictionValue(RestrictionField.Pattern)); errorInfo = validationContext.ComposeSchemaValidationError(element, null, errorMessageResourceId, qname, value.InnerText, subMessage); errorInfo.SetDebugField(isAttribute? qname : null, "Sch_PatternConstraintFailed"); validationContext.EmitError(errorInfo); } } } } }
/// <summary> /// Validate the attributes constraint. /// </summary> /// <param name="validationContext">The validation context.</param> /// <param name="schemaTypeData">The constraint data of the schema type.</param> private static void ValidateAttributes(ValidationContext validationContext, SchemaTypeData schemaTypeData) { var element = validationContext.Element; Debug.Assert( element.Attributes == null && schemaTypeData.AttributeConstraintsCount == 0 || element.Attributes.Length == schemaTypeData.AttributeConstraintsCount ); ValidationErrorInfo errorInfo; // validate xsd:use on attributes for (int i = 0; i < schemaTypeData.AttributeConstraintsCount; i++) { var attributeConstraint = schemaTypeData.AttributeConstraints[i]; if (attributeConstraint.SupportedVersion.Includes(validationContext.FileFormat)) { // only check the attribute constraints defined in the specified file format version. switch (attributeConstraint.XsdAttributeUse) { case XsdAttributeUse.Required: if (element.Attributes[i] == null) { string attributeQname = element.GetFixedAttributeQname(i).ToString(); // error: miss required attribute errorInfo = validationContext.ComposeSchemaValidationError(element, null, "Sch_MissRequiredAttribute", attributeQname); errorInfo.SetDebugField(attributeQname, "Sch_MissRequiredAttribute"); validationContext.EmitError(errorInfo); } break; case XsdAttributeUse.None: // none, so use default "optional" case XsdAttributeUse.Optional: break; case XsdAttributeUse.Prohibited: // no "prohibited" in Ecma at now. default: Debug.Assert(false); break; } if (element.Attributes[i] != null) { OpenXmlSimpleType attributeValue = element.Attributes[i]; string attributeQname = element.GetFixedAttributeQname(i).ToString(); ValidateValue(validationContext, attributeConstraint.SimpleTypeConstraint, attributeValue, attributeQname, true); } } else { if (element.Attributes[i] != null) { // The attribute is not defined in the specified version, report error. if (validationContext.McContext.IsIgnorableNs(element.AttributeNamespaceIds[i])) { // Ignorable attribute, no error. } else { // emit error string attributeQname = element.GetFixedAttributeQname(i).ToString(); ; errorInfo = validationContext.ComposeSchemaValidationError(element, null, "Sch_UndeclaredAttribute", attributeQname); errorInfo.SetDebugField(attributeQname, "Sch_UndeclaredAttribute"); validationContext.EmitError(errorInfo); } } } } // all unknown attributes (attributes not defined in schema) are in ExtendedAttributes. // they should be errors foreach (var extendedAttribute in element.ExtendedAttributes) { if (validationContext.McContext.IsIgnorableNs(extendedAttribute.NamespaceUri)) { // Ignorable attribute, no error. } // xml:space is always allowed else if ("http://www.w3.org/XML/1998/namespace" == extendedAttribute.NamespaceUri) { } else { // emit error string attributeQname = extendedAttribute.XmlQualifiedName.ToString(); errorInfo = validationContext.ComposeSchemaValidationError(element, null, "Sch_UndeclaredAttribute", attributeQname); errorInfo.SetDebugField(attributeQname, "Sch_UndeclaredAttribute"); validationContext.EmitError(errorInfo); } } }
protected override void EmitInvalidElementError(ValidationContext validationContext, ParticleMatchInfo particleMatchInfo) { var element = validationContext.Element; OpenXmlElement child; if (particleMatchInfo.LastMatchedElement == null) { child = validationContext.GetFirstChildMc(); } else { child = validationContext.GetNextChildMc(particleMatchInfo.LastMatchedElement); } string expectedChildren; ValidationErrorInfo errorInfo; switch (particleMatchInfo.Match) { case ParticleMatch.Nomatch: expectedChildren = GetExpectedChildrenMessage(validationContext.Element, this.GetExpectedElements()); errorInfo = validationContext.ComposeSchemaValidationError(element, child, "Sch_InvalidElementContentExpectingComplex", child.XmlQualifiedName.ToString(), expectedChildren); validationContext.EmitError(errorInfo); break; case ParticleMatch.Partial: case ParticleMatch.Matched: if (this._childrenParticles.ContainsKey(child.ElementTypeId)) { // more than one occurs of a child. errorInfo = validationContext.ComposeSchemaValidationError(element, child, "Sch_AllElement", child.XmlQualifiedName.ToString()); validationContext.EmitError(errorInfo); } else { expectedChildren = GetExpectedChildrenMessage(validationContext.Element, particleMatchInfo.ExpectedChildren); errorInfo = validationContext.ComposeSchemaValidationError(element, child, "Sch_InvalidElementContentExpectingComplex", child.XmlQualifiedName.ToString(), expectedChildren); validationContext.EmitError(errorInfo); } break; } }
protected virtual void EmitInvalidElementError(ValidationContext validationContext, ParticleMatchInfo particleMatchInfo) { OpenXmlElement child; // re-validate the element, collect the expected children information if (particleMatchInfo.Match != ParticleMatch.Nomatch) { #if DEBUG var oldParticleMatchInfo = particleMatchInfo; particleMatchInfo = new ParticleMatchInfo(); #endif child = validationContext.GetFirstChildMc(); validationContext.CollectExpectedChildren = true; particleMatchInfo.Reset(child); particleMatchInfo.InitExpectedChildren(); this.TryMatch(particleMatchInfo, validationContext); validationContext.CollectExpectedChildren = false; #if DEBUG Debug.Assert(particleMatchInfo.Match == oldParticleMatchInfo.Match); Debug.Assert(particleMatchInfo.LastMatchedElement == oldParticleMatchInfo.LastMatchedElement); #endif } var element = validationContext.Element; if (particleMatchInfo.LastMatchedElement == null) { child = validationContext.GetFirstChildMc(); } else { child = validationContext.GetNextChildMc(particleMatchInfo.LastMatchedElement); } ValidationErrorInfo errorInfo; string expectedChildren = null; switch (particleMatchInfo.Match) { case ParticleMatch.Nomatch: expectedChildren = GetExpectedChildrenMessage(validationContext.Element, this.GetExpectedElements()); break; case ParticleMatch.Partial: // error: the child can not be matched, it is invalid if (child == null) { // missing child errorInfo = validationContext.ComposeSchemaValidationError(element, null, "Sch_IncompleteContentExpectingComplex", GetExpectedChildrenMessage(element, particleMatchInfo.ExpectedChildren)); validationContext.EmitError(errorInfo); return; } else { expectedChildren = GetExpectedChildrenMessage(validationContext.Element, particleMatchInfo.ExpectedChildren); } break; case ParticleMatch.Matched: if (this.ParticleConstraint.CanOccursMoreThanOne) { expectedChildren = GetExpectedChildrenMessage(validationContext.Element, this.GetExpectedElements()); } else { expectedChildren = GetExpectedChildrenMessage(validationContext.Element, particleMatchInfo.ExpectedChildren); } break; } if (validationContext.Element.CanContainsChild(child)) { // The child can be contained in the parent, but not follow the schema. errorInfo = validationContext.ComposeSchemaValidationError(element, child, "Sch_UnexpectedElementContentExpectingComplex", child.XmlQualifiedName.ToString(), expectedChildren); } else { //Fix bug #448264, specifal case: same element name, but wrong type. Only occurs when validating memory DOM. var validElement = element.TryCreateValidChild(validationContext.FileFormat, child.NamespaceUri, child.LocalName); if (validElement == null) { errorInfo = validationContext.ComposeSchemaValidationError(element, child, "Sch_InvalidElementContentExpectingComplex", child.XmlQualifiedName.ToString(), expectedChildren); } else { // parent can contains a different type of element with same name errorInfo = validationContext.ComposeSchemaValidationError(element, child, "Sch_InvalidElementContentWrongType", child.XmlQualifiedName.ToString(), child.GetType().Name); } } validationContext.EmitError(errorInfo); }
/// <summary> /// Be called on root particle of complex type. /// </summary> /// <param name="validationContext"></param> /// <returns></returns> internal override void Validate(ValidationContext validationContext) { Debug.Assert(validationContext != null); OpenXmlCompositeElement element = validationContext.Element as OpenXmlCompositeElement; Debug.Assert(element != null); var child = validationContext.GetFirstChildMc(); ValidationErrorInfo errorInfo; // no children if (child == null) { if (this.ParticleConstraint.MinOccurs == 0) { // no child, ok return; } else { var requiredElements = this.GetRequiredElements(); if ( requiredElements.Count > 0 ) { errorInfo = validationContext.ComposeSchemaValidationError(element, null, "Sch_IncompleteContentExpectingComplex", GetExpectedChildrenMessage(element, requiredElements)); validationContext.EmitError(errorInfo); } return; } } if (this._particleMatchInfo == null) { this._particleMatchInfo = new ParticleMatchInfo(child); } else { _particleMatchInfo.Reset(child); } this.TryMatch(_particleMatchInfo, validationContext); switch (_particleMatchInfo.Match) { case ParticleMatch.Nomatch: // error: can not be matched, it is invalid EmitInvalidElementError(validationContext, _particleMatchInfo); return; case ParticleMatch.Partial: EmitInvalidElementError(validationContext, _particleMatchInfo); return; case ParticleMatch.Matched: Debug.Assert(_particleMatchInfo.LastMatchedElement != null); child = validationContext.GetNextChildMc(_particleMatchInfo.LastMatchedElement); { // Two cases now. // 1. All children be matched. // 2. Too many children ( > maxOccurs ). if (child != null) { // invalid child EmitInvalidElementError(validationContext, _particleMatchInfo); // TODO: how can we tell the user what is the required child? Use reflection in OpenXmlElement. } else { //Debug.Assert(result.Valid == true); } } break; } return; }