2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / System.XML / Mono.Xml.Schema / XsdValidatingReader.cs
index a3ef1b30a3c9f776d779cba1788c0614b875264c..51cbbcb98c080bd289bcf1fbf7adfac7cbafd4c7 100644 (file)
@@ -6,11 +6,6 @@
 //
 //     (C)2003 Atsushi Enomoto
 //
-// Note:
-//
-// This class doesn't support set_XmlResolver, since it isn't common to XmlReader interface. 
-// Try to set that of xml reader which is used to construct this object.
-//
 
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 using System;
 using System.Collections;
 using System.Collections.Specialized;
+using System.IO;
 using System.Text;
 using System.Xml;
 using System.Xml.Schema;
 using Mono.Xml;
 
+#if NET_2_0
+using ValException = System.Xml.Schema.XmlSchemaValidationException;
+#else
+using ValException = System.Xml.Schema.XmlSchemaException;
+#endif
+
+using QName = System.Xml.XmlQualifiedName;
+using ContentProc = System.Xml.Schema.XmlSchemaContentProcessing;
+using XsElement = System.Xml.Schema.XmlSchemaElement;
+using XsAttribute = System.Xml.Schema.XmlSchemaAttribute;
+using ComplexType = System.Xml.Schema.XmlSchemaComplexType;
+using SimpleType = System.Xml.Schema.XmlSchemaSimpleType;
+using SimpleTypeRest = System.Xml.Schema.XmlSchemaSimpleTypeRestriction;
+using SimpleTypeList = System.Xml.Schema.XmlSchemaSimpleTypeList;
+using SimpleTypeUnion = System.Xml.Schema.XmlSchemaSimpleTypeUnion;
+using XsDatatype = System.Xml.Schema.XmlSchemaDatatype;
+
 namespace Mono.Xml.Schema
 {
        internal class XsdValidatingReader : XmlReader, IXmlLineInfo, IHasXmlSchemaInfo, IHasXmlParserContext, IXmlNamespaceResolver
        {
-               static char [] wsChars = new char [] {' ', '\t', '\n', '\r'};
+               static readonly XsAttribute [] emptyAttributeArray =
+                       new XsAttribute [0];
 
                XmlReader reader;
                XmlResolver resolver;
@@ -54,35 +68,31 @@ namespace Mono.Xml.Schema
                XmlSchemaSet schemas = new XmlSchemaSet ();
                bool namespaces = true;
 
+#region ID Constraints
                bool checkIdentity = true;
-               Hashtable idList = new Hashtable ();
-               ArrayList missingIDReferences;
-               string thisElementId;
+               XsdIDManager idManager = new XsdIDManager ();
+#endregion
 
+#region Key Constraints
+               bool checkKeyConstraints = true;
                ArrayList keyTables = new ArrayList ();
                ArrayList currentKeyFieldConsumers;
+               ArrayList tmpKeyrefPool;
+#endregion
+               ArrayList elementQNameStack = new ArrayList ();
 
-               XsdValidationStateManager stateManager = new XsdValidationStateManager ();
-               XsdValidationContext context = new XsdValidationContext ();
+               XsdParticleStateManager state = new XsdParticleStateManager ();
 
+               int skipValidationDepth = -1;
                int xsiNilDepth = -1;
                StringBuilder storedCharacters = new StringBuilder ();
                bool shouldValidateCharacters;
-               int skipValidationDepth = -1;
 
-               XmlSchemaAttribute [] defaultAttributes = new XmlSchemaAttribute [0];
+               XsAttribute [] defaultAttributes = emptyAttributeArray;
                int currentDefaultAttribute = -1;
-               XmlQualifiedName currentQName;
-
-               ArrayList elementQNameStack = new ArrayList ();
-               bool popContext;
-
-               // Property Cache.
-               bool defaultAttributeConsumed;
-
-               // Validation engine cached object
                ArrayList defaultAttributesCache = new ArrayList ();
-               ArrayList tmpKeyrefPool;
+               bool defaultAttributeConsumed;
+               object currentAttrType;
 
 #region .ctor
                public XsdValidatingReader (XmlReader reader)
@@ -90,20 +100,19 @@ namespace Mono.Xml.Schema
                        this.reader = reader;
                        readerLineInfo = reader as IXmlLineInfo;
                        sourceReaderSchemaInfo = reader as IHasXmlSchemaInfo;
+                       schemas.ValidationEventHandler += ValidationEventHandler;
                }
 #endregion
 
                public ValidationEventHandler ValidationEventHandler;
 
                // Private Properties
-               private XmlQualifiedName CurrentQName {
-                       get {
-                               if (currentQName == null)
-                                       currentQName = new XmlQualifiedName (LocalName, NamespaceURI);
-                               return currentQName;
-                       }
+
+               private XsdValidationContext Context {
+                       get { return state.Context; }
                }
 
+#region Key Constraints
                internal ArrayList CurrentKeyFieldConsumers {
                        get {
                                if (currentKeyFieldConsumers == null)
@@ -111,14 +120,7 @@ namespace Mono.Xml.Schema
                                return currentKeyFieldConsumers;
                        }
                }
-
-               private ArrayList MissingIDReferences {
-                       get {
-                               if (missingIDReferences == null)
-                                       missingIDReferences = new ArrayList ();
-                               return missingIDReferences;
-                       }
-               }
+#endregion
 
                // Public Non-overrides
 
@@ -131,10 +133,6 @@ namespace Mono.Xml.Schema
                        set { namespaces = value; }
                }
 
-               public XmlReader Reader {
-                       get { return reader; }
-               }
-
                // This is required to resolve xsi:schemaLocation
                public XmlResolver XmlResolver {
                        set {
@@ -159,20 +157,22 @@ namespace Mono.Xml.Schema
 
                                switch (NodeType) {
                                case XmlNodeType.Element:
-                                       if (context.ActualType != null)
-                                               return context.ActualType;
-                                       else if (context.Element != null)
-                                               return context.Element.ElementType;
+                                       if (Context.ActualType != null)
+                                               return Context.ActualType;
                                        else
                                                return SourceReaderSchemaType;
                                case XmlNodeType.Attribute:
-                                       XmlSchemaComplexType ct = context.ActualType as XmlSchemaComplexType;
-                                       if (ct != null) {
-                                               XmlSchemaAttribute attdef = ct.AttributeUses [CurrentQName] as XmlSchemaAttribute;
-                                               if (attdef != null)
-                                                       return attdef.AttributeType;
+                                       if (currentAttrType == null) {
+                                               ComplexType ct = Context.ActualType as ComplexType;
+                                               if (ct != null) {
+                                                       XsAttribute attdef = ct.AttributeUses [new QName (LocalName, NamespaceURI)] as XsAttribute;
+                                                       if (attdef != null)
+                                                               currentAttrType = attdef.AttributeType;
+                                                       return currentAttrType;
+                                               }
+                                               currentAttrType = SourceReaderSchemaType;
                                        }
-                                       return SourceReaderSchemaType;
+                                       return currentAttrType;
                                default:
                                        return SourceReaderSchemaType;
                                }
@@ -215,13 +215,23 @@ namespace Mono.Xml.Schema
 
                // It is used only for independent XmlReader use, not for XmlValidatingReader.
 #if NET_2_0
+               [Obsolete]
                public override object ReadTypedValue ()
 #else
                public object ReadTypedValue ()
 #endif
                {
-                       XmlSchemaDatatype dt = SchemaType as XmlSchemaDatatype;
-                       XmlSchemaSimpleType st = SchemaType as XmlSchemaSimpleType;
+                       object o = XmlSchemaUtil.ReadTypedValue (this,
+                               SchemaType, ParserContext.NamespaceManager,
+                               storedCharacters);
+                       storedCharacters.Length = 0;
+                       return o;
+               }
+               
+               private object ReadTypedValueCore ()
+               {
+                       XsDatatype dt = SchemaType as XsDatatype;
+                       SimpleType st = SchemaType as SimpleType;
                        if (st != null)
                                dt = st.Datatype;
                        if (dt == null)
@@ -256,7 +266,7 @@ namespace Mono.Xml.Schema
                        return null;
                }
 
-               // Public Overrided Properties
+               // Public Overriden Properties
 
                public override int AttributeCount {
                        get {
@@ -325,11 +335,11 @@ namespace Mono.Xml.Schema
                        get { return GetAttribute (localName, ns); }
                }
 
-               int IXmlLineInfo.LineNumber {
+               public int LineNumber {
                        get { return readerLineInfo != null ? readerLineInfo.LineNumber : 0; }
                }
 
-               int IXmlLineInfo.LinePosition {
+               public int LinePosition {
                        get { return readerLineInfo != null ? readerLineInfo.LinePosition : 0; }
                }
 
@@ -350,7 +360,7 @@ namespace Mono.Xml.Schema
                                if (defaultAttributeConsumed)
                                        return String.Empty;
 
-                               XmlQualifiedName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
+                               QName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
                                string prefix = Prefix;
                                if (prefix == String.Empty)
                                        return qname.Name;
@@ -393,7 +403,7 @@ namespace Mono.Xml.Schema
                                        return reader.Prefix;
                                if (defaultAttributeConsumed)
                                        return String.Empty;
-                               XmlQualifiedName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
+                               QName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
                                string prefix = this.ParserContext.NamespaceManager.LookupPrefix (qname.Namespace, false);
                                if (prefix == null)
                                        return String.Empty;
@@ -453,11 +463,6 @@ namespace Mono.Xml.Schema
 
                // Private Methods
 
-               private XmlQualifiedName QualifyName (string name)
-               {
-                       return XmlQualifiedName.Parse (name, this);
-               }
-
                private void HandleError (string error)
                {
                        HandleError (error, null);
@@ -473,17 +478,17 @@ namespace Mono.Xml.Schema
                        if (ValidationType == ValidationType.None)      // extra quick check
                                return;
 
-                       XmlSchemaException schemaException = new XmlSchemaException (error, 
+                       ValException schemaException = new ValException (error, 
                                        this, this.BaseURI, null, innerException);
                        HandleError (schemaException, isWarning);
                }
 
-               private void HandleError (XmlSchemaException schemaException)
+               private void HandleError (ValException schemaException)
                {
                        HandleError (schemaException, false);
                }
 
-               private void HandleError (XmlSchemaException schemaException, bool isWarning)
+               private void HandleError (ValException schemaException, bool isWarning)
                {
                        if (ValidationType == ValidationType.None)
                                return;
@@ -498,38 +503,38 @@ namespace Mono.Xml.Schema
                                throw e.Exception;
                }
 
-               private XmlSchemaElement FindElement (string name, string ns)
+               private XsElement FindElement (string name, string ns)
                {
-                       return (XmlSchemaElement) schemas.GlobalElements [new XmlQualifiedName (name, ns)];
+                       return (XsElement) schemas.GlobalElements [new QName (name, ns)];
                }
 
-               private XmlSchemaType FindType (XmlQualifiedName qname)
+               private XmlSchemaType FindType (QName qname)
                {
                        return (XmlSchemaType) schemas.GlobalTypes [qname];
                }
 
                private void ValidateStartElementParticle ()
                {
-                       stateManager.CurrentElement = null;
-                       context.SiblingState =
-                               context.SiblingState.EvaluateStartElement (
-                                       reader.LocalName, reader.NamespaceURI);
-                       if (context.SiblingState == XsdValidationState.Invalid)
+                       if (Context.State == null)
+                               return;
+                       Context.XsiType = null;
+                       state.CurrentElement = null;
+                       Context.EvaluateStartElement (reader.LocalName,
+                               reader.NamespaceURI);
+                       if (Context.IsInvalid)
                                HandleError ("Invalid start element: " + reader.NamespaceURI + ":" + reader.LocalName);
 
-                       context.Element = stateManager.CurrentElement;
-                       if (context.Element != null)
-                               context.SchemaType = context.Element.ElementType;
+                       Context.SetElement (state.CurrentElement);
                }
 
                private void ValidateEndElementParticle ()
                {
-                       if (context.ChildState != null) {
-                               if (!context.ChildState.EvaluateEndElement ()) {
+                       if (Context.State != null) {
+                               if (!Context.EvaluateEndElement ()) {
                                        HandleError ("Invalid end element: " + reader.Name);
                                }
                        }
-                       context.PopScope (reader.Depth);
+                       state.PopContext ();
                }
 
                // Utility for missing validation completion related to child items.
@@ -538,37 +543,46 @@ namespace Mono.Xml.Schema
                        if (xsiNilDepth >= 0 && xsiNilDepth < reader.Depth)
                                HandleError ("Element item appeared, while current element context is nil.");
 
-                       storedCharacters.Append (reader.Value);
+                       if (shouldValidateCharacters)
+                               storedCharacters.Append (reader.Value);
                }
 
                // Utility for missing validation completion related to child items.
-               private void ValidateEndCharacters ()
+               private void ValidateEndSimpleContent ()
                {
-                       if (context.ActualType == null)
+                       if (shouldValidateCharacters)
+                               ValidateEndSimpleContentCore ();
+                       shouldValidateCharacters = false;
+                       storedCharacters.Length = 0;
+               }
+
+               private void ValidateEndSimpleContentCore ()
+               {
+                       if (Context.ActualType == null)
                                return;
 
                        string value = storedCharacters.ToString ();
 
-                       if (storedCharacters.Length == 0) {
+                       if (value.Length == 0) {
                                // 3.3.4 Element Locally Valid (Element) 5.1.2
-                               if (context.Element != null) {
-                                       if (context.Element.ValidatedDefaultValue != null)
-                                               value = context.Element.ValidatedDefaultValue;
+                               if (Context.Element != null) {
+                                       if (Context.Element.ValidatedDefaultValue != null)
+                                               value = Context.Element.ValidatedDefaultValue;
                                }                                       
                        }
 
-                       XmlSchemaDatatype dt = context.ActualType as XmlSchemaDatatype;
-                       XmlSchemaSimpleType st = context.ActualType as XmlSchemaSimpleType;
+                       XsDatatype dt = Context.ActualType as XsDatatype;
+                       SimpleType st = Context.ActualType as SimpleType;
                        if (dt == null) {
                                if (st != null) {
                                        dt = st.Datatype;
                                } else {
-                                       XmlSchemaComplexType ct = context.ActualType as XmlSchemaComplexType;
+                                       ComplexType ct = Context.ActualType as ComplexType;
                                        dt = ct.Datatype;
                                        switch (ct.ContentType) {
                                        case XmlSchemaContentType.ElementOnly:
                                        case XmlSchemaContentType.Empty:
-                                               if (storedCharacters.Length > 0)
+                                               if (value.Length > 0)
                                                        HandleError ("Character content not allowed.");
                                                break;
                                        }
@@ -576,54 +590,36 @@ namespace Mono.Xml.Schema
                        }
                        if (dt != null) {
                                // 3.3.4 Element Locally Valid (Element) :: 5.2.2.2. Fixed value constraints
-                               if (context.Element != null && context.Element.ValidatedFixedValue != null)
-                                       if (value != context.Element.ValidatedFixedValue)
+                               if (Context.Element != null && Context.Element.ValidatedFixedValue != null)
+                                       if (value != Context.Element.ValidatedFixedValue)
                                                HandleError ("Fixed value constraint was not satisfied.");
                                AssessStringValid (st, dt, value);
                        }
 
-                       // Identity field value
-                       if (currentKeyFieldConsumers != null) {
-                               while (this.currentKeyFieldConsumers.Count > 0) {
-                                       XsdKeyEntryField field = this.currentKeyFieldConsumers [0] as XsdKeyEntryField;
-                                       if (field.Identity != null)
-                                               HandleError ("Two or more identical field was found. Former value is '" + field.Identity + "' .");
-                                       object identity = null; // This means empty value
-                                       if (dt != null) {
-                                               try {
-                                                       identity = dt.ParseValue (value, NameTable, ParserContext.NamespaceManager);
-                                               } catch (Exception ex) { // FIXME: (wishlist) This is bad manner ;-(
-                                                       HandleError ("Identity value is invalid against its data type " + dt.TokenizedType, ex);
-                                               }
-                                       }
-                                       if (identity == null)
-                                               identity = value;
-
-                                       if (!field.SetIdentityField (identity, reader.Depth == xsiNilDepth, dt as XsdAnySimpleType, this))
-                                               HandleError ("Two or more identical key value was found: '" + value + "' .");
-                                       this.currentKeyFieldConsumers.RemoveAt (0);
-                               }
-                       }
+#region Key Constraints
+                       if (checkKeyConstraints)
+                               ValidateSimpleContentIdentity (dt, value);
+#endregion
 
                        shouldValidateCharacters = false;
                }
 
                // 3.14.4 String Valid 
-               private void AssessStringValid (XmlSchemaSimpleType st,
-                       XmlSchemaDatatype dt, string value)
+               private void AssessStringValid (SimpleType st,
+                       XsDatatype dt, string value)
                {
-                       XmlSchemaDatatype validatedDatatype = dt;
+                       XsDatatype validatedDatatype = dt;
                        if (st != null) {
                                string normalized = validatedDatatype.Normalize (value);
                                string [] values;
-                               XmlSchemaDatatype itemDatatype;
-                               XmlSchemaSimpleType itemSimpleType;
+                               XsDatatype itemDatatype;
+                               SimpleType itemSimpleType;
                                switch (st.DerivedBy) {
                                case XmlSchemaDerivationMethod.List:
-                                       XmlSchemaSimpleTypeList listContent = st.Content as XmlSchemaSimpleTypeList;
-                                       values = normalized.Split (wsChars);
-                                       itemDatatype = listContent.ValidatedListItemType as XmlSchemaDatatype;
-                                       itemSimpleType = listContent.ValidatedListItemType as XmlSchemaSimpleType;
+                                       SimpleTypeList listContent = st.Content as SimpleTypeList;
+                                       values = normalized.Split (XmlChar.WhitespaceChars);
+                                       itemDatatype = listContent.ValidatedListItemType as XsDatatype;
+                                       itemSimpleType = listContent.ValidatedListItemType as SimpleType;
                                        for (int vi = 0; vi < values.Length; vi++) {
                                                string each = values [vi];
                                                if (each == String.Empty)
@@ -642,14 +638,14 @@ namespace Mono.Xml.Schema
                                        }
                                        break;
                                case XmlSchemaDerivationMethod.Union:
-                                       XmlSchemaSimpleTypeUnion union = st.Content as XmlSchemaSimpleTypeUnion;
+                                       SimpleTypeUnion union = st.Content as SimpleTypeUnion;
                                        {
                                                string each = normalized;
                                                // validate against ValidatedItemType
                                                bool passed = false;
                                                foreach (object eachType in union.ValidatedTypes) {
-                                                       itemDatatype = eachType as XmlSchemaDatatype;
-                                                       itemSimpleType = eachType as XmlSchemaSimpleType;
+                                                       itemDatatype = eachType as XsDatatype;
+                                                       itemSimpleType = eachType as SimpleType;
                                                        if (itemDatatype != null) {
                                                                try {
                                                                        itemDatatype.ParseValue (each, NameTable, ParserContext.NamespaceManager);
@@ -660,7 +656,7 @@ namespace Mono.Xml.Schema
                                                        else {
                                                                try {
                                                                        AssessStringValid (itemSimpleType, itemSimpleType.Datatype, each);
-                                                               } catch (XmlSchemaException) {
+                                                               } catch (ValException) {
                                                                        continue;
                                                                }
                                                        }
@@ -674,7 +670,7 @@ namespace Mono.Xml.Schema
                                        }
                                        break;
                                case XmlSchemaDerivationMethod.Restriction:
-                                       XmlSchemaSimpleTypeRestriction str = st.Content as XmlSchemaSimpleTypeRestriction;
+                                       SimpleTypeRest str = st.Content as SimpleTypeRest;
                                        // facet validation
                                        if (str != null) {
                                                /* Don't forget to validate against inherited type's facets 
@@ -682,7 +678,7 @@ namespace Mono.Xml.Schema
                                                 * be restriction?
                                                 * */
                                                 // mmm, will check later.
-                                               XmlSchemaSimpleType baseType = st.BaseXmlSchemaType as XmlSchemaSimpleType;
+                                               SimpleType baseType = st.BaseXmlSchemaType as SimpleType;
                                                if (baseType != null) {
                                                         AssessStringValid(baseType, dt, normalized);
                                                }
@@ -704,14 +700,14 @@ namespace Mono.Xml.Schema
                        }
                }
 
-               private object GetLocalTypeDefinition (string name)
+               private object GetXsiType (string name)
                {
                        object xsiType = null;
-                       XmlQualifiedName typeQName = QualifyName (name);
-                       if (typeQName == XmlSchemaComplexType.AnyTypeName)
-                               xsiType = XmlSchemaComplexType.AnyType;
+                       QName typeQName = QName.Parse (name, this);
+                       if (typeQName == ComplexType.AnyTypeName)
+                               xsiType = ComplexType.AnyType;
                        else if (XmlSchemaUtil.IsBuiltInDatatypeName (typeQName))
-                               xsiType = XmlSchemaDatatype.FromName (typeQName);
+                               xsiType = XsDatatype.FromName (typeQName);
                        else
                                xsiType = FindType (typeQName);
                        return xsiType;
@@ -721,8 +717,8 @@ namespace Mono.Xml.Schema
                private void AssessLocalTypeDerivationOK (object xsiType, object baseType, XmlSchemaDerivationMethod flag)
                {
                        XmlSchemaType xsiSchemaType = xsiType as XmlSchemaType;
-                       XmlSchemaComplexType baseComplexType = baseType as XmlSchemaComplexType;
-                       XmlSchemaComplexType xsiComplexType = xsiSchemaType as XmlSchemaComplexType;
+                       ComplexType baseComplexType = baseType as ComplexType;
+                       ComplexType xsiComplexType = xsiSchemaType as ComplexType;
                        if (xsiType != baseType) {
                                // Extracted (not extraneous) check for 3.4.6 TypeDerivationOK.
                                if (baseComplexType != null)
@@ -739,21 +735,21 @@ namespace Mono.Xml.Schema
                        if (xsiComplexType != null)
                                try {
                                        xsiComplexType.ValidateTypeDerivationOK (baseType, null, null);
-                               } catch (XmlSchemaException ex) {
+                               } catch (ValException ex) {
 //                                     HandleError ("Locally specified schema complex type derivation failed. " + ex.Message, ex);
                                        HandleError (ex);
                                }
                        else {
-                               XmlSchemaSimpleType xsiSimpleType = xsiType as XmlSchemaSimpleType;
+                               SimpleType xsiSimpleType = xsiType as SimpleType;
                                if (xsiSimpleType != null) {
                                        try {
                                                xsiSimpleType.ValidateTypeDerivationOK (baseType, null, null, true);
-                                       } catch (XmlSchemaException ex) {
+                                       } catch (ValException ex) {
 //                                             HandleError ("Locally specified schema simple type derivation failed. " + ex.Message, ex);
                                                HandleError (ex);
                                        }
                                }
-                               else if (xsiType is XmlSchemaDatatype) {
+                               else if (xsiType is XsDatatype) {
                                        // do nothing
                                }
                                else
@@ -764,22 +760,12 @@ namespace Mono.Xml.Schema
                // Section 3.3.4 of the spec.
                private void AssessStartElementSchemaValidity ()
                {
-                       // If the reader is inside xsi:nil (and failed on validation),
-                       // then simply skip its content.
+                       // If the reader is inside xsi:nil (and failed
+                       // on validation), then simply skip its content.
                        if (xsiNilDepth >= 0 && xsiNilDepth < reader.Depth)
                                HandleError ("Element item appeared, while current element context is nil.");
 
-                       context.Load (reader.Depth);
-                       if (context.ChildState != null) {
-                               context.SiblingState = context.ChildState;
-                               context.ChildState = null;
-                       }
-
-                       // If validation state exists, then first assess particle validity.
-                       context.SchemaType = null;
-                       if (context.SiblingState != null) {
-                               ValidateStartElementParticle ();
-                       }
+                       ValidateStartElementParticle ();
 
                        string xsiNilValue = reader.GetAttribute ("nil", XmlSchema.InstanceNamespace);
                        if (xsiNilValue != null)
@@ -797,87 +783,89 @@ namespace Mono.Xml.Schema
                        string xsiTypeName = reader.GetAttribute ("type", XmlSchema.InstanceNamespace);
                        if (xsiTypeName != null) {
                                xsiTypeName = xsiTypeName.Trim (XmlChar.WhitespaceChars);
-                               object xsiType = GetLocalTypeDefinition (xsiTypeName);
+                               object xsiType = GetXsiType (xsiTypeName);
                                if (xsiType == null)
                                        HandleError ("The instance type was not found: " + xsiTypeName + " .");
                                else {
                                        XmlSchemaType xsiSchemaType = xsiType as XmlSchemaType;
-                                       if (xsiSchemaType != null && this.context.Element != null) {
-                                               XmlSchemaType elemBaseType = context.Element.ElementType as XmlSchemaType;
+                                       if (xsiSchemaType != null && this.Context.Element != null) {
+                                               XmlSchemaType elemBaseType = Context.Element.ElementType as XmlSchemaType;
                                                if (elemBaseType != null && (xsiSchemaType.DerivedBy & elemBaseType.FinalResolved) != 0)
                                                        HandleError ("The instance type is prohibited by the type of the context element.");
-                                               if (elemBaseType != xsiType && (xsiSchemaType.DerivedBy & this.context.Element.BlockResolved) != 0)
+                                               if (elemBaseType != xsiType && (xsiSchemaType.DerivedBy & this.Context.Element.BlockResolved) != 0)
                                                        HandleError ("The instance type is prohibited by the context element.");
                                        }
-                                       XmlSchemaComplexType xsiComplexType = xsiType as XmlSchemaComplexType;
+                                       ComplexType xsiComplexType = xsiType as ComplexType;
                                        if (xsiComplexType != null && xsiComplexType.IsAbstract)
                                                HandleError ("The instance type is abstract: " + xsiTypeName + " .");
                                        else {
                                                // If current schema type exists, then this xsi:type must be
                                                // valid extension of that type. See 1.2.1.2.4.
-                                               if (context.Element != null) {
-                                                       AssessLocalTypeDerivationOK (xsiType, context.Element.ElementType, context.Element.BlockResolved);
+                                               if (Context.Element != null) {
+                                                       AssessLocalTypeDerivationOK (xsiType, Context.Element.ElementType, Context.Element.BlockResolved);
                                                }
                                                AssessStartElementLocallyValidType (xsiType);   // 1.2.2:
-                                               context.LocalTypeDefinition = xsiType;
+                                               Context.XsiType = xsiType;
                                        }
                                }
                        }
-                       else
-                               context.LocalTypeDefinition = null;
 
                        // Create Validation Root, if not exist.
                        // [Schema Validity Assessment (Element) 1.1]
-                       if (context.Element == null)
-                               context.Element = FindElement (reader.LocalName, reader.NamespaceURI);
-                       if (context.Element != null) {
-                               if (xsiTypeName == null) {
-                                       context.SchemaType = context.Element.ElementType;
-                                       AssessElementLocallyValidElement (context.Element, xsiNilValue);        // 1.1.2
+                       if (Context.Element == null) {
+                               state.CurrentElement = FindElement (reader.LocalName, reader.NamespaceURI);
+                               Context.SetElement (state.CurrentElement);
+                       }
+                       if (Context.Element != null) {
+                               if (Context.XsiType == null) {
+                                       AssessElementLocallyValidElement (xsiNilValue); // 1.1.2
                                }
                        } else {
-                               switch (stateManager.ProcessContents) {
-                               case XmlSchemaContentProcessing.Skip:
+                               switch (state.ProcessContents) {
+                               case ContentProc.Skip:
                                        break;
-                               case XmlSchemaContentProcessing.Lax:
-                                       /*
-                                       schema = schemas [reader.NamespaceURI];
-                                       if (schema != null && !schema.missedSubComponents)
-                                               HandleError ("Element declaration for " + reader.LocalName + " is missing.");
-                                       */
+                               case ContentProc.Lax:
                                        break;
                                default:
                                        if (xsiTypeName == null &&
                                                (schemas.Contains (reader.NamespaceURI) ||
                                                !schemas.MissedSubComponents (reader.NamespaceURI)))
-                                               HandleError ("Element declaration for " + reader.LocalName + " is missing.");
+                                               HandleError ("Element declaration for " + new QName (reader.LocalName, reader.NamespaceURI) + " is missing.");
                                        break;
                                }
                        }
 
-                       if (stateManager.ProcessContents
-                               == XmlSchemaContentProcessing.Skip)
+                       state.PushContext ();
+
+                       XsdValidationState next = null;
+                       if (state.ProcessContents == ContentProc.Skip)
                                skipValidationDepth = reader.Depth;
                        else {
                                // create child particle state.
-                               XmlSchemaComplexType xsComplexType = SchemaType as XmlSchemaComplexType;
+                               ComplexType xsComplexType = SchemaType as ComplexType;
                                if (xsComplexType != null)
-                                       context.ChildState = stateManager.Create (xsComplexType.ValidatableParticle);
-                               else if (stateManager.ProcessContents == XmlSchemaContentProcessing.Lax)
-                                       context.ChildState = stateManager.Create (XmlSchemaAny.AnyTypeContent);
+                                       next = state.Create (xsComplexType.ValidatableParticle);
+                               else if (state.ProcessContents == ContentProc.Lax)
+                                       next = state.Create (XmlSchemaAny.AnyTypeContent);
                                else
-                                       context.ChildState = stateManager.Create (XmlSchemaParticle.Empty);
+                                       next = state.Create (XmlSchemaParticle.Empty);
                        }
+                       Context.State = next;
 
-                       AssessStartIdentityConstraints ();
+#region Key Constraints
+                       if (checkKeyConstraints) {
+                               ValidateKeySelectors ();
+                               ValidateKeyFields ();
+                       }
+#endregion
 
-                       context.PushScope (reader.Depth);
                }
 
                // 3.3.4 Element Locally Valid (Element)
-               private void AssessElementLocallyValidElement (XmlSchemaElement element, string xsiNilValue)
+               private void AssessElementLocallyValidElement (string xsiNilValue)
                {
-                       XmlQualifiedName qname = new XmlQualifiedName (reader.LocalName, reader.NamespaceURI);
+                       XsElement element = Context.Element;
+                       QName qname = new QName (reader.LocalName, reader.NamespaceURI);
                        // 1.
                        if (element == null)
                                HandleError ("Element declaration is required for " + qname);
@@ -888,21 +876,21 @@ namespace Mono.Xml.Schema
                        if (!element.ActualIsNillable && xsiNilValue != null)
                                HandleError ("This element declaration is not nillable: " + qname);
                        // 3.2.
-                       // Note that 3.2.1 xsi:nil constraints are to be validated in
+                       // Note that 3.2.1 xsi:nil constraints are to be 
+                       // validated in AssessElementSchemaValidity() and 
+                       // ValidateCharacters().
                        else if (xsiNilValue == "true") {
-                               // AssessElementSchemaValidity() and ValidateCharacters()
-
                                if (element.ValidatedFixedValue != null)
                                        HandleError ("Schema instance nil was specified, where the element declaration for " + qname + "has fixed value constraints.");
                        }
-                       // 4.
+                       // 4. xsi:type (it takes precedence than element type)
                        string xsiType = reader.GetAttribute ("type", XmlSchema.InstanceNamespace);
                        if (xsiType != null) {
-                               context.LocalTypeDefinition = GetLocalTypeDefinition (xsiType);
-                               AssessLocalTypeDerivationOK (context.LocalTypeDefinition, element.ElementType, element.BlockResolved);
+                               Context.XsiType = GetXsiType (xsiType);
+                               AssessLocalTypeDerivationOK (Context.XsiType, element.ElementType, element.BlockResolved);
                        }
                        else
-                               context.LocalTypeDefinition = null;
+                               Context.XsiType = null;
 
                        // 5 Not all things cannot be assessed here.
                        // It is common to 5.1 and 5.2
@@ -922,8 +910,8 @@ namespace Mono.Xml.Schema
                                HandleError ("Schema type does not exist.");
                                return;
                        }
-                       XmlSchemaComplexType cType = schemaType as XmlSchemaComplexType;
-                       XmlSchemaSimpleType sType = schemaType as XmlSchemaSimpleType;
+                       ComplexType cType = schemaType as ComplexType;
+                       SimpleType sType = schemaType as SimpleType;
                        if (sType != null) {
                                // 3.1.1.
                                while (reader.MoveToNextAttribute ()) {
@@ -955,7 +943,7 @@ namespace Mono.Xml.Schema
                }
 
                // 3.4.4 Element Locally Valid (Complex Type)
-               private void AssessElementLocallyValidComplexType (XmlSchemaComplexType cType)
+               private void AssessElementLocallyValidComplexType (ComplexType cType)
                {
                        // 1.
                        if (cType.IsAbstract)
@@ -973,11 +961,12 @@ namespace Mono.Xml.Schema
                                        case XmlSchema.InstanceNamespace:
                                                continue;
                                        }
-                                       XmlQualifiedName qname = new XmlQualifiedName (reader.LocalName, reader.NamespaceURI);
-                                       XmlSchemaObject attMatch = FindAttributeDeclaration (cType, qname);
+                                       QName qname = new QName (reader.LocalName, reader.NamespaceURI);
+                                       // including 3.10.4 Item Valid (Wildcard)
+                                       XmlSchemaObject attMatch = XmlSchemaUtil.FindAttributeDeclaration (reader.NamespaceURI, schemas, cType, qname);
                                        if (attMatch == null)
                                                HandleError ("Attribute declaration was not found for " + qname);
-                                       XmlSchemaAttribute attdecl = attMatch as XmlSchemaAttribute;
+                                       XsAttribute attdecl = attMatch as XsAttribute;
                                        if (attdecl != null) {
                                                AssessAttributeLocallyValidUse (attdecl);
                                                AssessAttributeLocallyValid (attdecl);
@@ -989,7 +978,7 @@ namespace Mono.Xml.Schema
                        // Collect default attributes.
                        // 4.
                        foreach (DictionaryEntry entry in cType.AttributeUses) {
-                               XmlSchemaAttribute attr = (XmlSchemaAttribute) entry.Value;
+                               XsAttribute attr = (XsAttribute) entry.Value;
                                if (reader [attr.QualifiedName.Name, attr.QualifiedName.Namespace] == null) {
                                        if (attr.ValidatedUse == XmlSchemaUse.Required && 
                                                attr.ValidatedFixedValue == null)
@@ -998,65 +987,27 @@ namespace Mono.Xml.Schema
                                                defaultAttributesCache.Add (attr);
                                }
                        }
-                       defaultAttributes = (XmlSchemaAttribute []) 
-                               defaultAttributesCache.ToArray (typeof (XmlSchemaAttribute));
-                       context.DefaultAttributes = defaultAttributes;
+                       if (defaultAttributesCache.Count == 0)
+                               defaultAttributes = emptyAttributeArray;
+                       else
+                               defaultAttributes = (XsAttribute []) 
+                                       defaultAttributesCache.ToArray (
+                                               typeof (XsAttribute));
                        defaultAttributesCache.Clear ();
                        // 5. wild IDs was already checked above.
                }
 
-               // Spec 3.10.4 Item Valid (Wildcard)
-               private static bool AttributeWildcardItemValid (XmlSchemaAnyAttribute anyAttr, XmlQualifiedName qname, string ns)
-               {
-                       if (anyAttr.HasValueAny)
-                               return true;
-                       if (anyAttr.HasValueOther && (anyAttr.TargetNamespace == "" || ns != anyAttr.TargetNamespace))
-                               return true;
-                       if (anyAttr.HasValueTargetNamespace && ns == anyAttr.TargetNamespace)
-                               return true;
-                       if (anyAttr.HasValueLocal && ns == "")
-                               return true;
-                       for (int i = 0; i < anyAttr.ResolvedNamespaces.Count; i++)
-                               if (anyAttr.ResolvedNamespaces [i] == ns)
-                                       return true;
-                       return false;
-               }
-
-               private XmlSchemaObject FindAttributeDeclaration (
-                       XmlSchemaComplexType cType,
-                       XmlQualifiedName qname)
-               {
-                       XmlSchemaObject result = cType.AttributeUses [qname];
-                       if (result != null)
-                               return result;
-                       if (cType.AttributeWildcard == null)
-                               return null;
-
-                       if (!AttributeWildcardItemValid (cType.AttributeWildcard, qname, reader.NamespaceURI))
-                               return null;
-
-                       if (cType.AttributeWildcard.ResolvedProcessContents == XmlSchemaContentProcessing.Skip)
-                               return cType.AttributeWildcard;
-                       XmlSchemaAttribute attr = schemas.GlobalAttributes [qname] as XmlSchemaAttribute;
-                       if (attr != null)
-                               return attr;
-                       if (cType.AttributeWildcard.ResolvedProcessContents == XmlSchemaContentProcessing.Lax)
-                               return cType.AttributeWildcard;
-                       else
-                               return null;
-               }
-
                // 3.2.4 Attribute Locally Valid and 3.4.4
-               private void AssessAttributeLocallyValid (XmlSchemaAttribute attr)
+               private void AssessAttributeLocallyValid (XsAttribute attr)
                {
                        // 2. - 4.
                        if (attr.AttributeType == null)
                                HandleError ("Attribute type is missing for " + attr.QualifiedName);
-                       XmlSchemaDatatype dt = attr.AttributeType as XmlSchemaDatatype;
+                       XsDatatype dt = attr.AttributeType as XsDatatype;
                        if (dt == null)
-                               dt = ((XmlSchemaSimpleType) attr.AttributeType).Datatype;
+                               dt = ((SimpleType) attr.AttributeType).Datatype;
                        // It is a bit heavy process, so let's omit as long as possible ;-)
-                       if (dt != XmlSchemaSimpleType.AnySimpleType || attr.ValidatedFixedValue != null) {
+                       if (dt != SimpleType.AnySimpleType || attr.ValidatedFixedValue != null) {
                                string normalized = dt.Normalize (reader.Value);
                                object parsedValue = null;
                                try {
@@ -1068,45 +1019,17 @@ namespace Mono.Xml.Schema
                                        HandleError ("The value of the attribute " + attr.QualifiedName + " does not match with its fixed value.");
                                        parsedValue = dt.ParseValue (attr.ValidatedFixedValue, reader.NameTable, this.ParserContext.NamespaceManager);
                                }
-                               if (this.checkIdentity)
-                                       AssessEachAttributeIdentityConstraint (dt, parsedValue);
-                       }
-               }
-
-               // 3.4.4-5 wild IDs
-               private void AssessEachAttributeIdentityConstraint (
-                       XmlSchemaDatatype dt, object parsedValue)
-               {
-                       // Validate identity constraints.
-                       string str = parsedValue as string;
-                       switch (dt.TokenizedType) {
-                       case XmlTokenizedType.ID:
-                               if (thisElementId != null)
-                                       HandleError ("ID type attribute was already assigned in the containing element.");
-                               thisElementId = str;
-                               if (idList.Contains (str))
-                                       HandleError ("Duplicate ID value was found.");
-                               else
-                                       idList.Add (str, str);
-                               if (MissingIDReferences.Contains (str))
-                                       MissingIDReferences.Remove (str);
-                               break;
-                       case XmlTokenizedType.IDREF:
-                               if (!idList.Contains (str))
-                                       MissingIDReferences.Add (str);
-                               break;
-                       case XmlTokenizedType.IDREFS:
-                               string [] idrefs = (string []) parsedValue;
-                               for (int i = 0; i < idrefs.Length; i++) {
-                                       string id = idrefs [i];
-                                       if (!idList.Contains (id))
-                                               MissingIDReferences.Add (id);
+#region ID Constraints
+                               if (this.checkIdentity) {
+                                       string error = idManager.AssessEachAttributeIdentityConstraint (dt, parsedValue, ((QName) elementQNameStack [elementQNameStack.Count - 1]).Name);
+                                       if (error != null)
+                                               HandleError (error);
                                }
-                               break;
+#endregion
                        }
                }
 
-               private void AssessAttributeLocallyValidUse (XmlSchemaAttribute attr)
+               private void AssessAttributeLocallyValidUse (XsAttribute attr)
                {
                        // This is extra check than spec 3.5.4
                        if (attr.ValidatedUse == XmlSchemaUse.Prohibited)
@@ -1115,35 +1038,42 @@ namespace Mono.Xml.Schema
 
                private void AssessEndElementSchemaValidity ()
                {
-                       if (context.ChildState == null)
-                               context.ChildState =
-                                       context.SiblingState;
                        ValidateEndElementParticle ();  // validate against childrens' state.
 
-                       if (shouldValidateCharacters) {
-                               ValidateEndCharacters ();
-                               shouldValidateCharacters = false;
-                       }
+                       ValidateEndSimpleContent ();
 
                        // 3.3.4 Assess ElementLocallyValidElement 5: value constraints.
                        // 3.3.4 Assess ElementLocallyValidType 3.1.3. = StringValid(3.14.4)
-                       // => ValidateEndCharacters().
+                       // => ValidateEndSimpleContent().
 
+#region Key Constraints
+                       if (checkKeyConstraints)
+                               ValidateEndElementKeyConstraints ();
+#endregion
+
+                       // Reset xsi:nil, if required.
+                       if (xsiNilDepth == reader.Depth)
+                               xsiNilDepth = -1;
+               }
+
+#region Key Constraints
+               private void ValidateEndElementKeyConstraints ()
+               {
                        // Reset Identity constraints.
                        for (int i = 0; i < keyTables.Count; i++) {
-                               XsdKeyTable keyTable = this.keyTables [i] as XsdKeyTable;
-                               if (keyTable.StartDepth == reader.Depth) {
-                                       EndIdentityValidation (keyTable);
+                               XsdKeyTable seq = this.keyTables [i] as XsdKeyTable;
+                               if (seq.StartDepth == reader.Depth) {
+                                       EndIdentityValidation (seq);
                                } else {
-                                       for (int k = 0; k < keyTable.Entries.Count; k++) {
-                                               XsdKeyEntry entry = keyTable.Entries [k] as XsdKeyEntry;
+                                       for (int k = 0; k < seq.Entries.Count; k++) {
+                                               XsdKeyEntry entry = seq.Entries [k] as XsdKeyEntry;
                                                // Remove finished (maybe key not found) entries.
                                                if (entry.StartDepth == reader.Depth) {
                                                        if (entry.KeyFound)
-                                                               keyTable.FinishedEntries.Add (entry);
-                                                       else if (entry.KeySequence.SourceSchemaIdentity is XmlSchemaKey)
+                                                               seq.FinishedEntries.Add (entry);
+                                                       else if (seq.SourceSchemaIdentity is XmlSchemaKey)
                                                                HandleError ("Key sequence is missing.");
-                                                       keyTable.Entries.RemoveAt (k);
+                                                       seq.Entries.RemoveAt (k);
                                                        k--;
                                                }
                                                // Pop validated key depth to find two or more fields.
@@ -1160,27 +1090,23 @@ namespace Mono.Xml.Schema
                                }
                        }
                        for (int i = 0; i < keyTables.Count; i++) {
-                               XsdKeyTable keyseq = this.keyTables [i] as XsdKeyTable;
-                               if (keyseq.StartDepth == reader.Depth) {
+                               XsdKeyTable seq = this.keyTables [i] as XsdKeyTable;
+                               if (seq.StartDepth == reader.Depth) {
                                        keyTables.RemoveAt (i);
                                        i--;
                                }
                        }
-
-                       // Reset xsi:nil, if required.
-                       if (xsiNilDepth == reader.Depth)
-                               xsiNilDepth = -1;
                }
 
                // 3.11.4 Identity Constraint Satisfied
-               private void AssessStartIdentityConstraints ()
+               private void ValidateKeySelectors ()
                {
                        if (tmpKeyrefPool != null)
                                tmpKeyrefPool.Clear ();
-                       if (context.Element != null && context.Element.Constraints.Count > 0) {
+                       if (Context.Element != null && Context.Element.Constraints.Count > 0) {
                                // (a) Create new key sequences, if required.
-                               for (int i = 0; i < context.Element.Constraints.Count; i++) {
-                                       XmlSchemaIdentityConstraint ident = (XmlSchemaIdentityConstraint) context.Element.Constraints [i];
+                               for (int i = 0; i < Context.Element.Constraints.Count; i++) {
+                                       XmlSchemaIdentityConstraint ident = (XmlSchemaIdentityConstraint) Context.Element.Constraints [i];
                                        XsdKeyTable seq = CreateNewKeyTable (ident);
                                        if (ident is XmlSchemaKeyref) {
                                                if (tmpKeyrefPool == null)
@@ -1193,82 +1119,142 @@ 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);
+                                       XsdKeyEntry entry = new XsdKeyEntry (seq, reader.Depth, readerLineInfo);
                                        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] as XsdKeyEntry;
                                        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 (ValException ex) {
+                                               HandleError (ex);
                                        }
                                }
                        }
                }
 
+               private void ProcessKeyEntry (XsdKeyEntry entry)
+               {
+                       bool isNil = XsiNilDepth == Depth;
+                       entry.ProcessMatch (false, elementQNameStack, this, NameTable, BaseURI, SchemaType, ParserContext.NamespaceManager, readerLineInfo, Depth, null, null, null, isNil, CurrentKeyFieldConsumers);
+                       if (MoveToFirstAttribute ()) {
+                               try {
+                                       do {
+                                               switch (NamespaceURI) {
+                                               case XmlNamespaceManager.XmlnsXmlns:
+                                               case XmlSchema.InstanceNamespace:
+                                                       continue;
+                                               }
+                                               entry.ProcessMatch (true, elementQNameStack, this, NameTable, BaseURI, SchemaType, ParserContext.NamespaceManager, readerLineInfo, 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;
                }
 
+               private void ValidateSimpleContentIdentity (
+                       XmlSchemaDatatype dt, string value)
+               {
+                       // Identity field value
+                       if (currentKeyFieldConsumers != null) {
+                               while (this.currentKeyFieldConsumers.Count > 0) {
+                                       XsdKeyEntryField field = this.currentKeyFieldConsumers [0] as XsdKeyEntryField;
+                                       if (field.Identity != null)
+                                               HandleError ("Two or more identical field was found. Former value is '" + field.Identity + "' .");
+                                       object identity = null; // This means empty value
+                                       if (dt != null) {
+                                               try {
+                                                       identity = dt.ParseValue (value, NameTable, ParserContext.NamespaceManager);
+                                               } catch (Exception ex) { // FIXME: (wishlist) This is bad manner ;-(
+                                                       HandleError ("Identity value is invalid against its data type " + dt.TokenizedType, ex);
+                                               }
+                                       }
+                                       if (identity == null)
+                                               identity = value;
+
+                                       if (!field.SetIdentityField (identity, reader.Depth == xsiNilDepth, dt as XsdAnySimpleType, this.Depth, readerLineInfo))
+                                               HandleError ("Two or more identical key value was found: '" + value + "' .");
+                                       this.currentKeyFieldConsumers.RemoveAt (0);
+                               }
+                       }
+               }
+
                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
 
                // Overrided Methods
 
@@ -1306,19 +1292,19 @@ namespace Mono.Xml.Schema
                        if (value != null)
                                return value;
 
-                       XmlQualifiedName qname = SplitQName (name);
+                       QName qname = SplitQName (name);
                        return GetDefaultAttribute (qname.Name, qname.Namespace);
                }
 
-               private XmlQualifiedName SplitQName (string name)
+               private QName SplitQName (string name)
                {
                        if (!XmlChar.IsName (name))
                                throw new ArgumentException ("Invalid name was specified.", "name");
 
                        Exception ex = null;
-                       XmlQualifiedName qname = XmlSchemaUtil.ToQName (reader, name, out ex);
+                       QName qname = XmlSchemaUtil.ToQName (reader, name, out ex);
                        if (ex != null)
-                               return XmlQualifiedName.Empty;
+                               return QName.Empty;
                        else
                                return qname;
                }
@@ -1352,7 +1338,7 @@ namespace Mono.Xml.Schema
                private int FindDefaultAttribute (string localName, string ns)
                {
                        for (int i = 0; i < this.defaultAttributes.Length; i++) {
-                               XmlSchemaAttribute attr = defaultAttributes [i];
+                               XsAttribute attr = defaultAttributes [i];
                                if (attr.QualifiedName.Name == localName &&
                                        (ns == null || attr.QualifiedName.Namespace == ns))
                                        return i;
@@ -1360,7 +1346,7 @@ namespace Mono.Xml.Schema
                        return -1;
                }
 
-               bool IXmlLineInfo.HasLineInfo ()
+               public bool HasLineInfo ()
                {
                        return readerLineInfo != null && readerLineInfo.HasLineInfo ();
                }
@@ -1388,7 +1374,7 @@ namespace Mono.Xml.Schema
                                return;
                        }
 
-                       currentQName = null;
+                       currentAttrType = null;
                        if (i < reader.AttributeCount) {
                                reader.MoveToAttribute (i);
                                this.currentDefaultAttribute = -1;
@@ -1411,7 +1397,7 @@ namespace Mono.Xml.Schema
                                return reader.MoveToAttribute (name);
                        }
 
-                       currentQName = null;
+                       currentAttrType = null;
                        bool b = reader.MoveToAttribute (name);
                        if (b) {
                                this.currentDefaultAttribute = -1;
@@ -1430,7 +1416,7 @@ namespace Mono.Xml.Schema
                                return reader.MoveToAttribute (localName, ns);
                        }
 
-                       currentQName = null;
+                       currentAttrType = null;
                        bool b = reader.MoveToAttribute (localName, ns);
                        if (b) {
                                this.currentDefaultAttribute = -1;
@@ -1455,7 +1441,7 @@ namespace Mono.Xml.Schema
                {
                        currentDefaultAttribute = -1;
                        defaultAttributeConsumed = false;
-                       currentQName = null;
+                       currentAttrType = null;
                        return reader.MoveToElement ();
                }
 
@@ -1467,7 +1453,7 @@ namespace Mono.Xml.Schema
                                return reader.MoveToFirstAttribute ();
                        }
 
-                       currentQName = null;
+                       currentAttrType = null;
                        if (reader.AttributeCount > 0) {
                                bool b = reader.MoveToFirstAttribute ();
                                if (b) {
@@ -1494,7 +1480,7 @@ namespace Mono.Xml.Schema
                                return reader.MoveToNextAttribute ();
                        }
 
-                       currentQName = null;
+                       currentAttrType = null;
                        if (currentDefaultAttribute >= 0) {
                                if (defaultAttributes.Length == currentDefaultAttribute + 1)
                                        return false;
@@ -1519,15 +1505,35 @@ namespace Mono.Xml.Schema
                                return false;
                }
 
+               private XmlSchema ReadExternalSchema (string uri)
+               {
+                       Uri absUri = resolver.ResolveUri ((BaseURI != "" ? new Uri (BaseURI) : null), uri);
+                       string absUriString = absUri != null ? absUri.ToString () : String.Empty;
+                       XmlTextReader xtr = null;
+                       try {
+                               xtr = new XmlTextReader (absUriString,
+                                       (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)
+                               return;
                        XmlSchema schema = null;
                        string schemaLocation = reader.GetAttribute ("schemaLocation", XmlSchema.InstanceNamespace);
                        bool schemaAdded = false;
                        if (schemaLocation != null) {
                                string [] tmp = null;
                                try {
-                                       schemaLocation = XmlSchemaDatatype.FromName ("token", XmlSchema.Namespace).Normalize (schemaLocation);
+                                       schemaLocation = XsDatatype.FromName ("token", XmlSchema.Namespace).Normalize (schemaLocation);
                                        tmp = schemaLocation.Split (XmlChar.WhitespaceChars);
                                } catch (Exception ex) {
                                        HandleError ("Invalid schemaLocation attribute format.", ex, true);
@@ -1536,18 +1542,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 (), NameTable);
-                                               schema = XmlSchema.Read (xtr, null);
+                                               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];
@@ -1564,17 +1563,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 (), NameTable);
-                                       schema = XmlSchema.Read (xtr, null);
+                                       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.");
@@ -1590,57 +1582,46 @@ namespace Mono.Xml.Schema
                                schemas.Compile ();
                }
 
-               private bool HasMissingIDReferences ()
-               {
-                       return missingIDReferences != null
-                               && missingIDReferences.Count > 0;
-               }
-
                public override bool Read ()
                {
                        currentDefaultAttribute = -1;
                        defaultAttributeConsumed = false;
-                       currentQName = null;
+                       currentAttrType = null;
+#region ID Constraints
                        if (this.checkIdentity)
-                               thisElementId = null;
-                       defaultAttributes = new XmlSchemaAttribute [0];
-                       if (!schemas.IsCompiled)
-                               schemas.Compile ();
-                       if (popContext) {
-                               elementQNameStack.RemoveAt (elementQNameStack.Count - 1);
-                               popContext = false;
-                       }
+                               idManager.OnStartElement ();
+#endregion
+                       defaultAttributes = emptyAttributeArray;
 
                        bool result = reader.Read ();
+#region ID Constraints
                        // 3.3.4 ElementLocallyValidElement 7 = Root Valid.
                        if (!result && this.checkIdentity &&
-                               HasMissingIDReferences ())
-                               HandleError ("There are missing ID references: " +
-                                       String.Join (" ",
-                                       this.missingIDReferences.ToArray (typeof (string)) as string []));
+                               idManager.HasMissingIDReferences ())
+                               HandleError ("There are missing ID references: " + idManager.GetMissingIDString ());
+#endregion
+
+                       // FIXME: schemaLocation could be specified 
+                       // at any Depth.
+                       if (reader.Depth == 0 &&
+                               reader.NodeType == XmlNodeType.Element)
+                               ExamineAdditionalSchema ();
+                       if (schemas.Count == 0)
+                               return result;
+                       if (!schemas.IsCompiled)
+                               schemas.Compile ();
 
                        switch (reader.NodeType) {
                        case XmlNodeType.Element:
-                               // FIXME: schemaLocation could be specified 
-                               // at any Depth.
-                               if (reader.Depth == 0)
-                                       ExamineAdditionalSchema ();
-
-                               this.elementQNameStack.Add (new XmlQualifiedName (reader.LocalName, reader.NamespaceURI));
+#region Key Constraints
+                               if (checkKeyConstraints)
+                                       this.elementQNameStack.Add (new QName (reader.LocalName, reader.NamespaceURI));
+#endregion
 
                                // If there is no schema information, then no validation is performed.
-                               if (schemas.Count == 0)
-                                       break;
-
                                if (skipValidationDepth < 0 || reader.Depth <= skipValidationDepth) {
-                                       if (shouldValidateCharacters) {
-                                               ValidateEndCharacters ();
-                                               shouldValidateCharacters = false;
-                                       }
+                                       ValidateEndSimpleContent ();
                                        AssessStartElementSchemaValidity ();
-                                       storedCharacters.Length = 0;
-                               } else {
-                                       context.Clear ();
                                }
 
                                if (reader.IsEmptyElement)
@@ -1649,22 +1630,20 @@ namespace Mono.Xml.Schema
                                        shouldValidateCharacters = true;
                                break;
                        case XmlNodeType.EndElement:
-                               if (reader.Depth == skipValidationDepth) {
+                               if (reader.Depth == skipValidationDepth)
                                        skipValidationDepth = -1;
-                                       context.Clear ();
-                               }
-                               else
+                               else if (skipValidationDepth < 0 || reader.Depth <= skipValidationDepth)
                                        AssessEndElementSchemaValidity ();
 
-                               storedCharacters.Length = 0;
-                               context.ChildState = null;
-                               popContext = true;
+                               if (checkKeyConstraints)
+                                       elementQNameStack.RemoveAt (elementQNameStack.Count - 1);
                                break;
 
                        case XmlNodeType.CDATA:
                        case XmlNodeType.SignificantWhitespace:
                        case XmlNodeType.Text:
-                               XmlSchemaComplexType ct = context.ActualType as XmlSchemaComplexType;
+                               // FIXME: does this check make sense?
+                               ComplexType ct = Context.ActualType as ComplexType;
                                if (ct != null && storedCharacters.Length > 0) {
                                        switch (ct.ContentType) {
                                        case XmlSchemaContentType.ElementOnly:
@@ -1722,69 +1701,144 @@ namespace Mono.Xml.Schema
                {
                        reader.ResolveEntity ();
                }
+       }
 
-               internal class XsdValidationContext
+       internal class XsdValidationContext
+       {
+               public XsdValidationContext ()
                {
-                       Hashtable contextStack;
+               }
+
+               // Some of them might be missing (See the spec section 5.3, and also 3.3.4).
+               public XsElement Element;
+               public object XsiType; // xsi:type
+               internal XsdValidationState State;
+
+               // Note that it represents current element's type.
+               public object ActualType {
+                       get {
+                               if (XsiType != null)
+                                       return XsiType;
+                               else
+                                       return Element != null ? Element.ElementType : null;
+                       }
+               }
 
-                       public XsdValidationContext ()
-                       {
-                               contextStack = new Hashtable ();
+#if NET_2_0
+               public XmlSchemaType ActualSchemaType {
+                       get {
+                               object at = ActualType;
+                               if (at == null)
+                                       return null;
+                               XmlSchemaType st = at as XmlSchemaType;
+                               if (st == null)
+                                       st = XmlSchemaType.GetBuiltInSimpleType (
+                                       ((XmlSchemaDatatype) at).TypeCode);
+                               return st;
                        }
+               }
+#endif
 
-                       // Some of them might be missing (See the spec section 5.3, and also 3.3.4).
-                       public XmlSchemaElement Element;
-                       public XsdValidationState SiblingState;
-                       public XsdValidationState ChildState;
-                       public XmlSchemaAttribute [] DefaultAttributes;
+               public bool IsInvalid {
+                       get { return State == XsdValidationState.Invalid; }
+               }
 
-                       // Some of them might be missing (See the spec section 5.3).
-                       public object SchemaType;
+               public object Clone ()
+               {
+                       return MemberwiseClone ();
+               }
 
-                       public object LocalTypeDefinition;
+               public void EvaluateStartElement (
+                       string localName, string ns)
+               {
+                       State = State.EvaluateStartElement (localName, ns);
+               }
 
-                       public object ActualType {
-                               get {
-                                       if (LocalTypeDefinition != null)
-                                               return LocalTypeDefinition;
-                                       else
-                                               return SchemaType;
-                               }
-                       }
+               public bool EvaluateEndElement ()
+               {
+                       return State.EvaluateEndElement ();
+               }
 
-                       public void Clear ()
-                       {
-                               Element = null;
-                               SchemaType = null;
-                               SiblingState = null;
-                               // FIXME: It should be fine. Need more refactory.
-//                             ChildState = null;
-                               LocalTypeDefinition = null;
-                       }
+               public void SetElement (XsElement element)
+               {
+                       Element = element;
+               }
+       }
 
-                       public void PushScope (int depth)
-                       {
-                               contextStack [depth] = this.MemberwiseClone ();
-                       }
+       internal class XsdIDManager
+       {
+               public XsdIDManager ()
+               {
+               }
+
+               Hashtable idList = new Hashtable ();
+               ArrayList missingIDReferences;
+               string thisElementId;
 
-                       public void PopScope (int depth)
-                       {
-                               Load (depth);
-                               contextStack.Remove (depth + 1);
+               private ArrayList MissingIDReferences {
+                       get {
+                               if (missingIDReferences == null)
+                                       missingIDReferences = new ArrayList ();
+                               return missingIDReferences;
                        }
+               }
+
+               public void OnStartElement ()
+               {
+                       thisElementId = null;
+               }
 
-                       public void Load (int depth)
-                       {
-                               Clear ();
-                               XsdValidationContext restored = (XsdValidationContext) contextStack [depth];
-                               if (restored != null) {
-                                       this.Element = restored.Element;
-                                       this.SiblingState = restored.SiblingState;
-                                       this.SchemaType = restored.SchemaType;
-                                       this.LocalTypeDefinition = restored.LocalTypeDefinition;
+               // 3.4.4-5 wild IDs
+               public string AssessEachAttributeIdentityConstraint (
+                       XsDatatype dt, object parsedValue, string elementName)
+               {
+                       // Validate identity constraints.
+                       string str = parsedValue as string;
+                       switch (dt.TokenizedType) {
+                       case XmlTokenizedType.ID:
+                               if (thisElementId != null)
+                                       return "ID type attribute was already assigned in the containing element.";
+                               else
+                                       thisElementId = str;
+                               if (idList.ContainsKey (str))
+                                       return "Duplicate ID value was found.";
+                               else
+                                       idList.Add (str, elementName);
+                               if (MissingIDReferences.Contains (str))
+                                       MissingIDReferences.Remove (str);
+                               break;
+                       case XmlTokenizedType.IDREF:
+                               if (!idList.Contains (str))
+                                       MissingIDReferences.Add (str);
+                               break;
+                       case XmlTokenizedType.IDREFS:
+                               string [] idrefs = (string []) parsedValue;
+                               for (int i = 0; i < idrefs.Length; i++) {
+                                       string id = idrefs [i];
+                                       if (!idList.Contains (id))
+                                               MissingIDReferences.Add (id);
                                }
+                               break;
                        }
+                       return null;
+               }
+
+               public object FindID (string name)
+               {
+                       return idList [name];
                }
-       }
 
+               public bool HasMissingIDReferences ()
+               {
+                       return missingIDReferences != null
+                               && missingIDReferences.Count > 0;
+               }
+
+               public string GetMissingIDString ()
+               {
+                       return String.Join (" ",
+                               MissingIDReferences.ToArray (typeof (string))
+                                       as string []);
+               }
+       }
 }