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