2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / System.XML / Mono.Xml.Schema / XsdValidatingReader.cs
index 561f350b304404f709bf0ae39bd4bdc334bf8e2c..51cbbcb98c080bd289bcf1fbf7adfac7cbafd4c7 100644 (file)
 //
 //     (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
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 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
 {
-       public class XsdValidatingReader : XmlReader, IXmlLineInfo, IHasXmlSchemaInfo, IHasXmlParserContext
+       internal class XsdValidatingReader : XmlReader, IXmlLineInfo, IHasXmlSchemaInfo, IHasXmlParserContext, IXmlNamespaceResolver
        {
-               char [] wsChars = new char [] {' ', '\t', '\n', '\r'};
+               static readonly XsAttribute [] emptyAttributeArray =
+                       new XsAttribute [0];
 
                XmlReader reader;
-               XmlValidatingReader xvReader;
+               XmlResolver resolver;
+               IHasXmlSchemaInfo sourceReaderSchemaInfo;
                IXmlLineInfo readerLineInfo;
-               bool laxElementValidation = true;
-               bool reportNoValidationError;
-               XmlSchemaCollection schemas = new XmlSchemaCollection ();
+               ValidationType validationType;
+               XmlSchemaSet schemas = new XmlSchemaSet ();
                bool namespaces = true;
 
-               ArrayList idList = new ArrayList ();
-               ArrayList missingIDReferences = new ArrayList ();
-               string thisElementId;
+#region ID Constraints
+               bool checkIdentity = true;
+               XsdIDManager idManager = new XsdIDManager ();
+#endregion
 
+#region Key Constraints
+               bool checkKeyConstraints = true;
                ArrayList keyTables = new ArrayList ();
-               ArrayList currentKeyFieldConsumers = new ArrayList ();
+               ArrayList currentKeyFieldConsumers;
+               ArrayList tmpKeyrefPool;
+#endregion
+               ArrayList elementQNameStack = new ArrayList ();
 
-               XsdValidationStateManager stateManager = new XsdValidationStateManager ();
-               XsdValidationContext context = new XsdValidationContext ();
-               XsdValidationState childParticleState;
+               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.
-               int nonDefaultAttributeCount;
-               bool defaultAttributeConsumed;
-
-               // Validation engine cached object
                ArrayList defaultAttributesCache = new ArrayList ();
-               ArrayList tmpKeyrefPool = new ArrayList ();
+               bool defaultAttributeConsumed;
+               object currentAttrType;
 
 #region .ctor
                public XsdValidatingReader (XmlReader reader)
-                       : this (reader, null)
-               {
-               }
-               
-               public XsdValidatingReader (XmlReader reader, XmlReader validatingReader)
                {
                        this.reader = reader;
-                       xvReader = validatingReader as XmlValidatingReader;
-                       if (xvReader != null) {
-                               if (xvReader.ValidationType == ValidationType.None)
-                                       reportNoValidationError = true;
-                       }
                        readerLineInfo = reader as IXmlLineInfo;
+                       sourceReaderSchemaInfo = reader as IHasXmlSchemaInfo;
+                       schemas.ValidationEventHandler += ValidationEventHandler;
                }
 #endregion
-               // Provate Properties
-               private XmlQualifiedName CurrentQName {
-                       get {
-                               if (currentQName == null)
-                                       currentQName = new XmlQualifiedName (LocalName, NamespaceURI);
-                               return currentQName;
-                       }
+
+               public ValidationEventHandler ValidationEventHandler;
+
+               // Private Properties
+
+               private XsdValidationContext Context {
+                       get { return state.Context; }
                }
 
+#region Key Constraints
                internal ArrayList CurrentKeyFieldConsumers {
-                       get { return currentKeyFieldConsumers; }
+                       get {
+                               if (currentKeyFieldConsumers == null)
+                                       currentKeyFieldConsumers = new ArrayList ();
+                               return currentKeyFieldConsumers;
+                       }
                }
+#endregion
 
                // Public Non-overrides
 
+               public int XsiNilDepth {
+                       get { return xsiNilDepth; }
+               }
+
                public bool Namespaces {
                        get { return namespaces; }
                        set { namespaces = value; }
                }
 
-               public XmlReader Reader {
-                       get { return reader; }
+               // This is required to resolve xsi:schemaLocation
+               public XmlResolver XmlResolver {
+                       set {
+                               resolver = value;
+                       }
                }
 
                // This should be changed before the first Read() call.
-               public XmlSchemaCollection Schemas {
+               public XmlSchemaSet Schemas {
                        get { return schemas; }
+                       set {
+                               if (ReadState != ReadState.Initial)
+                                       throw new InvalidOperationException ("Schemas must be set before the first call to Read().");
+                               schemas = value;
+                       }
                }
 
                public object SchemaType {
@@ -117,42 +157,81 @@ 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 null;
+                                               return SourceReaderSchemaType;
                                case XmlNodeType.Attribute:
-                                       // TODO: Default attribute support
-                                       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 null;
+                                       return currentAttrType;
                                default:
-                                       return null;
+                                       return SourceReaderSchemaType;
                                }
                        }
                }
 
-               // This property is never used in Mono.
+               private object SourceReaderSchemaType {
+                       get { return this.sourceReaderSchemaInfo != null ? sourceReaderSchemaInfo.SchemaType : null; }
+               }
+
                public ValidationType ValidationType {
-                       get {
-                               if (reportNoValidationError)
-                                       return ValidationType.None;
-                               else
-                                       return ValidationType.Schema;
+                       get { return validationType; }
+                       set {
+                               if (ReadState != ReadState.Initial)
+                                       throw new InvalidOperationException ("ValidationType must be set before reading.");
+                               validationType = value;
                        }
                }
 
+               IDictionary IXmlNamespaceResolver.GetNamespacesInScope (XmlNamespaceScope scope)
+               {
+                       IXmlNamespaceResolver resolver = reader as IXmlNamespaceResolver;
+                       if (resolver == null)
+                               throw new NotSupportedException ("The input XmlReader does not implement IXmlNamespaceResolver and thus this validating reader cannot collect in-scope namespaces.");
+                       return resolver.GetNamespacesInScope (scope);
+               }
+
+               string IXmlNamespaceResolver.LookupPrefix (string ns)
+               {
+                       return ((IXmlNamespaceResolver) this).LookupPrefix (ns, false);
+               }
+
+               string IXmlNamespaceResolver.LookupPrefix (string ns, bool atomizedNames)
+               {
+                       IXmlNamespaceResolver resolver = reader as IXmlNamespaceResolver;
+                       if (resolver == null)
+                               throw new NotSupportedException ("The input XmlReader does not implement IXmlNamespaceResolver and thus this validating reader cannot execute namespace prefix lookup.");
+                       return resolver.LookupPrefix (ns, atomizedNames);
+               }
+
                // 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)
@@ -179,7 +258,7 @@ namespace Mono.Xml.Schema
                                                loop = false;
                                                break;
                                        }
-                               } while (loop && !EOF);
+                               } while (loop && !EOF && ReadState == ReadState.Interactive);
                                return dt.ParseValue (storedCharacters.ToString (), NameTable, ParserContext.NamespaceManager);
                        case XmlNodeType.Attribute:
                                return dt.ParseValue (Value, NameTable, ParserContext.NamespaceManager);
@@ -187,21 +266,11 @@ namespace Mono.Xml.Schema
                        return null;
                }
 
-               public ValidationEventHandler ValidationEventHandler;
-
-               // Public Overrided Properties
+               // Public Overriden Properties
 
                public override int AttributeCount {
                        get {
-                               /*
-                               if (NodeType == XmlNodeType.Element)
-                                       return attributeCount;
-                               else if (IsDefault)
-                                       return 0;
-                               else
-                                       return reader.AttributeCount;
-                               */
-                               return nonDefaultAttributeCount + defaultAttributes.Length;
+                               return reader.AttributeCount + defaultAttributes.Length;
                        }
                }
 
@@ -266,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; }
                }
 
@@ -291,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;
@@ -334,8 +403,8 @@ namespace Mono.Xml.Schema
                                        return reader.Prefix;
                                if (defaultAttributeConsumed)
                                        return String.Empty;
-                               XmlQualifiedName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
-                               string prefix = this.ParserContext.NamespaceManager.LookupPrefix (qname.Namespace);
+                               QName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
+                               string prefix = this.ParserContext.NamespaceManager.LookupPrefix (qname.Namespace, false);
                                if (prefix == null)
                                        return String.Empty;
                                else
@@ -355,12 +424,13 @@ namespace Mono.Xml.Schema
                        get {
                                if (currentDefaultAttribute < 0)
                                        return reader.Value;
-                               return defaultAttributes [currentDefaultAttribute].ValidatedDefaultValue;
+                               string value = defaultAttributes [currentDefaultAttribute].ValidatedDefaultValue;
+                               if (value == null)
+                                       value = defaultAttributes [currentDefaultAttribute].ValidatedFixedValue;
+                               return value;
                        }
                }
 
-               XmlQualifiedName qnameXmlLang = new XmlQualifiedName ("lang", XmlNamespaceManager.XmlnsXml);
-
                public override string XmlLang {
                        get {
                                string xmlLang = reader.XmlLang;
@@ -369,7 +439,10 @@ namespace Mono.Xml.Schema
                                int idx = this.FindDefaultAttribute ("lang", XmlNamespaceManager.XmlnsXml);
                                if (idx < 0)
                                        return null;
-                               return defaultAttributes [idx].ValidatedDefaultValue;
+                               xmlLang = defaultAttributes [idx].ValidatedDefaultValue;
+                               if (xmlLang == null)
+                                       xmlLang = defaultAttributes [idx].ValidatedFixedValue;
+                               return xmlLang;
                        }
                }
 
@@ -381,22 +454,15 @@ namespace Mono.Xml.Schema
                                int idx = this.FindDefaultAttribute ("space", XmlNamespaceManager.XmlnsXml);
                                if (idx < 0)
                                        return XmlSpace.None;
-                               return (XmlSpace) Enum.Parse (typeof (XmlSpace), defaultAttributes [idx].ValidatedDefaultValue, false);
+                               string spaceSpec = defaultAttributes [idx].ValidatedDefaultValue;
+                               if (spaceSpec == null)
+                                       spaceSpec = defaultAttributes [idx].ValidatedFixedValue;
+                               return (XmlSpace) Enum.Parse (typeof (XmlSpace), spaceSpec, false);
                        }
                }
 
                // Private Methods
 
-               private XmlQualifiedName QualifyName (string name)
-               {
-                       int colonAt = name.IndexOf (':');
-                       if (colonAt < 0)
-                               return new XmlQualifiedName (name, null);
-                       else
-                               return new XmlQualifiedName (name.Substring (colonAt + 1),
-                                       LookupNamespace (name.Substring (0, colonAt)));
-               }
-
                private void HandleError (string error)
                {
                        HandleError (error, null);
@@ -404,117 +470,119 @@ namespace Mono.Xml.Schema
 
                private void HandleError (string error, Exception innerException)
                {
-                       if (reportNoValidationError)    // extra quick check
+                       HandleError (error, innerException, false);
+               }
+
+               private void HandleError (string error, Exception innerException, bool isWarning)
+               {
+                       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);
+                       HandleError (schemaException, isWarning);
                }
 
-               private void HandleError (XmlSchemaException schemaException)
+               private void HandleError (ValException schemaException)
                {
-                       if (reportNoValidationError)
+                       HandleError (schemaException, false);
+               }
+
+               private void HandleError (ValException schemaException, bool isWarning)
+               {
+                       if (ValidationType == ValidationType.None)
                                return;
 
                        ValidationEventArgs e = new ValidationEventArgs (schemaException,
-                               schemaException.Message, XmlSeverityType.Error);
+                               schemaException.Message, isWarning ? XmlSeverityType.Warning : XmlSeverityType.Error);
 
-                       if (this.ValidationEventHandler != null)
-                               this.ValidationEventHandler (this, e);
-                       else if (xvReader != null)
-                               xvReader.OnValidationEvent (this, e);
-                       else
-#if NON_MONO_ENV
-                               this.xvReader.OnValidationEvent (this, e);
-#else
+                       if (ValidationEventHandler != null)
+                               ValidationEventHandler (this, e);
+
+                       else if (e.Severity == XmlSeverityType.Error)
                                throw e.Exception;
-#endif
                }
 
-               private XmlSchemaElement FindElement (string name, string ns)
+               private XsElement FindElement (string name, string ns)
                {
-                       foreach (XmlSchema target in schemas) {
-                               XmlSchema matches = target.Schemas [reader.NamespaceURI];
-                               if (matches != null) {
-                                       XmlSchemaElement result = target.Elements [new XmlQualifiedName (reader.LocalName, reader.NamespaceURI)] as XmlSchemaElement;
-                                       if (result != null)
-                                               return result;
-                               }
-                       }
-                       return null;
+                       return (XsElement) schemas.GlobalElements [new QName (name, ns)];
                }
 
-               private XmlSchemaType FindType (XmlQualifiedName qname)
+               private XmlSchemaType FindType (QName qname)
                {
-                       foreach (XmlSchema target in schemas) {
-                               XmlSchemaType type = target.SchemaTypes [qname] as XmlSchemaType;
-                               if (type != null)
-                                       return type;
-                       }
-                       return null;
+                       return (XmlSchemaType) schemas.GlobalTypes [qname];
                }
 
                private void ValidateStartElementParticle ()
                {
-                       stateManager.CurrentElement = null;
-                       context.ParticleState = context.ParticleState.EvaluateStartElement (reader.LocalName, reader.NamespaceURI);
-                       if (context.ParticleState == 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 (childParticleState != null) {
-                               if (!childParticleState.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.
                private void ValidateCharacters ()
                {
-                       // TODO: value context validation here.
                        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 (shouldValidateCharacters)
+                               ValidateEndSimpleContentCore ();
+                       shouldValidateCharacters = false;
+                       storedCharacters.Length = 0;
+               }
+
+               private void ValidateEndSimpleContentCore ()
                {
-                       if (context.ActualType == null)
+                       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
-                               // TODO: check entire DefaultValid (3.3.6)
-                               if (context.Element != null && 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) {
-//                                     if (st.Variety == XmlSchemaDerivationMethod.Restriction)
                                        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;
                                        }
@@ -522,61 +590,45 @@ 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
-                       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;
-                               if (dt != null) {
-                                       try {
-                                               identity = dt.ParseValue (value, NameTable, ParserContext.NamespaceManager);
-                                       } catch (Exception ex) { // FIXME: This is bad manner ;-(
-                                               // FIXME: Such exception handling is not a good idea.
-                                               HandleError ("Identity value is invalid against its data type " + dt.TokenizedType, ex);
-                                       }
-                               }
-                               if (identity == null)
-                                       identity = value;
-                               
-                               if (!field.SetIdentityField (identity, 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;
-                                       foreach (string each in values) {
+                                       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)
                                                        continue;
                                                // validate against ValidatedItemType
                                                if (itemDatatype != null) {
                                                        try {
                                                                itemDatatype.ParseValue (each, NameTable, ParserContext.NamespaceManager);
-                                                       } catch (Exception ex) { // FIXME: better exception handling ;-(
+                                                       } catch (Exception ex) { // FIXME: (wishlist) better exception handling ;-(
                                                                HandleError ("List type value contains one or more invalid values.", ex);
                                                                break;
                                                        }
@@ -586,29 +638,25 @@ namespace Mono.Xml.Schema
                                        }
                                        break;
                                case XmlSchemaDerivationMethod.Union:
-                                       XmlSchemaSimpleTypeUnion union = st.Content as XmlSchemaSimpleTypeUnion;
-//                                     values = normalized.Split (wsChars);
-                               {
-string each = normalized;
-//                                     foreach (string each in values) {
-//                                             if (each == String.Empty)
-//                                                     continue;
+                                       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);
-                                                               } catch (Exception) { // FIXME: better exception handling ;-(
+                                                               } catch (Exception) { // FIXME: (wishlist) better exception handling ;-(
                                                                        continue;
                                                                }
                                                        }
                                                        else {
                                                                try {
                                                                        AssessStringValid (itemSimpleType, itemSimpleType.Datatype, each);
-                                                               } catch (XmlSchemaException) {
+                                                               } catch (ValException) {
                                                                        continue;
                                                                }
                                                        }
@@ -621,11 +669,19 @@ string each = normalized;
                                                }
                                        }
                                        break;
-                               // TODO: rest
                                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 
+                                                * Could we simplify this by assuming that the basetype will also
+                                                * be restriction?
+                                                * */
+                                                // mmm, will check later.
+                                               SimpleType baseType = st.BaseXmlSchemaType as SimpleType;
+                                               if (baseType != null) {
+                                                        AssessStringValid(baseType, dt, normalized);
+                                               }
                                                if (!str.ValidateValueWithFacets (normalized, NameTable)) {
                                                        HandleError ("Specified value was invalid against the facets.");
                                                        break;
@@ -638,22 +694,20 @@ string each = normalized;
                        if (validatedDatatype != null) {
                                try {
                                        validatedDatatype.ParseValue (value, NameTable, ParserContext.NamespaceManager);
-                               } catch (Exception ex) {        // FIXME: It is really bad design ;-P
+                               } catch (Exception ex) {        // FIXME: (wishlist) It is bad manner ;-(
                                        HandleError ("Invalidly typed data was specified.", ex);
                                }
                        }
                }
 
-               private object GetLocalTypeDefinition (string name)
+               private object GetXsiType (string name)
                {
                        object xsiType = null;
-                       XmlQualifiedName typeQName = QualifyName (name);
-                       if (typeQName.Namespace == XmlSchema.Namespace) {
-                               if (typeQName.Name == "anyType")
-                                       xsiType = XmlSchemaComplexType.AnyType;
-                               else
-                                       xsiType = XmlSchemaDatatype.FromName (typeQName);
-                       }
+                       QName typeQName = QName.Parse (name, this);
+                       if (typeQName == ComplexType.AnyTypeName)
+                               xsiType = ComplexType.AnyType;
+                       else if (XmlSchemaUtil.IsBuiltInDatatypeName (typeQName))
+                               xsiType = XsDatatype.FromName (typeQName);
                        else
                                xsiType = FindType (typeQName);
                        return xsiType;
@@ -663,8 +717,8 @@ string each = normalized;
                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)
@@ -681,21 +735,21 @@ string each = normalized;
                        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
@@ -706,23 +760,14 @@ string each = normalized;
                // 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 (childParticleState != null) {
-                               context.ParticleState = childParticleState;
-                               childParticleState = null;
-                       }
-
-                       // If validation state exists, then first assess particle validity.
-                       if (context.ParticleState != null) {
-                               ValidateStartElementParticle ();
-                       }
+                       ValidateStartElementParticle ();
 
-                       string xsiNilValue = GetAttribute ("nil", XmlSchema.InstanceNamespace);
+                       string xsiNilValue = reader.GetAttribute ("nil", XmlSchema.InstanceNamespace);
                        if (xsiNilValue != null)
                                xsiNilValue = xsiNilValue.Trim (XmlChar.WhitespaceChars);
                        bool isXsiNil = xsiNilValue == "true";
@@ -735,110 +780,117 @@ string each = normalized;
                        // Note that Schema Validity Assessment(Element) 1.2 takes
                        // precedence than 1.1 of that.
 
-                       // FIXME: xsi:type value should be normalized.
                        string xsiTypeName = reader.GetAttribute ("type", XmlSchema.InstanceNamespace);
                        if (xsiTypeName != null) {
-                               object xsiType = GetLocalTypeDefinition (xsiTypeName);
+                               xsiTypeName = xsiTypeName.Trim (XmlChar.WhitespaceChars);
+                               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) {
-                                                       // FIXME: supply *correct* base type
-                                                       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;
                                        }
                                }
                        }
 
                        // 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 {
-                               XmlSchema schema;
-                               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:
-                                       schema = schemas [reader.NamespaceURI];
-                                       if (xsiTypeName == null && (schema == null || !schema.missedSubComponents))
-                                               HandleError ("Element declaration for " + reader.LocalName + " is missing.");
+                                       if (xsiTypeName == null &&
+                                               (schemas.Contains (reader.NamespaceURI) ||
+                                               !schemas.MissedSubComponents (reader.NamespaceURI)))
+                                               HandleError ("Element declaration for " + new QName (reader.LocalName, reader.NamespaceURI) + " is missing.");
                                        break;
                                }
                        }
 
-                       if (stateManager.ProcessContents == XmlSchemaContentProcessing.Skip)
-                               skipValidationDepth = reader.Depth;
+                       state.PushContext ();
 
-                       // Finally, create child particle state.
-                       XmlSchemaComplexType xsComplexType = SchemaType as XmlSchemaComplexType;
-                       if (xsComplexType != null)
-                               childParticleState = stateManager.Create (xsComplexType.ContentTypeParticle);
-                       else if (stateManager.ProcessContents == XmlSchemaContentProcessing.Lax)
-                               childParticleState = stateManager.Create (XmlSchemaAny.AnyTypeContent);
-                       else
-                               childParticleState = stateManager.Create (XmlSchemaParticle.Empty);
+                       XsdValidationState next = null;
+                       if (state.ProcessContents == ContentProc.Skip)
+                               skipValidationDepth = reader.Depth;
+                       else {
+                               // create child particle state.
+                               ComplexType xsComplexType = SchemaType as ComplexType;
+                               if (xsComplexType != null)
+                                       next = state.Create (xsComplexType.ValidatableParticle);
+                               else if (state.ProcessContents == ContentProc.Lax)
+                                       next = state.Create (XmlSchemaAny.AnyTypeContent);
+                               else
+                                       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);
                        // 2.
-                       if (element.actualIsAbstract)
+                       if (element.ActualIsAbstract)
                                HandleError ("Abstract element declaration was specified for " + qname);
                        // 3.1.
-                       if (!element.actualIsNillable && xsiNilValue != null)
+                       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.XsiType = null;
 
                        // 5 Not all things cannot be assessed here.
                        // It is common to 5.1 and 5.2
@@ -858,8 +910,8 @@ string each = normalized;
                                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 ()) {
@@ -891,8 +943,7 @@ string each = normalized;
                }
 
                // 3.4.4 Element Locally Valid (Complex Type)
-               // TODO ("wild IDs constraints.")
-               private void AssessElementLocallyValidComplexType (XmlSchemaComplexType cType)
+               private void AssessElementLocallyValidComplexType (ComplexType cType)
                {
                        // 1.
                        if (cType.IsAbstract)
@@ -901,173 +952,85 @@ string each = normalized;
                        // 2 (xsi:nil and content prohibition)
                        // See AssessStartElementSchemaValidity() and ValidateCharacters()
 
-                       string elementNs = reader.NamespaceURI;
                        // 3. attribute uses and 
                        // 5. wild IDs
-                       while (reader.MoveToNextAttribute ()) {
-                               if (reader.NamespaceURI == "http://www.w3.org/2000/xmlns/")
-                                       continue;
-                               else if (reader.NamespaceURI == XmlSchema.InstanceNamespace)
-                                       continue;
-                               XmlQualifiedName qname = new XmlQualifiedName (reader.LocalName, reader.NamespaceURI);
-                               object attMatch = FindAttributeDeclaration (cType, qname, elementNs);
-                               if (attMatch == null)
-                                       HandleError ("Attribute declaration was not found for " + qname);
-                               else {
-                                       XmlSchemaAttribute attdecl = attMatch as XmlSchemaAttribute;
-                                       if (attdecl == null) { // i.e. anyAttribute
-                                               XmlSchemaAnyAttribute anyAttrMatch = attMatch as XmlSchemaAnyAttribute;
-                                       } else {
-                                               AssessAttributeLocallyValidUse (attdecl);
-                                               AssessAttributeLocallyValid (attdecl, true);
+                       if (reader.MoveToFirstAttribute ()) {
+                               do {
+                                       switch (reader.NamespaceURI) {
+                                       case"http://www.w3.org/2000/xmlns/":
+                                       case XmlSchema.InstanceNamespace:
+                                               continue;
                                        }
-                               }
+                                       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);
+                                       XsAttribute attdecl = attMatch as XsAttribute;
+                                       if (attdecl != null) {
+                                               AssessAttributeLocallyValidUse (attdecl);
+                                               AssessAttributeLocallyValid (attdecl);
+                                       } // otherwise anyAttribute or null.
+                               } while (reader.MoveToNextAttribute ());
+                               reader.MoveToElement ();
                        }
-                       reader.MoveToElement ();
 
                        // Collect default attributes.
                        // 4.
-                       // FIXME: FixedValue check maybe extraneous.
-                       foreach (XmlSchemaAttribute attr in cType.AttributeUses) {
+                       foreach (DictionaryEntry entry in cType.AttributeUses) {
+                               XsAttribute attr = (XsAttribute) entry.Value;
                                if (reader [attr.QualifiedName.Name, attr.QualifiedName.Namespace] == null) {
                                        if (attr.ValidatedUse == XmlSchemaUse.Required && 
                                                attr.ValidatedFixedValue == null)
                                                HandleError ("Required attribute " + attr.QualifiedName + " was not found.");
-                                       else if (attr.ValidatedDefaultValue != null)
+                                       else if (attr.ValidatedDefaultValue != null || attr.ValidatedFixedValue != null)
                                                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 bool AttributeWildcardItemValid (XmlSchemaAnyAttribute anyAttr, XmlQualifiedName qname)
-               {
-                       if (anyAttr.HasValueAny)
-                               return true;
-                       if (anyAttr.HasValueOther && (anyAttr.TargetNamespace == "" || reader.NamespaceURI != anyAttr.TargetNamespace))
-                               return true;
-                       if (anyAttr.HasValueTargetNamespace && reader.NamespaceURI == anyAttr.TargetNamespace)
-                               return true;
-                       if (anyAttr.HasValueLocal && reader.NamespaceURI == "")
-                               return true;
-                       foreach (string ns in anyAttr.ResolvedNamespaces)
-                               if (ns == reader.NamespaceURI)
-                                       return true;
-                       return false;
-               }
-
-               private XmlSchemaObject FindAttributeDeclaration (XmlSchemaComplexType cType,
-                       XmlQualifiedName qname, string elementNs)
-               {
-                       XmlSchemaObject result = cType.AttributeUses [qname];
-                       if (result != null)
-                               return result;
-                       if (cType.AttributeWildcard == null)
-                               return null;
-
-                       if (!AttributeWildcardItemValid (cType.AttributeWildcard, qname))
-                               return null;
-
-                       if (cType.AttributeWildcard.ProcessContents == XmlSchemaContentProcessing.Skip)
-                               return cType.AttributeWildcard;
-                       foreach (XmlSchema schema in schemas) {
-                               foreach (XmlSchemaAttribute attr in schema.Attributes)
-                                       if (attr.QualifiedName == qname)
-                                               return attr;
-                       }
-                       if (cType.AttributeWildcard.ProcessContents == XmlSchemaContentProcessing.Lax)
-                               return cType.AttributeWildcard;
-                       else
-                               return null;
-               }
-
-               // 3.2.4 Attribute Locally Valid and 3.4.4 - 5.wildIDs
-               // TODO
-               private void AssessAttributeLocallyValid (XmlSchemaAttribute attr, bool checkWildIDs)
+               // 3.2.4 Attribute Locally Valid and 3.4.4
+               private void AssessAttributeLocallyValid (XsAttribute attr)
                {
-                       // 1.
-                       switch (reader.NamespaceURI) {
-                       case XmlNamespaceManager.XmlnsXml:
-                       case XmlNamespaceManager.XmlnsXmlns:
-                       case XmlSchema.InstanceNamespace:
-                               break;
-                       }
-                       // TODO 2. - 4.
+                       // 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 {
-                                       dt.ParseValue (normalized, reader.NameTable, this.ParserContext.NamespaceManager);
-                               } catch (Exception ex) {
-                                       // FIXME: Such exception handling is not a good idea.
+                                       parsedValue = dt.ParseValue (normalized, reader.NameTable, this.ParserContext.NamespaceManager);
+                               } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
                                        HandleError ("Attribute value is invalid against its data type " + dt.TokenizedType, ex);
                                }
-                               if (attr.ValidatedFixedValue != null && attr.ValidatedFixedValue != normalized)
+                               if (attr.ValidatedFixedValue != null && attr.ValidatedFixedValue != normalized) {
                                        HandleError ("The value of the attribute " + attr.QualifiedName + " does not match with its fixed value.");
-                               // FIXME: this is extraneous checks in 3.2.4 Attribute Locally Valid.
-                               if (checkWildIDs)
-                                       AssessEachAttributeIdentityConstraint (dt, normalized, parsedValue);
-                       }
-               }
-
-               private void AssessEachAttributeIdentityConstraint (XmlSchemaDatatype dt,
-                       string normalized, object parsedValue)
-               {
-                       // Get normalized value and (if required) parsedValue if missing.
-                       switch (dt.TokenizedType) {
-                       case XmlTokenizedType.IDREFS:
-                               if (normalized == null)
-                                       normalized = dt.Normalize (reader.Value);
-                               if (parsedValue == null)
-                                       parsedValue = dt.ParseValue (normalized, reader.NameTable, ParserContext.NamespaceManager);
-                               break;
-                       case XmlTokenizedType.ID:
-                       case XmlTokenizedType.IDREF:
-                               if (normalized == null)
-                                       normalized = dt.Normalize (reader.Value);
-                               break;
-                       }
-
-                       // Validate identity constraints.
-                       switch (dt.TokenizedType) {
-                       case XmlTokenizedType.ID:
-                               if (thisElementId != null)
-                                       HandleError ("ID type attribute was already assigned in the containing element.");
-                               thisElementId = normalized;
-                               idList.Add (normalized);
-                               break;
-                       case XmlTokenizedType.IDREF:
-                               if (missingIDReferences.Contains (normalized))
-                                       missingIDReferences.Remove (normalized);
-                               else
-                                       missingIDReferences.Add (normalized);
-                               break;
-                       case XmlTokenizedType.IDREFS:
-                               foreach (string id in (string []) parsedValue) {
-                                       if (missingIDReferences.Contains (id))
-                                               missingIDReferences.Remove (id);
-                                       else
-                                               missingIDReferences.Add (id);
+                                       parsedValue = dt.ParseValue (attr.ValidatedFixedValue, reader.NameTable, this.ParserContext.NamespaceManager);
                                }
-                               break;
+#region ID Constraints
+                               if (this.checkIdentity) {
+                                       string error = idManager.AssessEachAttributeIdentityConstraint (dt, parsedValue, ((QName) elementQNameStack [elementQNameStack.Count - 1]).Name);
+                                       if (error != null)
+                                               HandleError (error);
+                               }
+#endregion
                        }
                }
 
-               // TODO
-               private void AssessAttributeLocallyValidUse (XmlSchemaAttribute attr)
+               private void AssessAttributeLocallyValidUse (XsAttribute attr)
                {
-                       // TODO: value constraint check
                        // This is extra check than spec 3.5.4
                        if (attr.ValidatedUse == XmlSchemaUse.Prohibited)
                                HandleError ("Attribute " + attr.QualifiedName + " is prohibited in this context.");
@@ -1075,36 +1038,48 @@ string each = normalized;
 
                private void AssessEndElementSchemaValidity ()
                {
-                       if (childParticleState == null)
-                               childParticleState = context.ParticleState;
                        ValidateEndElementParticle ();  // validate against childrens' state.
 
-                       context.Load (reader.Depth);
+                       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.
                                                else {
-                                                       foreach (XsdKeyEntryField kf in entry.KeyFields) {
+                                                       for (int j = 0; j < entry.KeyFields.Count; j++) {
+                                                               XsdKeyEntryField kf = entry.KeyFields [j];
                                                                if (!kf.FieldFound && kf.FieldFoundDepth == reader.Depth) {
                                                                        kf.FieldFoundDepth = 0;
                                                                        kf.FieldFoundPath = null;
@@ -1115,111 +1090,171 @@ string each = normalized;
                                }
                        }
                        for (int i = 0; i < keyTables.Count; i++) {
-                               XsdKeyTable keyseq = this.keyTables [i] as XsdKeyTable;
-                               if (keyseq.StartDepth == reader.Depth) {
-//Console.WriteLine ("Finishing table.");
+                               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
-               // TODO
-               private void AssessStartIdentityConstraints ()
+               private void ValidateKeySelectors ()
                {
-                       tmpKeyrefPool.Clear ();
-                       if (context.Element != null && context.Element.Constraints.Count > 0) {
+                       if (tmpKeyrefPool != null)
+                               tmpKeyrefPool.Clear ();
+                       if (Context.Element != null && Context.Element.Constraints.Count > 0) {
                                // (a) Create new key sequences, if required.
-                               foreach (XmlSchemaIdentityConstraint ident in context.Element.Constraints) {
+                               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 (ident is XmlSchemaKeyref) {
+                                               if (tmpKeyrefPool == null)
+                                                       tmpKeyrefPool = new ArrayList ();
                                                tmpKeyrefPool.Add (seq);
+                                       }
                                }
                        }
 
                        // (b) Evaluate current key sequences.
-                       foreach (XsdKeyTable seq in this.keyTables) {
-                               if (seq.SelectorMatches (this.elementQNameStack, reader) != null) {
+                       for (int i = 0; i < keyTables.Count; i++) {
+                               XsdKeyTable seq  = (XsdKeyTable) keyTables [i];
+                               if (seq.SelectorMatches (this.elementQNameStack, reader.Depth) != null) {
                                        // creates and registers new entry.
-                                       XsdKeyEntry entry = new XsdKeyEntry (seq, reader);
-                                       seq./*NotFound*/Entries.Add (entry);
+                                       XsdKeyEntry entry = new XsdKeyEntry (seq, reader.Depth, readerLineInfo);
+                                       seq.Entries.Add (entry);
                                }
                        }
+               }
 
+               private void ValidateKeyFields ()
+               {
                        // (c) Evaluate field paths.
-                       foreach (XsdKeyTable seq in this.keyTables) {
+                       for (int i = 0; i < keyTables.Count; i++) {
+                               XsdKeyTable seq  = (XsdKeyTable) keyTables [i];
                                // If possible, create new field entry candidates.
-                               for (int i = 0; i < seq./*NotFound*/Entries.Count; i++) {
-                                       XsdKeyEntry entry = seq./*NotFound*/Entries [i] as XsdKeyEntry;
-//                                     if (entry.KeyFound)
-// FIXME: it should not be skipped for multiple key check!!
-//                                             continue;
+                               for (int j = 0; j < seq.Entries.Count; j++) {
                                        try {
-                                               entry.FieldMatches (this.elementQNameStack, this);
-                                       } catch (Exception ex) {
-                                               // FIXME: Such exception handling is not a good idea.
-                                               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;
-                       XmlSchemaKeyref keyref = ident as XmlSchemaKeyref;
                        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 ();
-                       foreach (XsdKeyEntry entry in seq./*NotFound*/Entries) {
+                       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;
-                                               foreach (XsdKeyEntry entry in seq.FinishedEntries) {
-                                                       foreach (XsdKeyEntry targetEntry in target.FinishedEntries) {
-                                                               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.");
-                               foreach (XsdKeyEntry entry in seq.FinishedEntries) {
-                                       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
 
@@ -1238,7 +1273,7 @@ string each = normalized;
 
                        if (reader.AttributeCount > i)
                                reader.GetAttribute (i);
-                       int defIdx = i - nonDefaultAttributeCount;
+                       int defIdx = i - reader.AttributeCount;
                        if (i < AttributeCount)
                                return defaultAttributes [defIdx].DefaultValue;
 
@@ -1257,19 +1292,19 @@ string each = normalized;
                        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;
                }
@@ -1292,24 +1327,26 @@ string each = normalized;
                private string GetDefaultAttribute (string localName, string ns)
                {
                        int idx = this.FindDefaultAttribute (localName, ns);
-                       if (idx >= 0)
-                               return defaultAttributes [idx].ValidatedDefaultValue;
-                       else
+                       if (idx < 0)
                                return null;
+                       string value = defaultAttributes [idx].ValidatedDefaultValue;
+                       if (value == null)
+                               value = defaultAttributes [idx].ValidatedFixedValue;
+                       return value;
                }
 
                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 &&
-                                       attr.QualifiedName.Namespace == ns)
+                                       (ns == null || attr.QualifiedName.Namespace == ns))
                                        return i;
                        }
                        return -1;
                }
 
-               bool IXmlLineInfo.HasLineInfo ()
+               public bool HasLineInfo ()
                {
                        return readerLineInfo != null && readerLineInfo.HasLineInfo ();
                }
@@ -1319,6 +1356,15 @@ string each = normalized;
                        return reader.LookupNamespace (prefix);
                }
 
+               string IXmlNamespaceResolver.LookupNamespace (string prefix, bool atomizedNames)
+               {
+                       IXmlNamespaceResolver res = reader as IXmlNamespaceResolver;
+                       if (res != null)
+                               return res.LookupNamespace (prefix, atomizedNames);
+                       else
+                               return reader.LookupNamespace (prefix);
+               }
+
                public override void MoveToAttribute (int i)
                {
                        switch (reader.NodeType) {
@@ -1328,15 +1374,15 @@ string each = normalized;
                                return;
                        }
 
-                       currentQName = null;
-                       if (i < this.nonDefaultAttributeCount) {
+                       currentAttrType = null;
+                       if (i < reader.AttributeCount) {
                                reader.MoveToAttribute (i);
                                this.currentDefaultAttribute = -1;
                                this.defaultAttributeConsumed = false;
                        }
 
                        if (i < AttributeCount) {
-                               this.currentDefaultAttribute = i - nonDefaultAttributeCount;
+                               this.currentDefaultAttribute = i - reader.AttributeCount;
                                this.defaultAttributeConsumed = false;
                        }
                        else
@@ -1351,7 +1397,7 @@ string each = normalized;
                                return reader.MoveToAttribute (name);
                        }
 
-                       currentQName = null;
+                       currentAttrType = null;
                        bool b = reader.MoveToAttribute (name);
                        if (b) {
                                this.currentDefaultAttribute = -1;
@@ -1359,8 +1405,7 @@ string each = normalized;
                                return true;
                        }
 
-                       XmlQualifiedName qname = SplitQName (name);
-                       return MoveToDefaultAttribute (qname.Name, qname.Namespace);
+                       return MoveToDefaultAttribute (name, null);
                }
 
                public override bool MoveToAttribute (string localName, string ns)
@@ -1371,7 +1416,7 @@ string each = normalized;
                                return reader.MoveToAttribute (localName, ns);
                        }
 
-                       currentQName = null;
+                       currentAttrType = null;
                        bool b = reader.MoveToAttribute (localName, ns);
                        if (b) {
                                this.currentDefaultAttribute = -1;
@@ -1396,7 +1441,7 @@ string each = normalized;
                {
                        currentDefaultAttribute = -1;
                        defaultAttributeConsumed = false;
-                       currentQName = null;
+                       currentAttrType = null;
                        return reader.MoveToElement ();
                }
 
@@ -1408,8 +1453,8 @@ string each = normalized;
                                return reader.MoveToFirstAttribute ();
                        }
 
-                       currentQName = null;
-                       if (this.nonDefaultAttributeCount > 0) {
+                       currentAttrType = null;
+                       if (reader.AttributeCount > 0) {
                                bool b = reader.MoveToFirstAttribute ();
                                if (b) {
                                        currentDefaultAttribute = -1;
@@ -1435,7 +1480,7 @@ string each = normalized;
                                return reader.MoveToNextAttribute ();
                        }
 
-                       currentQName = null;
+                       currentAttrType = null;
                        if (currentDefaultAttribute >= 0) {
                                if (defaultAttributes.Length == currentDefaultAttribute + 1)
                                        return false;
@@ -1460,22 +1505,47 @@ string each = normalized;
                                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 = XmlSchemaDatatype.FromName ("NMTOKENS").ParseValue (schemaLocation, NameTable, null) as string [];
+                               string [] tmp = null;
+                               try {
+                                       schemaLocation = XsDatatype.FromName ("token", XmlSchema.Namespace).Normalize (schemaLocation);
+                                       tmp = schemaLocation.Split (XmlChar.WhitespaceChars);
+                               } catch (Exception ex) {
+                                       HandleError ("Invalid schemaLocation attribute format.", ex, true);
+                                       tmp = new string [0];
+                               }
                                if (tmp.Length % 2 != 0)
                                        HandleError ("Invalid schemaLocation attribute format.");
                                for (int i = 0; i < tmp.Length; i += 2) {
                                        try {
-                                               Uri absUri = new Uri ((this.BaseURI != "" ? new Uri (BaseURI) : null), tmp [i + 1]);
-                                               XmlTextReader xtr = new XmlTextReader (absUri.ToString ());
-                                               schema = XmlSchema.Read (xtr, null);
-                                       } catch (Exception ex) {
-                                               // FIXME: better exception handling...
-//                                             HandleError ("Errors were occured when resolving schemaLocation specified schema document.", ex);
+                                               schema = ReadExternalSchema (tmp [i + 1]);
+                                       } catch (Exception) { // FIXME: (wishlist) It is bad manner ;-(
+                                               HandleError ("Could not resolve schema location URI: " + tmp [i + 1], null, true);
                                                continue;
                                        }
                                        if (schema.TargetNamespace == null)
@@ -1485,78 +1555,73 @@ string each = normalized;
                                }
                        }
                        if (schema != null) {
-                               try {
+                               if (!schemas.Contains (schema.TargetNamespace)) {
+                                       schemaAdded = true;
                                        schemas.Add (schema);
-                               } catch (XmlSchemaException ex) {
-                                       HandleError (ex);
                                }
                        }
                        schema = null;
                        string noNsSchemaLocation = reader.GetAttribute ("noNamespaceSchemaLocation", XmlSchema.InstanceNamespace);
                        if (noNsSchemaLocation != null) {
                                try {
-                                       Uri absUri = new Uri ((this.BaseURI != "" ? new Uri (BaseURI) : null), noNsSchemaLocation);
-                                       XmlTextReader xtr = new XmlTextReader (absUri.ToString ());
-                                       schema = XmlSchema.Read (xtr, null);
-                               } catch (Exception ex) {
-                                       // FIXME: better exception handling...
-//                                     HandleError ("Errors were occured when resolving schemaLocation specified schema document.", ex);
+                                       schema = ReadExternalSchema (noNsSchemaLocation);
+                               } catch (Exception) { // FIXME: (wishlist) It is bad manner ;-(
+                                       HandleError ("Could not resolve schema location URI: " + noNsSchemaLocation, null, true);
                                }
                                if (schema != null && schema.TargetNamespace != null)
                                        HandleError ("Specified schema has different target namespace.");
                        }
                        if (schema != null) {
-                               try {
+                               if (!schemas.Contains (schema.TargetNamespace)) {
+                                       schemaAdded = true;
                                        schemas.Add (schema);
-                               } catch (XmlSchemaException ex) {
-                                       HandleError (ex);
                                }
                        }
+                       // FIXME: should call Reprocess()?
+                       if (schemaAdded)
+                               schemas.Compile ();
                }
 
                public override bool Read ()
                {
-                       nonDefaultAttributeCount = 0;
                        currentDefaultAttribute = -1;
                        defaultAttributeConsumed = false;
-                       currentQName = null;
-                       thisElementId = null;
-                       defaultAttributes = new XmlSchemaAttribute [0];
-                       if (popContext) {
-                               elementQNameStack.RemoveAt (elementQNameStack.Count - 1);
-                               popContext = false;
-                       }
+                       currentAttrType = null;
+#region ID Constraints
+                       if (this.checkIdentity)
+                               idManager.OnStartElement ();
+#endregion
+                       defaultAttributes = emptyAttributeArray;
 
                        bool result = reader.Read ();
+#region ID Constraints
                        // 3.3.4 ElementLocallyValidElement 7 = Root Valid.
-                       if (!result && missingIDReferences.Count > 0)
-                               HandleError ("There are missing ID references: " +
-                                       String.Join (" ",
-                                       this.missingIDReferences.ToArray (typeof (string)) as string []));
+                       if (!result && this.checkIdentity &&
+                               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:
-                               nonDefaultAttributeCount = reader.AttributeCount;
-
-                               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;
-
-//                             context.Load (reader.Depth);
                                if (skipValidationDepth < 0 || reader.Depth <= skipValidationDepth) {
-                                       if (shouldValidateCharacters) {
-                                               ValidateEndCharacters ();
-                                               shouldValidateCharacters = false;
-                                       }
+                                       ValidateEndSimpleContent ();
                                        AssessStartElementSchemaValidity ();
-                                       storedCharacters.Length = 0;
-                               } else {
-                                       context.Clear ();
                                }
 
                                if (reader.IsEmptyElement)
@@ -1565,26 +1630,20 @@ string each = normalized;
                                        shouldValidateCharacters = true;
                                break;
                        case XmlNodeType.EndElement:
-                               if (reader.Depth == skipValidationDepth) {
+                               if (reader.Depth == skipValidationDepth)
                                        skipValidationDepth = -1;
-                                       context.Clear ();
-                               } else {
-//                                     context.Load (reader.Depth);
-                                       if (shouldValidateCharacters) {
-                                               ValidateEndCharacters ();
-                                               shouldValidateCharacters = false;
-                                       }
+                               else if (skipValidationDepth < 0 || reader.Depth <= skipValidationDepth)
                                        AssessEndElementSchemaValidity ();
-                               }
-                               storedCharacters.Length = 0;
-                               childParticleState = 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:
@@ -1642,84 +1701,144 @@ string each = normalized;
                {
                        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;
 
-                       public XsdValidationContext ()
-                       {
-                               contextStack = new Hashtable ();
+               // Note that it represents current element's type.
+               public object ActualType {
+                       get {
+                               if (XsiType != null)
+                                       return XsiType;
+                               else
+                                       return Element != null ? Element.ElementType : null;
                        }
+               }
 
-                       // Some of them might be missing (See the spec section 5.3, and also 3.3.4).
-                       public XmlSchemaElement Element;
-                       public XsdValidationState ParticleState;
-                       public XmlSchemaAttribute [] DefaultAttributes;
+#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).
-                       public object SchemaType;
+               public bool IsInvalid {
+                       get { return State == XsdValidationState.Invalid; }
+               }
 
-                       public object LocalTypeDefinition;
+               public object Clone ()
+               {
+                       return MemberwiseClone ();
+               }
 
-                       public object ActualType {
-                               get {
-                                       if (LocalTypeDefinition != null)
-                                               return LocalTypeDefinition;
-                                       else
-                                               return SchemaType;
-                               }
-                       }
+               public void EvaluateStartElement (
+                       string localName, string ns)
+               {
+                       State = State.EvaluateStartElement (localName, ns);
+               }
 
-                       public void Clear ()
-                       {
-                               Element = null;
-                               SchemaType = null;
-                               ParticleState = null;
-                               LocalTypeDefinition = null;
-                       }
+               public bool EvaluateEndElement ()
+               {
+                       return State.EvaluateEndElement ();
+               }
 
-                       public void PushScope (int depth)
-                       {
-                               contextStack [depth] = this.MemberwiseClone ();
-                       }
+               public void SetElement (XsElement element)
+               {
+                       Element = element;
+               }
+       }
 
-                       public void PopScope (int depth)
-                       {
-                               Load (depth);
-                               contextStack.Remove (depth + 1);
+       internal class XsdIDManager
+       {
+               public XsdIDManager ()
+               {
+               }
+
+               Hashtable idList = new Hashtable ();
+               ArrayList missingIDReferences;
+               string thisElementId;
+
+               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.ParticleState = restored.ParticleState;
-                                       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;
                }
 
-               /*
-               internal class XsdValidityState
+               public object FindID (string name)
                {
-                       ArrayList currentParticles = new ArrayList ();
-                       ArrayList occured = new ArrayList ();
-                       Hashtable xsAllConsumed = new Hashtable ();
-                       XmlSchemaParticle parciele;
-                       int particleDepth;
+                       return idList [name];
+               }
 
-                       public XsdValidityState (XmlSchemaParticle particle)
-                       {
-                               this.parciele = particle;
-                               currentParticles.Add (particle);
-                       }
+               public bool HasMissingIDReferences ()
+               {
+                       return missingIDReferences != null
+                               && missingIDReferences.Count > 0;
+               }
 
+               public string GetMissingIDString ()
+               {
+                       return String.Join (" ",
+                               MissingIDReferences.ToArray (typeof (string))
+                                       as string []);
                }
-               */
        }
-
 }