private void ElementIdentityConstraints() { for (int i = _startIDConstraint; i < _validationStack.Length; i++) { // no constraint for this level if (((ValidationState)(_validationStack[i])).Constr == null) { continue; } // else ConstraintStruct[] constraints = ((ValidationState)_validationStack[i]).Constr; for (int j = 0; j < constraints.Length; ++j) { // check selector from here if (constraints[j].axisSelector.MoveToStartElement(reader.LocalName, reader.NamespaceURI)) { // selector selects new node, activate a new set of fields Debug.WriteLine("Selector Match!"); Debug.WriteLine("Name: " + reader.LocalName + "\t|\tURI: " + reader.NamespaceURI + "\n"); // in which axisFields got updated constraints[j].axisSelector.PushKS(PositionInfo.LineNumber, PositionInfo.LinePosition); } // axisFields is not null, but may be empty for (int k = 0; k < constraints[j].axisFields.Count; ++k) { LocatedActiveAxis laxis = (LocatedActiveAxis)constraints[j].axisFields[k]; // check field from here if (laxis.MoveToStartElement(reader.LocalName, reader.NamespaceURI)) { Debug.WriteLine("Element Field Match!"); // checking simpleType / simpleContent if (context.ElementDecl != null) { // nextElement can be null when xml/xsd are not valid if (context.ElementDecl.Datatype == null) { SendValidationEvent(ResXml.Sch_FieldSimpleTypeExpected, reader.LocalName); } else { // can't fill value here, wait till later.... // fill type : xsdType laxis.isMatched = true; // since it's simpletyped element, the endchildren will come consequently... don't worry } } } } } } }
// facilitate modifying private void AttributeIdentityConstraints(string name, string ns, object obj, string sobj, SchemaAttDef attdef) { for (int ci = _startIDConstraint; ci < _validationStack.Length; ci++) { // no constraint for this level if (((ValidationState)(_validationStack[ci])).Constr == null) { continue; } // else ConstraintStruct[] constraints = ((ValidationState)_validationStack[ci]).Constr; for (int i = 0; i < constraints.Length; ++i) { // axisFields is not null, but may be empty for (int j = 0; j < constraints[i].axisFields.Count; ++j) { LocatedActiveAxis laxis = (LocatedActiveAxis)constraints[i].axisFields[j]; // check field from here if (laxis.MoveToAttribute(name, ns)) { Debug.WriteLine("Attribute Field Match!"); //attribute is only simpletype, so needn't checking... // can fill value here, yeah!! Debug.WriteLine("Attribute Field Filling Value!"); Debug.WriteLine("Name: " + name + "\t|\tURI: " + ns + "\t|\tValue: " + obj + "\n"); if (laxis.Ks[laxis.Column] != null) { // should be evaluated to either an empty node-set or a node-set with exactly one member // two matches... SendValidationEvent(ResXml.Sch_FieldSingleValueExpected, name); } else if ((attdef != null) && (attdef.Datatype != null)) { laxis.Ks[laxis.Column] = new TypedObject(obj, sobj, attdef.Datatype); } } } } } }
private void EndElementIdentityConstraints() { for (int ci = _validationStack.Length - 1; ci >= _startIDConstraint; ci--) { // no constraint for this level if (((ValidationState)(_validationStack[ci])).Constr == null) { continue; } // else ConstraintStruct[] constraints = ((ValidationState)_validationStack[ci]).Constr; for (int i = 0; i < constraints.Length; ++i) { // EndChildren // axisFields is not null, but may be empty for (int j = 0; j < constraints[i].axisFields.Count; ++j) { LocatedActiveAxis laxis = (LocatedActiveAxis)constraints[i].axisFields[j]; // check field from here // isMatched is false when nextElement is null. so needn't change this part. if (laxis.isMatched) { Debug.WriteLine("Element Field Filling Value!"); Debug.WriteLine("Name: " + reader.LocalName + "\t|\tURI: " + reader.NamespaceURI + "\t|\tValue: " + reader.TypedValueObject + "\n"); // fill value laxis.isMatched = false; if (laxis.Ks[laxis.Column] != null) { // [field...] should be evaluated to either an empty node-set or a node-set with exactly one member // two matches... already existing field value in the table. SendValidationEvent(ResXml.Sch_FieldSingleValueExpected, reader.LocalName); } else { // for element, reader.Value = ""; string stringValue = !hasSibling ? textString : textValue.ToString(); // only for identity-constraint exception reporting if (reader.TypedValueObject != null && stringValue.Length != 0) { laxis.Ks[laxis.Column] = new TypedObject(reader.TypedValueObject, stringValue, context.ElementDecl.Datatype); } } } // EndChildren laxis.EndElement(reader.LocalName, reader.NamespaceURI); } if (constraints[i].axisSelector.EndElement(reader.LocalName, reader.NamespaceURI)) { // insert key sequence into hash (+ located active axis tuple leave for later) KeySequence ks = constraints[i].axisSelector.PopKS(); // unqualified keysequence are not allowed switch (constraints[i].constraint.Role) { case CompiledIdentityConstraint.ConstraintRole.Key: if (!ks.IsQualified()) { //Key's fields can't be null... if we can return context node's line info maybe it will be better //only keymissing & keyduplicate reporting cases are necessary to be dealt with... 3 places... SendValidationEvent(new XmlSchemaException(ResXml.Sch_MissingKey, constraints[i].constraint.name.ToString(), reader.BaseURI, ks.PosLine, ks.PosCol)); } else if (constraints[i].qualifiedTable.Contains(ks)) { // unique or key checking value confliction // for redundant key, reporting both occurings // doesn't work... how can i retrieve value out?? SendValidationEvent(new XmlSchemaException(ResXml.Sch_DuplicateKey, new string[2] { ks.ToString(), constraints[i].constraint.name.ToString() }, reader.BaseURI, ks.PosLine, ks.PosCol)); } else { constraints[i].qualifiedTable.Add(ks, ks); } break; case CompiledIdentityConstraint.ConstraintRole.Unique: if (!ks.IsQualified()) { continue; } if (constraints[i].qualifiedTable.Contains(ks)) { // unique or key checking confliction SendValidationEvent(new XmlSchemaException(ResXml.Sch_DuplicateKey, new string[2] { ks.ToString(), constraints[i].constraint.name.ToString() }, reader.BaseURI, ks.PosLine, ks.PosCol)); } else { constraints[i].qualifiedTable.Add(ks, ks); } break; case CompiledIdentityConstraint.ConstraintRole.Keyref: // is there any possibility: // 2 keyrefs: value is equal, type is not // both put in the hashtable, 1 reference, 1 not if (constraints[i].qualifiedTable != null) { //Will be null in cases when the keyref is outside the scope of the key, that is not allowed by our impl if (!ks.IsQualified() || constraints[i].qualifiedTable.Contains(ks)) { continue; } constraints[i].qualifiedTable.Add(ks, ks); } break; } } } } // current level's constraint struct ConstraintStruct[] vcs = ((ValidationState)(_validationStack[_validationStack.Length - 1])).Constr; if (vcs != null) { // validating all referencing tables... for (int i = 0; i < vcs.Length; ++i) { if ((vcs[i].constraint.Role == CompiledIdentityConstraint.ConstraintRole.Keyref) || (vcs[i].keyrefTable == null)) { continue; } foreach (KeySequence ks in vcs[i].keyrefTable.Keys) { if (!vcs[i].qualifiedTable.Contains(ks)) { SendValidationEvent(new XmlSchemaException(ResXml.Sch_UnresolvedKeyref, new string[2] { ks.ToString(), vcs[i].constraint.name.ToString() }, reader.BaseURI, ks.PosLine, ks.PosCol)); } } } } }