Преглед изворни кода

2004-12-13 Atsushi Enomoto <[email protected]>

	* XsdKeyTable.cs : eliminated XmlReader dependency.
	* XsdValidatingReader.cs :
	  AssertIdentityConstraints() is now splited to selector validation
	  and field validation. Extracted EndKeyrefValidation() to process
	  keyref constraints.
	  Added ReadExternalSchema() and commonized xsi:schemaLocation
	  handling and xsi:noNamespaceSchemaLocation handling.
	* XsdIdentityState.cs :
	  Eliminated XsdValidatingReader dependency.
	  In XsdKeyEntryField, renamed KeySequence to OwnerSequence.
	  XsdKeyEntryFieldCollection is now based on CollectionBase.
	  In XsdKeyEntry, FieldMatches() is renamed to ProcessMatch() and
	  modified to accept splited XsdValidatingReader members.
	* XsdIdentityPath.cs : added default .ctor() and IsAttribute property.



svn path=/trunk/mcs/; revision=37695
Atsushi Eno пре 21 година
родитељ
комит
ff59f3a239

+ 18 - 1
mcs/class/System.XML/Mono.Xml.Schema/ChangeLog

@@ -1,4 +1,21 @@
-2004-12-11  Atsushi Enomoto <[email protected]>
+2004-12-13  Atsushi Enomoto <[email protected]>
+
+	* XsdKeyTable.cs : eliminated XmlReader dependency.
+	* XsdValidatingReader.cs :
+	  AssertIdentityConstraints() is now splited to selector validation
+	  and field validation. Extracted EndKeyrefValidation() to process
+	  keyref constraints.
+	  Added ReadExternalSchema() and commonized xsi:schemaLocation
+	  handling and xsi:noNamespaceSchemaLocation handling.
+	* XsdIdentityState.cs :
+	  Eliminated XsdValidatingReader dependency.
+	  In XsdKeyEntryField, renamed KeySequence to OwnerSequence.
+	  XsdKeyEntryFieldCollection is now based on CollectionBase.
+	  In XsdKeyEntry, FieldMatches() is renamed to ProcessMatch() and
+	  modified to accept splited XsdValidatingReader members.
+	* XsdIdentityPath.cs : added default .ctor() and IsAttribute property.
+
+2004-12-13  Atsushi Enomoto <[email protected]>
 
 	* XsdIdentityState.cs,
 	  XsdIdentityPath.cs,

+ 12 - 0
mcs/class/System.XML/Mono.Xml.Schema/XsdIdentityPath.cs

@@ -93,8 +93,20 @@ namespace Mono.Xml.Schema
 
 	internal class XsdIdentityPath
 	{
+		public XsdIdentityPath ()
+		{
+		}
+
 		public XsdIdentityStep [] OrderedSteps;
 		public bool Descendants;
+
+		public bool IsAttribute {
+			get {
+				return OrderedSteps.Length == 0 ?
+					false :
+					OrderedSteps [OrderedSteps.Length - 1].IsAttribute;
+			}
+		}
 	}
 
 	internal class XsdIdentityStep

+ 83 - 157
mcs/class/System.XML/Mono.Xml.Schema/XsdIdentityState.cs

@@ -38,6 +38,12 @@ using System.Globalization;
 using System.Xml;
 using System.Xml.Schema;
 
+#if NET_2_0
+using NSResolver = System.Xml.IXmlNamespaceResolver;
+#else
+using NSResolver = System.Xml.XmlNamespaceManager;
+#endif
+
 namespace Mono.Xml.Schema
 {
 	internal class XsdKeyEntryField
@@ -86,9 +92,9 @@ namespace Mono.Xml.Schema
 				FieldLinePosition = li.LinePosition;
 			}
 
-			if (!(this.entry.KeySequence.SourceSchemaIdentity is XmlSchemaKeyref)) {
-				for (int i = 0; i < entry.KeySequence.FinishedEntries.Count; i++) {
-					XsdKeyEntry other = (XsdKeyEntry) entry.KeySequence.FinishedEntries [i];
+			if (!(this.entry.OwnerSequence.SourceSchemaIdentity is XmlSchemaKeyref)) {
+				for (int i = 0; i < entry.OwnerSequence.FinishedEntries.Count; i++) {
+					XsdKeyEntry other = (XsdKeyEntry) entry.OwnerSequence.FinishedEntries [i];
 					if (this.entry.CompareIdentity (other))
 						return false;
 				}
@@ -97,44 +103,59 @@ namespace Mono.Xml.Schema
 			return true;
 		}
 
-		// It might throw Exception including other than XmlSchemaException (ReadTypedValue).
-		internal XsdIdentityPath FieldMatches (ArrayList qnameStack, XsdValidatingReader reader)
+		// if (elementPath) check only elements; else only attributes.
+		internal XsdIdentityPath Matches (bool matchesAttr, object sender, XmlNameTable nameTable, ArrayList qnameStack, string sourceUri, object schemaType, NSResolver nsResolver, IXmlLineInfo lineInfo, int depth, string attrName, string attrNS, string attrValue)
 		{
 			for (int i = 0; i < field.Paths.Length; i++) {
 				XsdIdentityPath path = field.Paths [i];
-				if (FieldFound && (reader.Depth > this.FieldFoundDepth && this.FieldFoundPath == path))
+				bool isAttribute = path.IsAttribute;
+				if (matchesAttr != isAttribute)
+					continue;
+				XsdIdentityStep step;
+				if (path.IsAttribute) {
+					step = path.OrderedSteps [path.OrderedSteps.Length - 1];
+					bool match = false;
+					if (step.IsAnyName || step.NsName != null) {
+						if (step.IsAnyName || attrNS == step.NsName)
+							match = true;
+					}
+					else if (step.Name == attrName && step.Namespace == attrNS)
+						match = true;
+					if (match) {
+						this.FillAttributeFieldValue (sender, nameTable, sourceUri, schemaType, nsResolver, attrValue, lineInfo, depth);
+						if (this.Identity != null)
+							return path;
+					}
+				}
+				if (FieldFound && (depth > this.FieldFoundDepth && this.FieldFoundPath == path))
 					continue;
 
 				// Only "." hits.
 				if (path.OrderedSteps.Length == 0) {
-					if (reader.Depth == entry.StartDepth)
+					if (depth == entry.StartDepth)
 						return path;
 					else
 						continue;
 				}
 				// It does not hit as yet (too shallow to hit).
-				if (reader.Depth - entry.StartDepth < path.OrderedSteps.Length - 1)
+				if (depth - entry.StartDepth < path.OrderedSteps.Length - 1)
 					continue;
 
-				bool isAttributePath = false;
 				int iter = path.OrderedSteps.Length;
-				if (path.OrderedSteps [iter-1].IsAttribute) {
-					isAttributePath = true;
+				if (isAttribute)
 					iter--;
-				}
-				if (path.Descendants && reader.Depth < entry.StartDepth + iter)
+				if (path.Descendants && depth < entry.StartDepth + iter)
 					continue;
-				else if (!path.Descendants && reader.Depth != entry.StartDepth + iter)
+				else if (!path.Descendants && depth != entry.StartDepth + iter)
 					continue;
 
 				iter--;
 
-				XsdIdentityStep step;
 				for (; iter >= 0; iter--) {
 					step = path.OrderedSteps [iter];
-					if (step.IsAnyName)
+					if (step.IsCurrent || step.IsAnyName)
 						continue;
-					XmlQualifiedName qname = (XmlQualifiedName) qnameStack [entry.StartDepth + iter + 1];
+					XmlQualifiedName qname = (XmlQualifiedName) qnameStack [entry.StartDepth + iter + (isAttribute ? 0 : 1)];
 					if (step.NsName != null && qname.Namespace == step.NsName)
 						continue;
 					if ((step.Name == "*" || step.Name == qname.Name) &&
@@ -145,152 +166,54 @@ namespace Mono.Xml.Schema
 				}
 				if (iter >= 0)	// i.e. did not match against the path.
 					continue;
-				if (!isAttributePath)
-					return path;
-				step = path.OrderedSteps [path.OrderedSteps.Length - 1];
-				if (step.IsAnyName || step.NsName != null) {
-					try {
-						while (reader.MoveToNextAttribute ()) {
-							if (reader.NamespaceURI == XmlSchema.InstanceNamespace)
-								continue;
-							if (step.IsAnyName || reader.NamespaceURI == step.NsName) {
-								this.FillAttributeFieldValue (reader);
-							}
-						}
-					} finally {
-						reader.MoveToElement ();
-					}
-					if (this.Identity != null)
-						return path;
-					else
-						continue;
-				}
-				if (reader.MoveToAttribute (step.Name, step.Namespace)) {
-					this.FillAttributeFieldValue (reader);
-					reader.MoveToElement ();
-					return path;
-				}
-				else
-					continue;
+
+				return path;
 			}
 			return null;
 		}
 
-		private void FillAttributeFieldValue (XsdValidatingReader reader)
+		private void FillAttributeFieldValue (object sender, XmlNameTable nameTable, string sourceUri, object schemaType, NSResolver nsResolver, string value, IXmlLineInfo lineInfo, int depth)
 		{
 			if (this.FieldFound)
-				throw new XmlSchemaException ("The key value was was already found."
+				throw new XmlSchemaException ("The key value was already found."
 					+ (this.FieldHasLineInfo ?
 						String.Format (CultureInfo.InvariantCulture, " At line {0}, position {1}.", FieldLineNumber, FieldLinePosition) :
 						""),
-					reader, reader.BaseURI, entry.KeySequence.SourceSchemaIdentity, null);
-			XmlSchemaDatatype dt = reader.SchemaType as XmlSchemaDatatype;
-			XmlSchemaSimpleType st = reader.SchemaType as XmlSchemaSimpleType;
+					sender, sourceUri, entry.OwnerSequence.SourceSchemaIdentity, null);
+			XmlSchemaDatatype dt = schemaType as XmlSchemaDatatype;
+			XmlSchemaSimpleType st = schemaType as XmlSchemaSimpleType;
 			if (dt == null && st != null)
 				dt = st.Datatype;
-			object identity = XmlSchemaUtil.ReadTypedValue (reader, reader.SchemaType, reader.ParserContext.NamespaceManager, null);
-			if (identity == null)
-				identity = reader.Value;
-			if (!this.SetIdentityField (identity, reader.Depth - 1 == reader.XsiNilDepth , dt as XsdAnySimpleType, reader.Depth, (IXmlLineInfo) reader))
-				throw new XmlSchemaException ("Two or more identical field was found.", 
-					reader, reader.BaseURI, entry.KeySequence.SourceSchemaIdentity, null);
-			// HACK: This is not logical. Attributes never be cosuming,
-			// so I used it as a temporary mark to sign it is *just* validated now.
-			this.Consuming = true;
-			this.FieldFound = true;
+			object identity = null;
+			try {
+				if (dt != null)
+					identity = dt.ParseValue (value, nameTable, nsResolver);
+				if (identity == null)
+					identity = value;
+				if (!this.SetIdentityField (identity, false, dt as XsdAnySimpleType, depth, lineInfo))
+					throw new XmlSchemaException ("Two or more identical field was found.",
+						sender, sourceUri, entry.OwnerSequence.SourceSchemaIdentity, null);
+				// HACK: This is not logical. Attributes never be cosuming,
+				// so I used it as a temporary mark to sign it is *just* validated now.
+				this.Consuming = true;
+				this.FieldFound = true;
+			} catch (Exception ex) {
+				throw new XmlSchemaException ("Failed to read typed value.", sender, sourceUri, entry.OwnerSequence.SourceSchemaIdentity, ex);
+			}
 		}
 	}
 
-	internal class XsdKeyEntryFieldCollection : IList
+	internal class XsdKeyEntryFieldCollection : CollectionBase
 	{
-		ArrayList al = new ArrayList ();
-
-		#region IList
-		public bool IsReadOnly {
-			get { return false; }
-		}
-
-		object IList.this [int i] {
-			get { return al [i]; }
-			set { al [i] = value; }
-		}
-
 		public XsdKeyEntryField this [int i] {
-			get { return (XsdKeyEntryField) al [i]; }
-			set { al [i] = value; }
-		}
-
-		public void RemoveAt (int i)
-		{
-			al.RemoveAt (i);
-		}
-
-		public void Insert (int i, object value)
-		{
-			al.Insert (i, value);
-		}
-
-		public void Remove (object value)
-		{
-			al.Remove (value);
-		}
-
-		public bool Contains (object value)
-		{
-			return al.Contains (value);
-		}
-
-		public void Clear ()
-		{
-			al.Clear ();
+			get { return (XsdKeyEntryField) List [i]; }
+			set { List [i] = value; }
 		}
 
-		public int IndexOf (object value)
+		public int Add (XsdKeyEntryField value)
 		{
-			return al.IndexOf (value);
+			return List.Add (value);
 		}
-
-		public int Add (object value)
-		{
-			return al.Add (value);
-		}
-
-		public bool IsFixedSize {
-			get { return false; }
-		}
-
-		#endregion
-
-		#region ICollection
-
-		public bool IsSynchronized {
-			get { return al.IsSynchronized; }
-		}
-
-		public int Count {
-			get { return al.Count; }
-		}
-
-		public void CopyTo(Array array, int i)
-		{
-			al.CopyTo (array, i);
-		}
-
-		public object SyncRoot {
-			get { return al.SyncRoot; }
-		}
-
-		#endregion
-
-		#region IEnumerable
-
-		public IEnumerator GetEnumerator ()
-		{
-			return ((IEnumerable) al).GetEnumerator ();
-		}
-
-		#endregion
-
 	}
 
 	// Created per field/key pair, created per selector-matched element.
@@ -311,7 +234,7 @@ namespace Mono.Xml.Schema
 //		public int KeyRefSelectorLinePosition;
 //		public bool KeyRefSelectorHasLineInfo;
 
-		public XsdKeyTable KeySequence;
+		public XsdKeyTable OwnerSequence;
 		private bool keyFound = false;
 
 		public XsdKeyEntry (
@@ -337,7 +260,7 @@ namespace Mono.Xml.Schema
 
 		private void Init (XsdKeyTable keyseq, int depth, IXmlLineInfo li)
 		{
-			KeySequence = keyseq;
+			OwnerSequence = keyseq;
 			KeyFields = new XsdKeyEntryFieldCollection ();
 			for (int i = 0; i < keyseq.Selector.Fields.Length; i++)
 				KeyFields.Add (new XsdKeyEntryField (this, keyseq.Selector.Fields [i]));
@@ -366,46 +289,49 @@ namespace Mono.Xml.Schema
 		}
 
 		// In this method, attributes are ignored.
-		// It might throw Exception including non-XmlSchemaException.
-		public void FieldMatches (ArrayList qnameStack, XsdValidatingReader reader)
+		// It might throw Exception.
+		public bool ProcessMatch (bool isAttribute, ArrayList qnameStack, object sender, XmlNameTable nameTable, string sourceUri, object schemaType, NSResolver nsResolver, IXmlLineInfo li, int depth, string attrName, string attrNS, string attrValue, bool isXsiNil, ArrayList currentKeyFieldConsumers)
 		{
+			bool found = false;
 			for (int i = 0; i < KeyFields.Count; i++) {
 				XsdKeyEntryField keyField = KeyFields [i];
-				XsdIdentityPath path = keyField.FieldMatches (qnameStack, reader);
+				XsdIdentityPath path = keyField.Matches (isAttribute, sender, nameTable, qnameStack, sourceUri, schemaType, nsResolver, li, depth, attrName, attrNS, attrValue);
 				if (path != null) {
 					if (keyField.FieldFound) {
 						// HACK: This is not logical by nature. Attributes never be cosuming,
 						// so I used it as a temporary mark to sign it is *just* validated now.
+						// FIXME: This hack seems harmful here.
 						if (!keyField.Consuming)
 							throw new XmlSchemaException ("Two or more matching field was found.",
-								reader, reader.BaseURI, this.KeySequence.SourceSchemaIdentity, null);
+								sender, sourceUri, this.OwnerSequence.SourceSchemaIdentity, null);
 						else
 							keyField.Consuming = false;
 					}
 					if (!keyField.Consumed) {
-						if (reader.XsiNilDepth == reader.Depth && !keyField.SetIdentityField (Guid.Empty, true, XsdAnySimpleType.Instance, reader.Depth, (IXmlLineInfo) reader))
-							throw new XmlSchemaException ("Two or more identical field was found.", reader, reader.BaseURI, KeySequence.SourceSchemaIdentity, null);
+						if (isXsiNil && !keyField.SetIdentityField (Guid.Empty, true, XsdAnySimpleType.Instance, depth, li))
+							throw new XmlSchemaException ("Two or more identical field was found.", sender, sourceUri, OwnerSequence.SourceSchemaIdentity, null);
 						else {
-							XmlSchemaComplexType ct = reader.SchemaType as XmlSchemaComplexType;
+							XmlSchemaComplexType ct = schemaType as XmlSchemaComplexType;
 							if (ct != null && 
 								(ct.ContentType == XmlSchemaContentType.Empty || ct.ContentType == XmlSchemaContentType.ElementOnly) && 
-								reader.SchemaType != XmlSchemaComplexType.AnyType)
-								throw new XmlSchemaException ("Specified schema type is complex type, which is not allowed for identity constraints.", reader, reader.BaseURI, KeySequence.SourceSchemaIdentity, null);
+								schemaType != XmlSchemaComplexType.AnyType)
+								throw new XmlSchemaException ("Specified schema type is complex type, which is not allowed for identity constraints.", sender, sourceUri, OwnerSequence.SourceSchemaIdentity, null);
 							keyField.FieldFound = true;
 							keyField.FieldFoundPath = path;
-							keyField.FieldFoundDepth = reader.Depth;
+							keyField.FieldFoundDepth = depth;
 							keyField.Consuming = true;
-							IXmlLineInfo li = reader as IXmlLineInfo;
 							if (li != null && li.HasLineInfo ()) {
 								keyField.FieldHasLineInfo = true;
 								keyField.FieldLineNumber = li.LineNumber;
 								keyField.FieldLinePosition = li.LinePosition;
 							}
-							reader.CurrentKeyFieldConsumers.Add (keyField);
+							currentKeyFieldConsumers.Add (keyField);
 						}
 					}
 				}
+				found |= keyField.Consumed;
 			}
+			return found;
 		}
 	}
 }

+ 8 - 8
mcs/class/System.XML/Mono.Xml.Schema/XsdKeyTable.cs

@@ -67,9 +67,9 @@ namespace Mono.Xml.Schema
 		public int StartDepth;
 		public XsdKeyTable ReferencedKey;
 
-		public XsdKeyTable (XmlSchemaIdentityConstraint source, XmlReader reader)
+		public XsdKeyTable (XmlSchemaIdentityConstraint source)
 		{
-			Reset (source, reader);
+			Reset (source);
 		}
 
 		public XmlQualifiedName QualifiedName {
@@ -88,7 +88,7 @@ namespace Mono.Xml.Schema
 			get { return selector; }
 		}
 
-		public void Reset (XmlSchemaIdentityConstraint source, XmlReader reader)
+		public void Reset (XmlSchemaIdentityConstraint source)
 		{
 			this.source = source;
 			this.selector = source.CompiledSelector;
@@ -100,28 +100,28 @@ namespace Mono.Xml.Schema
 		}
 
 		// In this method, attributes are ignored.
-		public XsdIdentityPath SelectorMatches (ArrayList qnameStack, XmlReader reader)
+		public XsdIdentityPath SelectorMatches (ArrayList qnameStack, int depth)
 		{
 			for (int i = 0; i < Selector.Paths.Length; i++) {
 				XsdIdentityPath path = Selector.Paths [i];
 				// Only "." hits.
-				if (reader.Depth == this.StartDepth) {
+				if (depth == this.StartDepth) {
 					if (path.OrderedSteps.Length == 0)
 						return path;
 					else
 						continue;
 				}
 				// It does not hit as yet (too shallow to hit).
-				if (reader.Depth - this.StartDepth < path.OrderedSteps.Length - 1)
+				if (depth - this.StartDepth < path.OrderedSteps.Length - 1)
 					continue;
 
 				int iter = path.OrderedSteps.Length;
 				if (path.OrderedSteps [iter-1].IsAttribute)
 					iter--;
 
-				if (path.Descendants && reader.Depth < this.StartDepth + iter)
+				if (path.Descendants && depth < this.StartDepth + iter)
 					continue;
-				else if (!path.Descendants && reader.Depth != this.StartDepth + iter)
+				else if (!path.Descendants && depth != this.StartDepth + iter)
 					continue;
 
 				iter--;

+ 95 - 62
mcs/class/System.XML/Mono.Xml.Schema/XsdValidatingReader.cs

@@ -859,6 +859,7 @@ namespace Mono.Xml.Schema
 				case ContentProc.Lax:
 					break;
 				default:
+					// FIXME: why is it not invalid if xsi:type exists?
 					if (xsiTypeName == null &&
 						(schemas.Contains (reader.NamespaceURI) ||
 						!schemas.MissedSubComponents (reader.NamespaceURI)))
@@ -885,8 +886,10 @@ namespace Mono.Xml.Schema
 			Context.State = next;
 
 #region Key Constraints
-			if (checkKeyConstraints)
-				AssessStartIdentityConstraints ();
+			if (checkKeyConstraints) {
+				ValidateKeySelectors ();
+				ValidateKeyFields ();
+			}
 #endregion
 
 		}
@@ -913,6 +916,7 @@ namespace Mono.Xml.Schema
 					HandleError ("Schema instance nil was specified, where the element declaration for " + qname + "has fixed value constraints.");
 			}
 			// 4.
+			// FIXME: Actually xsi:type is handled in AssessElementSchemaValidity(). So it should be double-checked if it is really required.
 			string xsiType = reader.GetAttribute ("type", XmlSchema.InstanceNamespace);
 			if (xsiType != null) {
 				Context.XsiType = GetXsiType (xsiType);
@@ -1170,7 +1174,7 @@ namespace Mono.Xml.Schema
 						if (entry.StartDepth == reader.Depth) {
 							if (entry.KeyFound)
 								seq.FinishedEntries.Add (entry);
-							else if (entry.KeySequence.SourceSchemaIdentity is XmlSchemaKey)
+							else if (seq.SourceSchemaIdentity is XmlSchemaKey)
 								HandleError ("Key sequence is missing.");
 							seq.Entries.RemoveAt (k);
 							k--;
@@ -1198,7 +1202,7 @@ namespace Mono.Xml.Schema
 		}
 
 		// 3.11.4 Identity Constraint Satisfied
-		private void AssessStartIdentityConstraints ()
+		private void ValidateKeySelectors ()
 		{
 			if (tmpKeyrefPool != null)
 				tmpKeyrefPool.Clear ();
@@ -1218,31 +1222,53 @@ namespace Mono.Xml.Schema
 			// (b) Evaluate current key sequences.
 			for (int i = 0; i < keyTables.Count; i++) {
 				XsdKeyTable seq  = (XsdKeyTable) keyTables [i];
-				if (seq.SelectorMatches (this.elementQNameStack, reader) != null) {
+				if (seq.SelectorMatches (this.elementQNameStack, reader.Depth) != null) {
 					// creates and registers new entry.
 					XsdKeyEntry entry = new XsdKeyEntry (seq, reader.Depth, reader as IXmlLineInfo);
 					seq.Entries.Add (entry);
 				}
 			}
+		}
 
+		private void ValidateKeyFields ()
+		{
 			// (c) Evaluate field paths.
 			for (int i = 0; i < keyTables.Count; i++) {
 				XsdKeyTable seq  = (XsdKeyTable) keyTables [i];
 				// If possible, create new field entry candidates.
 				for (int j = 0; j < seq.Entries.Count; j++) {
-					XsdKeyEntry entry = seq.Entries [j];
 					try {
-						entry.FieldMatches (this.elementQNameStack, this);
-					} catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
-						HandleError ("Identity field value is invalid against its data type.", ex);
+						ProcessKeyEntry (seq.Entries [j]);
+					} catch (XmlSchemaException ex) {
+						HandleError (ex);
 					}
 				}
 			}
 		}
 
+		private void ProcessKeyEntry (XsdKeyEntry entry)
+		{
+			bool isNil = XsiNilDepth == Depth;
+			bool found = entry.ProcessMatch (false, elementQNameStack, this, NameTable, BaseURI, SchemaType, ParserContext.NamespaceManager, this as IXmlLineInfo, Depth, null, null, null, isNil, CurrentKeyFieldConsumers);
+			if (MoveToFirstAttribute ()) {
+				try {
+					do {
+						switch (NamespaceURI) {
+						case XmlNamespaceManager.XmlnsXmlns:
+						case XmlSchema.InstanceNamespace:
+							continue;
+						}
+						found = entry.ProcessMatch (true, elementQNameStack, this, NameTable, BaseURI, SchemaType, ParserContext.NamespaceManager, this as IXmlLineInfo, Depth, LocalName, NamespaceURI, Value, false, CurrentKeyFieldConsumers);
+					} while (MoveToNextAttribute ());
+				} finally {
+					MoveToElement ();
+				}
+			}
+		}
+
 		private XsdKeyTable CreateNewKeyTable (XmlSchemaIdentityConstraint ident)
 		{
-			XsdKeyTable seq = new XsdKeyTable (ident, this);
+			XsdKeyTable seq = new XsdKeyTable (ident);
 			seq.StartDepth = reader.Depth;
 			this.keyTables.Add (seq);
 			return seq;
@@ -1250,49 +1276,59 @@ namespace Mono.Xml.Schema
 
 		private void EndIdentityValidation (XsdKeyTable seq)
 		{
-			ArrayList errors = new ArrayList ();
+			ArrayList errors = null;
 			for (int i = 0; i < seq.Entries.Count; i++) {
 				XsdKeyEntry entry = (XsdKeyEntry) seq.Entries [i];
 				if (entry.KeyFound)
 					continue;
-				if (seq.SourceSchemaIdentity is XmlSchemaKey)
+				if (seq.SourceSchemaIdentity is XmlSchemaKey) {
+					if (errors == null)
+						errors = new ArrayList ();
 					errors.Add ("line " + entry.SelectorLineNumber + "position " + entry.SelectorLinePosition);
+				}
 			}
-			if (errors.Count > 0)
+			if (errors != null)
 				HandleError ("Invalid identity constraints were found. Key was not found. "
 					+ String.Join (", ", errors.ToArray (typeof (string)) as string []));
 
-			errors.Clear ();
-			// Find reference target
+			// If it is keyref, then find reference target
 			XmlSchemaKeyref xsdKeyref = seq.SourceSchemaIdentity as XmlSchemaKeyref;
-			if (xsdKeyref != null) {
-				for (int i = this.keyTables.Count - 1; i >= 0; i--) {
-					XsdKeyTable target = this.keyTables [i] as XsdKeyTable;
-					if (target.SourceSchemaIdentity == xsdKeyref.Target) {
-						seq.ReferencedKey = target;
-						for (int j = 0; j < seq.FinishedEntries.Count; j++) {
-							XsdKeyEntry entry = (XsdKeyEntry) seq.FinishedEntries [j];
-							for (int k = 0; k < target.FinishedEntries.Count; k++) {
-								XsdKeyEntry targetEntry = (XsdKeyEntry) target.FinishedEntries [k];
-								if (entry.CompareIdentity (targetEntry)) {
-									entry.KeyRefFound = true;
-									break;
-								}
-							}
+			if (xsdKeyref != null)
+				EndKeyrefValidation (seq, xsdKeyref.Target);
+		}
+
+		private void EndKeyrefValidation (XsdKeyTable seq, XmlSchemaIdentityConstraint targetIdent)
+		{
+			for (int i = this.keyTables.Count - 1; i >= 0; i--) {
+				XsdKeyTable target = this.keyTables [i] as XsdKeyTable;
+				if (target.SourceSchemaIdentity != targetIdent)
+					continue;
+				seq.ReferencedKey = target;
+				for (int j = 0; j < seq.FinishedEntries.Count; j++) {
+					XsdKeyEntry entry = (XsdKeyEntry) seq.FinishedEntries [j];
+					for (int k = 0; k < target.FinishedEntries.Count; k++) {
+						XsdKeyEntry targetEntry = (XsdKeyEntry) target.FinishedEntries [k];
+						if (entry.CompareIdentity (targetEntry)) {
+							entry.KeyRefFound = true;
+							break;
 						}
 					}
 				}
-				if (seq.ReferencedKey == null)
-					HandleError ("Target key was not found.");
-				for (int i = 0; i < seq.FinishedEntries.Count; i++) {
-					XsdKeyEntry entry = (XsdKeyEntry) seq.FinishedEntries [i];
-					if (!entry.KeyRefFound)
-						errors.Add (" line " + entry.SelectorLineNumber + ", position " + entry.SelectorLinePosition);
+			}
+			if (seq.ReferencedKey == null)
+				HandleError ("Target key was not found.");
+			ArrayList errors = null;
+			for (int i = 0; i < seq.FinishedEntries.Count; i++) {
+				XsdKeyEntry entry = (XsdKeyEntry) seq.FinishedEntries [i];
+				if (!entry.KeyRefFound) {
+					if (errors == null)
+						errors = new ArrayList ();
+					errors.Add (" line " + entry.SelectorLineNumber + ", position " + entry.SelectorLinePosition);
 				}
-				if (errors.Count > 0)
-					HandleError ("Invalid identity constraints were found. Referenced key was not found: "
-						+ String.Join (" / ", errors.ToArray (typeof (string)) as string []));
 			}
+			if (errors != null)
+				HandleError ("Invalid identity constraints were found. Referenced key was not found: "
+					+ String.Join (" / ", errors.ToArray (typeof (string)) as string []));
 		}
 #endregion
 
@@ -1545,6 +1581,23 @@ namespace Mono.Xml.Schema
 				return false;
 		}
 
+		private XmlSchema ReadExternalSchema (string uri)
+		{
+			Uri absUri = resolver.ResolveUri ((BaseURI != "" ? new Uri (BaseURI) : null), uri);
+			XmlTextReader xtr = null;
+			try {
+				xtr = new XmlTextReader (absUri.ToString (),
+					(Stream) resolver.GetEntity (
+						absUri, null, typeof (Stream)),
+					NameTable);
+				return XmlSchema.Read (
+					xtr, ValidationEventHandler);
+			} finally {
+				if (xtr != null)
+					xtr.Close ();
+			}
+		}
+
 		private void ExamineAdditionalSchema ()
 		{
 			if (resolver == null)
@@ -1564,21 +1617,11 @@ namespace Mono.Xml.Schema
 				if (tmp.Length % 2 != 0)
 					HandleError ("Invalid schemaLocation attribute format.");
 				for (int i = 0; i < tmp.Length; i += 2) {
-					Uri absUri = null;
-					XmlTextReader xtr = null;
 					try {
-						absUri = new Uri ((this.BaseURI != "" ? new Uri (BaseURI) : null), tmp [i + 1]);
-						xtr = new XmlTextReader (
-							absUri.ToString (),
-							(Stream) resolver.GetEntity (absUri, null, typeof (Stream)),
-							NameTable);
-						schema = XmlSchema.Read (xtr, ValidationEventHandler);
+						schema = ReadExternalSchema (tmp [i + 1]);
 					} catch (Exception) { // FIXME: (wishlist) It is bad manner ;-(
-						HandleError ("Could not resolve schema location URI: " + absUri, null, true);
+						HandleError ("Could not resolve schema location URI: " + tmp [i + 1], null, true);
 						continue;
-					} finally {
-						if (xtr != null)
-							xtr.Close ();
 					}
 					if (schema.TargetNamespace == null)
 						schema.TargetNamespace = tmp [i];
@@ -1595,20 +1638,10 @@ namespace Mono.Xml.Schema
 			schema = null;
 			string noNsSchemaLocation = reader.GetAttribute ("noNamespaceSchemaLocation", XmlSchema.InstanceNamespace);
 			if (noNsSchemaLocation != null) {
-				Uri absUri = null;
-				XmlTextReader xtr = null;
 				try {
-					absUri = new Uri ((this.BaseURI != "" ? new Uri (BaseURI) : null), noNsSchemaLocation);
-					xtr = new XmlTextReader (
-						absUri.ToString (),
-						(Stream) resolver.GetEntity (absUri, null, typeof (Stream)),
-						NameTable);
-					schema = XmlSchema.Read (xtr, ValidationEventHandler);
+					schema = ReadExternalSchema (noNsSchemaLocation);
 				} catch (Exception) { // FIXME: (wishlist) It is bad manner ;-(
-					HandleError ("Could not resolve schema location URI: " + absUri, null, true);
-				} finally {
-					if (xtr != null)
-						xtr.Close ();
+					HandleError ("Could not resolve schema location URI: " + noNsSchemaLocation, null, true);
 				}
 				if (schema != null && schema.TargetNamespace != null)
 					HandleError ("Specified schema has different target namespace.");