In .:
[mono.git] / mcs / class / System.XML / Mono.Xml.Schema / XsdValidatingReader.cs
1 //
2 // Mono.Xml.Schema.XsdValidatingReader.cs
3 //
4 // Author:
5 //      Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
6 //
7 //      (C)2003 Atsushi Enomoto
8 //
9
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30 using System;
31 using System.Collections;
32 #if NET_2_0
33 using System.Collections.Generic;
34 #endif
35 using System.Collections.Specialized;
36 using System.IO;
37 using System.Text;
38 using System.Xml;
39 using System.Xml.Schema;
40 using Mono.Xml;
41
42 #if NET_2_0
43 using ValException = System.Xml.Schema.XmlSchemaValidationException;
44 #else
45 using ValException = System.Xml.Schema.XmlSchemaException;
46 #endif
47
48 using QName = System.Xml.XmlQualifiedName;
49 using ContentProc = System.Xml.Schema.XmlSchemaContentProcessing;
50 using XsElement = System.Xml.Schema.XmlSchemaElement;
51 using XsAttribute = System.Xml.Schema.XmlSchemaAttribute;
52 using ComplexType = System.Xml.Schema.XmlSchemaComplexType;
53 using SimpleType = System.Xml.Schema.XmlSchemaSimpleType;
54 using SimpleTypeRest = System.Xml.Schema.XmlSchemaSimpleTypeRestriction;
55 using SimpleTypeList = System.Xml.Schema.XmlSchemaSimpleTypeList;
56 using SimpleTypeUnion = System.Xml.Schema.XmlSchemaSimpleTypeUnion;
57 using XsDatatype = System.Xml.Schema.XmlSchemaDatatype;
58
59 namespace Mono.Xml.Schema
60 {
61         internal class XsdValidatingReader : XmlReader, IXmlLineInfo, IHasXmlSchemaInfo, IHasXmlParserContext
62         {
63                 static readonly XsAttribute [] emptyAttributeArray =
64                         new XsAttribute [0];
65
66                 XmlReader reader;
67                 XmlResolver resolver;
68                 IHasXmlSchemaInfo sourceReaderSchemaInfo;
69                 IXmlLineInfo readerLineInfo;
70                 ValidationType validationType;
71                 XmlSchemaSet schemas = new XmlSchemaSet ();
72                 bool namespaces = true;
73                 bool validationStarted;
74
75 #region ID Constraints
76                 bool checkIdentity = true;
77                 XsdIDManager idManager = new XsdIDManager ();
78 #endregion
79
80 #region Key Constraints
81                 bool checkKeyConstraints = true;
82                 ArrayList keyTables = new ArrayList ();
83                 ArrayList currentKeyFieldConsumers;
84                 ArrayList tmpKeyrefPool;
85 #endregion
86                 ArrayList elementQNameStack = new ArrayList ();
87
88                 XsdParticleStateManager state = new XsdParticleStateManager ();
89
90                 int skipValidationDepth = -1;
91                 int xsiNilDepth = -1;
92                 StringBuilder storedCharacters = new StringBuilder ();
93                 bool shouldValidateCharacters;
94
95                 XsAttribute [] defaultAttributes = emptyAttributeArray;
96                 int currentDefaultAttribute = -1;
97                 ArrayList defaultAttributesCache = new ArrayList ();
98                 bool defaultAttributeConsumed;
99                 object currentAttrType;
100
101 #region .ctor
102                 public XsdValidatingReader (XmlReader reader)
103                 {
104                         this.reader = reader;
105                         readerLineInfo = reader as IXmlLineInfo;
106                         sourceReaderSchemaInfo = reader as IHasXmlSchemaInfo;
107                         schemas.ValidationEventHandler += ValidationEventHandler;
108                 }
109 #endregion
110
111                 public ValidationEventHandler ValidationEventHandler;
112
113                 // Private Properties
114
115                 private XsdValidationContext Context {
116                         get { return state.Context; }
117                 }
118
119 #region Key Constraints
120                 internal ArrayList CurrentKeyFieldConsumers {
121                         get {
122                                 if (currentKeyFieldConsumers == null)
123                                         currentKeyFieldConsumers = new ArrayList ();
124                                 return currentKeyFieldConsumers;
125                         }
126                 }
127 #endregion
128
129                 // Public Non-overrides
130
131                 public int XsiNilDepth {
132                         get { return xsiNilDepth; }
133                 }
134
135                 public bool Namespaces {
136                         get { return namespaces; }
137                         set { namespaces = value; }
138                 }
139
140                 // This is required to resolve xsi:schemaLocation
141                 public XmlResolver XmlResolver {
142                         set {
143                                 resolver = value;
144                         }
145                 }
146
147                 // This should be changed before the first Read() call.
148                 public XmlSchemaSet Schemas {
149                         get { return schemas; }
150                         set {
151                                 if (validationStarted)
152                                         throw new InvalidOperationException ("Schemas must be set before the first call to Read().");
153                                 schemas = value;
154                         }
155                 }
156
157                 public object SchemaType {
158                         get {
159                                 if (ReadState != ReadState.Interactive)
160                                         return null;
161
162                                 switch (NodeType) {
163                                 case XmlNodeType.Element:
164                                         if (Context.ActualType != null)
165                                                 return Context.ActualType;
166                                         else
167                                                 return SourceReaderSchemaType;
168                                 case XmlNodeType.Attribute:
169                                         if (currentAttrType == null) {
170                                                 ComplexType ct = Context.ActualType as ComplexType;
171                                                 if (ct != null) {
172                                                         XsAttribute attdef = ct.AttributeUses [new QName (LocalName, NamespaceURI)] as XsAttribute;
173                                                         if (attdef != null)
174                                                                 currentAttrType = attdef.AttributeType;
175                                                         return currentAttrType;
176                                                 }
177                                                 currentAttrType = SourceReaderSchemaType;
178                                         }
179                                         return currentAttrType;
180                                 default:
181                                         return SourceReaderSchemaType;
182                                 }
183                         }
184                 }
185
186                 private object SourceReaderSchemaType {
187                         get { return this.sourceReaderSchemaInfo != null ? sourceReaderSchemaInfo.SchemaType : null; }
188                 }
189
190                 public ValidationType ValidationType {
191                         get { return validationType; }
192                         set {
193                                 if (validationStarted)
194                                         throw new InvalidOperationException ("ValidationType must be set before reading.");
195                                 validationType = value;
196                         }
197                 }
198
199                 // It is used only for independent XmlReader use, not for XmlValidatingReader.
200                 public object ReadTypedValue ()
201                 {
202                         object o = XmlSchemaUtil.ReadTypedValue (this,
203                                 SchemaType, NamespaceManager,
204                                 storedCharacters);
205                         storedCharacters.Length = 0;
206                         return o;
207                 }
208                 
209                 // Public Overriden Properties
210
211                 public override int AttributeCount {
212                         get {
213                                 return reader.AttributeCount + defaultAttributes.Length;
214                         }
215                 }
216
217                 public override string BaseURI {
218                         get { return reader.BaseURI; }
219                 }
220
221                 // If this class is used to implement XmlValidatingReader,
222                 // it should be left to DTDValidatingReader. In other cases,
223                 // it depends on the reader's ability.
224                 public override bool CanResolveEntity {
225                         get { return reader.CanResolveEntity; }
226                 }
227
228                 public override int Depth {
229                         get {
230                                 if (currentDefaultAttribute < 0)
231                                         return reader.Depth;
232                                 if (this.defaultAttributeConsumed)
233                                         return reader.Depth + 2;
234                                 return reader.Depth + 1;
235                         }
236                 }
237
238                 public override bool EOF {
239                         get { return reader.EOF; }
240                 }
241
242                 public override bool HasValue {
243                         get {
244                                 if (currentDefaultAttribute < 0)
245                                         return reader.HasValue;
246                                 return true;
247                         }
248                 }
249
250                 public override bool IsDefault {
251                         get {
252                                 if (currentDefaultAttribute < 0)
253                                         return reader.IsDefault;
254                                 return true;
255                         }
256                 }
257
258                 public override bool IsEmptyElement {
259                         get {
260                                 if (currentDefaultAttribute < 0)
261                                         return reader.IsEmptyElement;
262                                 return false;
263                         }
264                 }
265
266                 public override string this [int i] {
267                         get { return GetAttribute (i); }
268                 }
269
270                 public override string this [string name] {
271                         get { return GetAttribute (name); }
272                 }
273
274                 public override string this [string localName, string ns] {
275                         get { return GetAttribute (localName, ns); }
276                 }
277
278                 public int LineNumber {
279                         get { return readerLineInfo != null ? readerLineInfo.LineNumber : 0; }
280                 }
281
282                 public int LinePosition {
283                         get { return readerLineInfo != null ? readerLineInfo.LinePosition : 0; }
284                 }
285
286                 public override string LocalName {
287                         get {
288                                 if (currentDefaultAttribute < 0)
289                                         return reader.LocalName;
290                                 if (defaultAttributeConsumed)
291                                         return String.Empty;
292                                 return defaultAttributes [currentDefaultAttribute].QualifiedName.Name;
293                         }
294                 }
295
296                 public override string Name {
297                         get {
298                                 if (currentDefaultAttribute < 0)
299                                         return reader.Name;
300                                 if (defaultAttributeConsumed)
301                                         return String.Empty;
302
303                                 QName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
304                                 string prefix = Prefix;
305                                 if (prefix == String.Empty)
306                                         return qname.Name;
307                                 else
308                                         return String.Concat (prefix, ":", qname.Name);
309                         }
310                 }
311
312                 public override string NamespaceURI {
313                         get {
314                                 if (currentDefaultAttribute < 0)
315                                         return reader.NamespaceURI;
316                                 if (defaultAttributeConsumed)
317                                         return String.Empty;
318                                 return defaultAttributes [currentDefaultAttribute].QualifiedName.Namespace;
319                         }
320                 }
321
322                 public override XmlNameTable NameTable {
323                         get { return reader.NameTable; }
324                 }
325
326                 public override XmlNodeType NodeType {
327                         get {
328                                 if (currentDefaultAttribute < 0)
329                                         return reader.NodeType;
330                                 if (defaultAttributeConsumed)
331                                         return XmlNodeType.Text;
332                                 return XmlNodeType.Attribute;
333                         }
334                 }
335
336                 public XmlParserContext ParserContext {
337                         get { return XmlSchemaUtil.GetParserContext (reader); }
338                 }
339
340                 internal XmlNamespaceManager NamespaceManager {
341                         get { return ParserContext != null ? ParserContext.NamespaceManager : null; }
342                 }
343
344                 public override string Prefix {
345                         get {
346                                 if (currentDefaultAttribute < 0)
347                                         return reader.Prefix;
348                                 if (defaultAttributeConsumed)
349                                         return String.Empty;
350                                 QName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
351                                 string prefix = NamespaceManager != null ? NamespaceManager.LookupPrefix (qname.Namespace, false) : null;
352                                 if (prefix == null)
353                                         return String.Empty;
354                                 else
355                                         return prefix;
356                         }
357                 }
358
359                 public override char QuoteChar {
360                         get { return reader.QuoteChar; }
361                 }
362
363                 public override ReadState ReadState {
364                         get { return reader.ReadState; }
365                 }
366
367                 public override string Value {
368                         get {
369                                 if (currentDefaultAttribute < 0)
370                                         return reader.Value;
371                                 string value = defaultAttributes [currentDefaultAttribute].ValidatedDefaultValue;
372                                 if (value == null)
373                                         value = defaultAttributes [currentDefaultAttribute].ValidatedFixedValue;
374                                 return value;
375                         }
376                 }
377
378                 public override string XmlLang {
379                         get {
380                                 string xmlLang = reader.XmlLang;
381                                 if (xmlLang != null)
382                                         return xmlLang;
383                                 int idx = this.FindDefaultAttribute ("lang", XmlNamespaceManager.XmlnsXml);
384                                 if (idx < 0)
385                                         return null;
386                                 xmlLang = defaultAttributes [idx].ValidatedDefaultValue;
387                                 if (xmlLang == null)
388                                         xmlLang = defaultAttributes [idx].ValidatedFixedValue;
389                                 return xmlLang;
390                         }
391                 }
392
393                 public override XmlSpace XmlSpace {
394                         get {
395                                 XmlSpace space = reader.XmlSpace;
396                                 if (space != XmlSpace.None)
397                                         return space;
398                                 int idx = this.FindDefaultAttribute ("space", XmlNamespaceManager.XmlnsXml);
399                                 if (idx < 0)
400                                         return XmlSpace.None;
401                                 string spaceSpec = defaultAttributes [idx].ValidatedDefaultValue;
402                                 if (spaceSpec == null)
403                                         spaceSpec = defaultAttributes [idx].ValidatedFixedValue;
404                                 return (XmlSpace) Enum.Parse (typeof (XmlSpace), spaceSpec, false);
405                         }
406                 }
407
408                 // Private Methods
409
410                 private void HandleError (string error)
411                 {
412                         HandleError (error, null);
413                 }
414
415                 private void HandleError (string error, Exception innerException)
416                 {
417                         HandleError (error, innerException, false);
418                 }
419
420                 private void HandleError (string error, Exception innerException, bool isWarning)
421                 {
422                         if (ValidationType == ValidationType.None)      // extra quick check
423                                 return;
424
425                         ValException schemaException = new ValException (error, 
426                                         this, this.BaseURI, null, innerException);
427                         HandleError (schemaException, isWarning);
428                 }
429
430                 private void HandleError (ValException schemaException)
431                 {
432                         HandleError (schemaException, false);
433                 }
434
435                 private void HandleError (ValException schemaException, bool isWarning)
436                 {
437                         if (ValidationType == ValidationType.None)
438                                 return;
439
440                         ValidationEventArgs e = new ValidationEventArgs (schemaException,
441                                 schemaException.Message, isWarning ? XmlSeverityType.Warning : XmlSeverityType.Error);
442
443                         if (ValidationEventHandler != null)
444                                 ValidationEventHandler (this, e);
445
446                         else if (e.Severity == XmlSeverityType.Error)
447                                 throw e.Exception;
448                 }
449
450                 private XsElement FindElement (string name, string ns)
451                 {
452                         return (XsElement) schemas.GlobalElements [new QName (name, ns)];
453                 }
454
455                 private XmlSchemaType FindType (QName qname)
456                 {
457                         return (XmlSchemaType) schemas.GlobalTypes [qname];
458                 }
459
460                 private void ValidateStartElementParticle ()
461                 {
462                         if (Context.State == null)
463                                 return;
464                         Context.XsiType = null;
465                         state.CurrentElement = null;
466                         Context.EvaluateStartElement (reader.LocalName,
467                                 reader.NamespaceURI);
468                         if (Context.IsInvalid)
469                                 HandleError ("Invalid start element: " + reader.NamespaceURI + ":" + reader.LocalName);
470
471                         Context.SetElement (state.CurrentElement);
472                 }
473
474                 private void ValidateEndElementParticle ()
475                 {
476                         if (Context.State != null) {
477                                 if (!Context.EvaluateEndElement ()) {
478                                         HandleError ("Invalid end element: " + reader.Name);
479                                 }
480                         }
481                         state.PopContext ();
482                 }
483
484                 // Utility for missing validation completion related to child items.
485                 private void ValidateCharacters ()
486                 {
487                         if (xsiNilDepth >= 0 && xsiNilDepth < reader.Depth)
488                                 HandleError ("Element item appeared, while current element context is nil.");
489
490                         if (shouldValidateCharacters)
491                                 storedCharacters.Append (reader.Value);
492                 }
493
494                 // Utility for missing validation completion related to child items.
495                 private void ValidateEndSimpleContent ()
496                 {
497                         if (shouldValidateCharacters)
498                                 ValidateEndSimpleContentCore ();
499                         shouldValidateCharacters = false;
500                         storedCharacters.Length = 0;
501                 }
502
503                 private void ValidateEndSimpleContentCore ()
504                 {
505                         if (Context.ActualType == null)
506                                 return;
507
508                         string value = storedCharacters.ToString ();
509
510                         if (value.Length == 0) {
511                                 // 3.3.4 Element Locally Valid (Element) 5.1.2
512                                 if (Context.Element != null) {
513                                         if (Context.Element.ValidatedDefaultValue != null)
514                                                 value = Context.Element.ValidatedDefaultValue;
515                                 }                                       
516                         }
517
518                         XsDatatype dt = Context.ActualType as XsDatatype;
519                         SimpleType st = Context.ActualType as SimpleType;
520                         if (dt == null) {
521                                 if (st != null) {
522                                         dt = st.Datatype;
523                                 } else {
524                                         ComplexType ct = Context.ActualType as ComplexType;
525                                         dt = ct.Datatype;
526                                         switch (ct.ContentType) {
527                                         case XmlSchemaContentType.ElementOnly:
528                                         case XmlSchemaContentType.Empty:
529                                                 if (value.Length > 0 && !XmlChar.IsWhitespace (value))
530                                                         HandleError ("Character content not allowed.");
531                                                 break;
532                                         }
533                                 }
534                         }
535                         if (dt != null) {
536                                 // 3.3.4 Element Locally Valid (Element) :: 5.2.2.2. Fixed value constraints
537                                 if (Context.Element != null && Context.Element.ValidatedFixedValue != null)
538                                         if (value != Context.Element.ValidatedFixedValue)
539                                                 HandleError ("Fixed value constraint was not satisfied.");
540                                 AssessStringValid (st, dt, value);
541                         }
542
543 #region Key Constraints
544                         if (checkKeyConstraints)
545                                 ValidateSimpleContentIdentity (dt, value);
546 #endregion
547
548                         shouldValidateCharacters = false;
549                 }
550
551                 // 3.14.4 String Valid 
552                 private void AssessStringValid (SimpleType st,
553                         XsDatatype dt, string value)
554                 {
555                         XsDatatype validatedDatatype = dt;
556                         if (st != null) {
557                                 string normalized = validatedDatatype.Normalize (value);
558                                 string [] values;
559                                 XsDatatype itemDatatype;
560                                 SimpleType itemSimpleType;
561                                 switch (st.DerivedBy) {
562                                 case XmlSchemaDerivationMethod.List:
563                                         SimpleTypeList listContent = st.Content as SimpleTypeList;
564                                         values = normalized.Split (XmlChar.WhitespaceChars);
565                                         itemDatatype = listContent.ValidatedListItemType as XsDatatype;
566                                         itemSimpleType = listContent.ValidatedListItemType as SimpleType;
567                                         for (int vi = 0; vi < values.Length; vi++) {
568                                                 string each = values [vi];
569                                                 if (each == String.Empty)
570                                                         continue;
571                                                 // validate against ValidatedItemType
572                                                 if (itemDatatype != null) {
573                                                         try {
574                                                                 itemDatatype.ParseValue (each, NameTable, NamespaceManager);
575                                                         } catch (Exception ex) { // FIXME: (wishlist) better exception handling ;-(
576                                                                 HandleError ("List type value contains one or more invalid values.", ex);
577                                                                 break;
578                                                         }
579                                                 }
580                                                 else
581                                                         AssessStringValid (itemSimpleType, itemSimpleType.Datatype, each);
582                                         }
583                                         break;
584                                 case XmlSchemaDerivationMethod.Union:
585                                         SimpleTypeUnion union = st.Content as SimpleTypeUnion;
586                                         {
587                                                 string each = normalized;
588                                                 // validate against ValidatedItemType
589                                                 bool passed = false;
590                                                 foreach (object eachType in union.ValidatedTypes) {
591                                                         itemDatatype = eachType as XsDatatype;
592                                                         itemSimpleType = eachType as SimpleType;
593                                                         if (itemDatatype != null) {
594                                                                 try {
595                                                                         itemDatatype.ParseValue (each, NameTable, NamespaceManager);
596                                                                 } catch (Exception) { // FIXME: (wishlist) better exception handling ;-(
597                                                                         continue;
598                                                                 }
599                                                         }
600                                                         else {
601                                                                 try {
602                                                                         AssessStringValid (itemSimpleType, itemSimpleType.Datatype, each);
603                                                                 } catch (ValException) {
604                                                                         continue;
605                                                                 }
606                                                         }
607                                                         passed = true;
608                                                         break;
609                                                 }
610                                                 if (!passed) {
611                                                         HandleError ("Union type value contains one or more invalid values.");
612                                                         break;
613                                                 }
614                                         }
615                                         break;
616                                 case XmlSchemaDerivationMethod.Restriction:
617                                         SimpleTypeRest str = st.Content as SimpleTypeRest;
618                                         // facet validation
619                                         if (str != null) {
620                                                 /* Don't forget to validate against inherited type's facets 
621                                                  * Could we simplify this by assuming that the basetype will also
622                                                  * be restriction?
623                                                  * */
624                                                  // mmm, will check later.
625                                                 SimpleType baseType = st.BaseXmlSchemaType as SimpleType;
626                                                 if (baseType != null) {
627                                                          AssessStringValid(baseType, dt, value);
628                                                 }
629                                                 if (!str.ValidateValueWithFacets (value, NameTable)) {
630                                                         HandleError ("Specified value was invalid against the facets.");
631                                                         break;
632                                                 }
633                                         }
634                                         validatedDatatype = st.Datatype;
635                                         break;
636                                 }
637                         }
638                         if (validatedDatatype != null) {
639                                 try {
640                                         validatedDatatype.ParseValue (value, NameTable, NamespaceManager);
641                                 } catch (Exception ex) {        // FIXME: (wishlist) It is bad manner ;-(
642                                         HandleError ("Invalidly typed data was specified.", ex);
643                                 }
644                         }
645                 }
646
647                 private object GetXsiType (string name)
648                 {
649                         object xsiType = null;
650                         QName typeQName = QName.Parse (name, this);
651                         if (typeQName == ComplexType.AnyTypeName)
652                                 xsiType = ComplexType.AnyType;
653                         else if (XmlSchemaUtil.IsBuiltInDatatypeName (typeQName))
654                                 xsiType = XsDatatype.FromName (typeQName);
655                         else
656                                 xsiType = FindType (typeQName);
657                         return xsiType;
658                 }
659
660                 // It is common to ElementLocallyValid::4 and SchemaValidityAssessment::1.2.1.2.4
661                 private void AssessLocalTypeDerivationOK (object xsiType, object baseType, XmlSchemaDerivationMethod flag)
662                 {
663                         XmlSchemaType xsiSchemaType = xsiType as XmlSchemaType;
664                         ComplexType baseComplexType = baseType as ComplexType;
665                         ComplexType xsiComplexType = xsiSchemaType as ComplexType;
666                         if (xsiType != baseType) {
667                                 // Extracted (not extraneous) check for 3.4.6 TypeDerivationOK.
668                                 if (baseComplexType != null)
669                                         flag |= baseComplexType.BlockResolved;
670                                 if (flag == XmlSchemaDerivationMethod.All) {
671                                         HandleError ("Prohibited element type substitution.");
672                                         return;
673                                 } else if (xsiSchemaType != null && (flag & xsiSchemaType.DerivedBy) != 0) {
674                                         HandleError ("Prohibited element type substitution.");
675                                         return;
676                                 }
677                         }
678
679                         if (xsiComplexType != null)
680                                 try {
681                                         xsiComplexType.ValidateTypeDerivationOK (baseType, null, null);
682                                 } catch (ValException ex) {
683 //                                      HandleError ("Locally specified schema complex type derivation failed. " + ex.Message, ex);
684                                         HandleError (ex);
685                                 }
686                         else {
687                                 SimpleType xsiSimpleType = xsiType as SimpleType;
688                                 if (xsiSimpleType != null) {
689                                         try {
690                                                 xsiSimpleType.ValidateTypeDerivationOK (baseType, null, null, true);
691                                         } catch (ValException ex) {
692 //                                              HandleError ("Locally specified schema simple type derivation failed. " + ex.Message, ex);
693                                                 HandleError (ex);
694                                         }
695                                 }
696                                 else if (xsiType is XsDatatype) {
697                                         // do nothing
698                                 }
699                                 else
700                                         HandleError ("Primitive data type cannot be derived type using xsi:type specification.");
701                         }
702                 }
703
704                 // Section 3.3.4 of the spec.
705                 private void AssessStartElementSchemaValidity ()
706                 {
707                         // If the reader is inside xsi:nil (and failed
708                         // on validation), then simply skip its content.
709                         if (xsiNilDepth >= 0 && xsiNilDepth < reader.Depth)
710                                 HandleError ("Element item appeared, while current element context is nil.");
711
712                         ValidateStartElementParticle ();
713
714                         string xsiNilValue = reader.GetAttribute ("nil", XmlSchema.InstanceNamespace);
715                         if (xsiNilValue != null)
716                                 xsiNilValue = xsiNilValue.Trim (XmlChar.WhitespaceChars);
717                         bool isXsiNil = xsiNilValue == "true";
718                         if (isXsiNil && this.xsiNilDepth < 0)
719                                 xsiNilDepth = reader.Depth;
720
721                         // [Schema Validity Assessment (Element) 1.2]
722                         // Evaluate "local type definition" from xsi:type.
723                         // (See spec 3.3.4 Schema Validity Assessment (Element) 1.2.1.2.3.
724                         // Note that Schema Validity Assessment(Element) 1.2 takes
725                         // precedence than 1.1 of that.
726
727                         string xsiTypeName = reader.GetAttribute ("type", XmlSchema.InstanceNamespace);
728                         if (xsiTypeName != null) {
729                                 xsiTypeName = xsiTypeName.Trim (XmlChar.WhitespaceChars);
730                                 object xsiType = GetXsiType (xsiTypeName);
731                                 if (xsiType == null)
732                                         HandleError ("The instance type was not found: " + xsiTypeName + " .");
733                                 else {
734                                         XmlSchemaType xsiSchemaType = xsiType as XmlSchemaType;
735                                         if (xsiSchemaType != null && this.Context.Element != null) {
736                                                 XmlSchemaType elemBaseType = Context.Element.ElementType as XmlSchemaType;
737                                                 if (elemBaseType != null && (xsiSchemaType.DerivedBy & elemBaseType.FinalResolved) != 0)
738                                                         HandleError ("The instance type is prohibited by the type of the context element.");
739                                                 if (elemBaseType != xsiType && (xsiSchemaType.DerivedBy & this.Context.Element.BlockResolved) != 0)
740                                                         HandleError ("The instance type is prohibited by the context element.");
741                                         }
742                                         ComplexType xsiComplexType = xsiType as ComplexType;
743                                         if (xsiComplexType != null && xsiComplexType.IsAbstract)
744                                                 HandleError ("The instance type is abstract: " + xsiTypeName + " .");
745                                         else {
746                                                 // If current schema type exists, then this xsi:type must be
747                                                 // valid extension of that type. See 1.2.1.2.4.
748                                                 if (Context.Element != null) {
749                                                         AssessLocalTypeDerivationOK (xsiType, Context.Element.ElementType, Context.Element.BlockResolved);
750                                                 }
751                                                 AssessStartElementLocallyValidType (xsiType);   // 1.2.2:
752                                                 Context.XsiType = xsiType;
753                                         }
754                                 }
755                         }
756
757                         // Create Validation Root, if not exist.
758                         // [Schema Validity Assessment (Element) 1.1]
759                         if (Context.Element == null) {
760                                 state.CurrentElement = FindElement (reader.LocalName, reader.NamespaceURI);
761                                 Context.SetElement (state.CurrentElement);
762                         }
763                         if (Context.Element != null) {
764                                 if (Context.XsiType == null) {
765                                         AssessElementLocallyValidElement (xsiNilValue); // 1.1.2
766                                 }
767                         } else {
768                                 switch (state.ProcessContents) {
769                                 case ContentProc.Skip:
770                                         break;
771                                 case ContentProc.Lax:
772                                         break;
773                                 default:
774                                         if (xsiTypeName == null &&
775                                                 (schemas.Contains (reader.NamespaceURI) ||
776                                                 !schemas.MissedSubComponents (reader.NamespaceURI)))
777                                                 HandleError ("Element declaration for " + new QName (reader.LocalName, reader.NamespaceURI) + " is missing.");
778                                         break;
779                                 }
780                         }
781
782                         state.PushContext ();
783
784                         XsdValidationState next = null;
785                         if (state.ProcessContents == ContentProc.Skip)
786                                 skipValidationDepth = reader.Depth;
787                         else {
788                                 // create child particle state.
789                                 ComplexType xsComplexType = SchemaType as ComplexType;
790                                 if (xsComplexType != null)
791                                         next = state.Create (xsComplexType.ValidatableParticle);
792                                 else if (state.ProcessContents == ContentProc.Lax)
793                                         next = state.Create (XmlSchemaAny.AnyTypeContent);
794                                 else
795                                         next = state.Create (XmlSchemaParticle.Empty);
796                         }
797                         Context.State = next;
798
799 #region Key Constraints
800                         if (checkKeyConstraints) {
801                                 ValidateKeySelectors ();
802                                 ValidateKeyFields ();
803                         }
804 #endregion
805
806                 }
807
808                 // 3.3.4 Element Locally Valid (Element)
809                 private void AssessElementLocallyValidElement (string xsiNilValue)
810                 {
811                         XsElement element = Context.Element;
812                         QName qname = new QName (reader.LocalName, reader.NamespaceURI);
813                         // 1.
814                         if (element == null)
815                                 HandleError ("Element declaration is required for " + qname);
816                         // 2.
817                         if (element.ActualIsAbstract)
818                                 HandleError ("Abstract element declaration was specified for " + qname);
819                         // 3.1.
820                         if (!element.ActualIsNillable && xsiNilValue != null)
821                                 HandleError ("This element declaration is not nillable: " + qname);
822                         // 3.2.
823                         // Note that 3.2.1 xsi:nil constraints are to be 
824                         // validated in AssessElementSchemaValidity() and 
825                         // ValidateCharacters().
826                         else if (xsiNilValue == "true") {
827                                 if (element.ValidatedFixedValue != null)
828                                         HandleError ("Schema instance nil was specified, where the element declaration for " + qname + "has fixed value constraints.");
829                         }
830                         // 4. xsi:type (it takes precedence than element type)
831                         string xsiType = reader.GetAttribute ("type", XmlSchema.InstanceNamespace);
832                         if (xsiType != null) {
833                                 Context.XsiType = GetXsiType (xsiType);
834                                 AssessLocalTypeDerivationOK (Context.XsiType, element.ElementType, element.BlockResolved);
835                         }
836                         else
837                                 Context.XsiType = null;
838
839                         // 5 Not all things cannot be assessed here.
840                         // It is common to 5.1 and 5.2
841                         if (element.ElementType != null)
842                                 AssessStartElementLocallyValidType (SchemaType);
843
844                         // 6. should be out from here.
845                         // See invokation of AssessStartIdentityConstraints().
846
847                         // 7 is going to be validated in Read() (in case of xmlreader's EOF).
848                 }
849
850                 // 3.3.4 Element Locally Valid (Type)
851                 private void AssessStartElementLocallyValidType (object schemaType)
852                 {
853                         if (schemaType == null) {       // 1.
854                                 HandleError ("Schema type does not exist.");
855                                 return;
856                         }
857                         ComplexType cType = schemaType as ComplexType;
858                         SimpleType sType = schemaType as SimpleType;
859                         if (sType != null) {
860                                 // 3.1.1.
861                                 while (reader.MoveToNextAttribute ()) {
862                                         if (reader.NamespaceURI == XmlNamespaceManager.XmlnsXmlns)
863                                                 continue;
864                                         if (reader.NamespaceURI != XmlSchema.InstanceNamespace)
865                                                 HandleError ("Current simple type cannot accept attributes other than schema instance namespace.");
866                                         switch (reader.LocalName) {
867                                         case "type":
868                                         case "nil":
869                                         case "schemaLocation":
870                                         case "noNamespaceSchemaLocation":
871                                                 break;
872                                         default:
873                                                 HandleError ("Unknown schema instance namespace attribute: " + reader.LocalName);
874                                                 break;
875                                         }
876                                 }
877                                 reader.MoveToElement ();
878                                 // 3.1.2 and 3.1.3 cannot be assessed here.
879                         } else if (cType != null) {
880                                 if (cType.IsAbstract) { // 2.
881                                         HandleError ("Target complex type is abstract.");
882                                         return;
883                                 }
884                                 // 3.2
885                                 AssessElementLocallyValidComplexType (cType);
886                         }
887                 }
888
889                 // 3.4.4 Element Locally Valid (Complex Type)
890                 private void AssessElementLocallyValidComplexType (ComplexType cType)
891                 {
892                         // 1.
893                         if (cType.IsAbstract)
894                                 HandleError ("Target complex type is abstract.");
895
896                         // 2 (xsi:nil and content prohibition)
897                         // See AssessStartElementSchemaValidity() and ValidateCharacters()
898
899                         // 3. attribute uses and 
900                         // 5. wild IDs
901                         if (reader.MoveToFirstAttribute ()) {
902                                 do {
903                                         switch (reader.NamespaceURI) {
904                                         case"http://www.w3.org/2000/xmlns/":
905                                         case XmlSchema.InstanceNamespace:
906                                                 continue;
907                                         }
908                                         QName qname = new QName (reader.LocalName, reader.NamespaceURI);
909                                         // including 3.10.4 Item Valid (Wildcard)
910                                         XmlSchemaObject attMatch = XmlSchemaUtil.FindAttributeDeclaration (reader.NamespaceURI, schemas, cType, qname);
911                                         if (attMatch == null)
912                                                 HandleError ("Attribute declaration was not found for " + qname);
913                                         XsAttribute attdecl = attMatch as XsAttribute;
914                                         if (attdecl != null) {
915                                                 AssessAttributeLocallyValidUse (attdecl);
916                                                 AssessAttributeLocallyValid (attdecl);
917                                         } // otherwise anyAttribute or null.
918                                 } while (reader.MoveToNextAttribute ());
919                                 reader.MoveToElement ();
920                         }
921
922                         // Collect default attributes.
923                         // 4.
924                         foreach (DictionaryEntry entry in cType.AttributeUses) {
925                                 XsAttribute attr = (XsAttribute) entry.Value;
926                                 if (reader [attr.QualifiedName.Name, attr.QualifiedName.Namespace] == null) {
927                                         if (attr.ValidatedUse == XmlSchemaUse.Required && 
928                                                 attr.ValidatedFixedValue == null)
929                                                 HandleError ("Required attribute " + attr.QualifiedName + " was not found.");
930                                         else if (attr.ValidatedDefaultValue != null || attr.ValidatedFixedValue != null)
931                                                 defaultAttributesCache.Add (attr);
932                                 }
933                         }
934                         if (defaultAttributesCache.Count == 0)
935                                 defaultAttributes = emptyAttributeArray;
936                         else
937                                 defaultAttributes = (XsAttribute []) 
938                                         defaultAttributesCache.ToArray (
939                                                 typeof (XsAttribute));
940                         defaultAttributesCache.Clear ();
941                         // 5. wild IDs was already checked above.
942                 }
943
944                 // 3.2.4 Attribute Locally Valid and 3.4.4
945                 private void AssessAttributeLocallyValid (XsAttribute attr)
946                 {
947                         // 2. - 4.
948                         if (attr.AttributeType == null)
949                                 HandleError ("Attribute type is missing for " + attr.QualifiedName);
950                         XsDatatype dt = attr.AttributeType as XsDatatype;
951                         if (dt == null)
952                                 dt = ((SimpleType) attr.AttributeType).Datatype;
953                         // It is a bit heavy process, so let's omit as long as possible ;-)
954                         if (dt != SimpleType.AnySimpleType || attr.ValidatedFixedValue != null) {
955                                 string normalized = dt.Normalize (reader.Value);
956                                 object parsedValue = null;
957                                 try {
958                                         parsedValue = dt.ParseValue (normalized, reader.NameTable, NamespaceManager);
959                                 } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
960                                         HandleError ("Attribute value is invalid against its data type " + dt.TokenizedType, ex);
961                                 }
962                                 if (attr.ValidatedFixedValue != null && attr.ValidatedFixedValue != normalized) {
963                                         HandleError ("The value of the attribute " + attr.QualifiedName + " does not match with its fixed value.");
964                                         parsedValue = dt.ParseValue (attr.ValidatedFixedValue, reader.NameTable, NamespaceManager);
965                                 }
966 #region ID Constraints
967                                 if (this.checkIdentity) {
968                                         string error = idManager.AssessEachAttributeIdentityConstraint (dt, parsedValue, ((QName) elementQNameStack [elementQNameStack.Count - 1]).Name);
969                                         if (error != null)
970                                                 HandleError (error);
971                                 }
972 #endregion
973                         }
974                 }
975
976                 private void AssessAttributeLocallyValidUse (XsAttribute attr)
977                 {
978                         // This is extra check than spec 3.5.4
979                         if (attr.ValidatedUse == XmlSchemaUse.Prohibited)
980                                 HandleError ("Attribute " + attr.QualifiedName + " is prohibited in this context.");
981                 }
982
983                 private void AssessEndElementSchemaValidity ()
984                 {
985                         ValidateEndElementParticle ();  // validate against childrens' state.
986
987                         ValidateEndSimpleContent ();
988
989                         // 3.3.4 Assess ElementLocallyValidElement 5: value constraints.
990                         // 3.3.4 Assess ElementLocallyValidType 3.1.3. = StringValid(3.14.4)
991                         // => ValidateEndSimpleContent().
992
993 #region Key Constraints
994                         if (checkKeyConstraints)
995                                 ValidateEndElementKeyConstraints ();
996 #endregion
997
998                         // Reset xsi:nil, if required.
999                         if (xsiNilDepth == reader.Depth)
1000                                 xsiNilDepth = -1;
1001                 }
1002
1003 #region Key Constraints
1004                 private void ValidateEndElementKeyConstraints ()
1005                 {
1006                         // Reset Identity constraints.
1007                         for (int i = 0; i < keyTables.Count; i++) {
1008                                 XsdKeyTable seq = this.keyTables [i] as XsdKeyTable;
1009                                 if (seq.StartDepth == reader.Depth) {
1010                                         EndIdentityValidation (seq);
1011                                 } else {
1012                                         for (int k = 0; k < seq.Entries.Count; k++) {
1013                                                 XsdKeyEntry entry = seq.Entries [k] as XsdKeyEntry;
1014                                                 // Remove finished (maybe key not found) entries.
1015                                                 if (entry.StartDepth == reader.Depth) {
1016                                                         if (entry.KeyFound)
1017                                                                 seq.FinishedEntries.Add (entry);
1018                                                         else if (seq.SourceSchemaIdentity is XmlSchemaKey)
1019                                                                 HandleError ("Key sequence is missing.");
1020                                                         seq.Entries.RemoveAt (k);
1021                                                         k--;
1022                                                 }
1023                                                 // Pop validated key depth to find two or more fields.
1024                                                 else {
1025                                                         for (int j = 0; j < entry.KeyFields.Count; j++) {
1026                                                                 XsdKeyEntryField kf = entry.KeyFields [j];
1027                                                                 if (!kf.FieldFound && kf.FieldFoundDepth == reader.Depth) {
1028                                                                         kf.FieldFoundDepth = 0;
1029                                                                         kf.FieldFoundPath = null;
1030                                                                 }
1031                                                         }
1032                                                 }
1033                                         }
1034                                 }
1035                         }
1036                         for (int i = 0; i < keyTables.Count; i++) {
1037                                 XsdKeyTable seq = this.keyTables [i] as XsdKeyTable;
1038                                 if (seq.StartDepth == reader.Depth) {
1039                                         keyTables.RemoveAt (i);
1040                                         i--;
1041                                 }
1042                         }
1043                 }
1044
1045                 // 3.11.4 Identity Constraint Satisfied
1046                 private void ValidateKeySelectors ()
1047                 {
1048                         if (tmpKeyrefPool != null)
1049                                 tmpKeyrefPool.Clear ();
1050                         if (Context.Element != null && Context.Element.Constraints.Count > 0) {
1051                                 // (a) Create new key sequences, if required.
1052                                 for (int i = 0; i < Context.Element.Constraints.Count; i++) {
1053                                         XmlSchemaIdentityConstraint ident = (XmlSchemaIdentityConstraint) Context.Element.Constraints [i];
1054                                         XsdKeyTable seq = CreateNewKeyTable (ident);
1055                                         if (ident is XmlSchemaKeyref) {
1056                                                 if (tmpKeyrefPool == null)
1057                                                         tmpKeyrefPool = new ArrayList ();
1058                                                 tmpKeyrefPool.Add (seq);
1059                                         }
1060                                 }
1061                         }
1062
1063                         // (b) Evaluate current key sequences.
1064                         for (int i = 0; i < keyTables.Count; i++) {
1065                                 XsdKeyTable seq  = (XsdKeyTable) keyTables [i];
1066                                 if (seq.SelectorMatches (this.elementQNameStack, reader.Depth) != null) {
1067                                         // creates and registers new entry.
1068                                         XsdKeyEntry entry = new XsdKeyEntry (seq, reader.Depth, readerLineInfo);
1069                                         seq.Entries.Add (entry);
1070                                 }
1071                         }
1072                 }
1073
1074                 private void ValidateKeyFields ()
1075                 {
1076                         // (c) Evaluate field paths.
1077                         for (int i = 0; i < keyTables.Count; i++) {
1078                                 XsdKeyTable seq  = (XsdKeyTable) keyTables [i];
1079                                 // If possible, create new field entry candidates.
1080                                 for (int j = 0; j < seq.Entries.Count; j++) {
1081                                         try {
1082                                                 ProcessKeyEntry (seq.Entries [j]);
1083                                         } catch (ValException ex) {
1084                                                 HandleError (ex);
1085                                         }
1086                                 }
1087                         }
1088                 }
1089
1090                 private void ProcessKeyEntry (XsdKeyEntry entry)
1091                 {
1092                         bool isNil = XsiNilDepth == Depth;
1093                         entry.ProcessMatch (false, elementQNameStack, this, NameTable, BaseURI, SchemaType, NamespaceManager, readerLineInfo, Depth, null, null, null, isNil, CurrentKeyFieldConsumers);
1094                         if (MoveToFirstAttribute ()) {
1095                                 try {
1096                                         do {
1097                                                 switch (NamespaceURI) {
1098                                                 case XmlNamespaceManager.XmlnsXmlns:
1099                                                 case XmlSchema.InstanceNamespace:
1100                                                         continue;
1101                                                 }
1102                                                 XmlSchemaDatatype dt = SchemaType as XmlSchemaDatatype;
1103                                                 XmlSchemaSimpleType st = SchemaType as XmlSchemaSimpleType;
1104                                                 if (dt == null && st != null)
1105                                                         dt = st.Datatype;
1106                                                 object identity = null;
1107                                                 if (dt != null)
1108                                                         identity = dt.ParseValue (Value, NameTable, NamespaceManager);
1109                                                 if (identity == null)
1110                                                         identity = Value;
1111                                                 entry.ProcessMatch (true, elementQNameStack, this, NameTable, BaseURI, SchemaType, NamespaceManager, readerLineInfo, Depth, LocalName, NamespaceURI, identity, false, CurrentKeyFieldConsumers);
1112                                         } while (MoveToNextAttribute ());
1113                                 } finally {
1114                                         MoveToElement ();
1115                                 }
1116                         }
1117                 }
1118
1119                 private XsdKeyTable CreateNewKeyTable (XmlSchemaIdentityConstraint ident)
1120                 {
1121                         XsdKeyTable seq = new XsdKeyTable (ident);
1122                         seq.StartDepth = reader.Depth;
1123                         this.keyTables.Add (seq);
1124                         return seq;
1125                 }
1126
1127                 private void ValidateSimpleContentIdentity (
1128                         XmlSchemaDatatype dt, string value)
1129                 {
1130                         // Identity field value
1131                         if (currentKeyFieldConsumers != null) {
1132                                 while (this.currentKeyFieldConsumers.Count > 0) {
1133                                         XsdKeyEntryField field = this.currentKeyFieldConsumers [0] as XsdKeyEntryField;
1134                                         if (field.Identity != null)
1135                                                 HandleError ("Two or more identical field was found. Former value is '" + field.Identity + "' .");
1136                                         object identity = null; // This means empty value
1137                                         if (dt != null) {
1138                                                 try {
1139                                                         identity = dt.ParseValue (value, NameTable, NamespaceManager);
1140                                                 } catch (Exception ex) { // FIXME: (wishlist) This is bad manner ;-(
1141                                                         HandleError ("Identity value is invalid against its data type " + dt.TokenizedType, ex);
1142                                                 }
1143                                         }
1144                                         if (identity == null)
1145                                                 identity = value;
1146
1147                                         if (!field.SetIdentityField (identity, reader.Depth == xsiNilDepth, dt as XsdAnySimpleType, this.Depth, readerLineInfo))
1148                                                 HandleError ("Two or more identical key value was found: '" + value + "' .");
1149                                         this.currentKeyFieldConsumers.RemoveAt (0);
1150                                 }
1151                         }
1152                 }
1153
1154                 private void EndIdentityValidation (XsdKeyTable seq)
1155                 {
1156                         ArrayList errors = null;
1157                         for (int i = 0; i < seq.Entries.Count; i++) {
1158                                 XsdKeyEntry entry = (XsdKeyEntry) seq.Entries [i];
1159                                 if (entry.KeyFound)
1160                                         continue;
1161                                 if (seq.SourceSchemaIdentity is XmlSchemaKey) {
1162                                         if (errors == null)
1163                                                 errors = new ArrayList ();
1164                                         errors.Add ("line " + entry.SelectorLineNumber + "position " + entry.SelectorLinePosition);
1165                                 }
1166                         }
1167                         if (errors != null)
1168                                 HandleError ("Invalid identity constraints were found. Key was not found. "
1169                                         + String.Join (", ", errors.ToArray (typeof (string)) as string []));
1170
1171                         // If it is keyref, then find reference target
1172                         XmlSchemaKeyref xsdKeyref = seq.SourceSchemaIdentity as XmlSchemaKeyref;
1173                         if (xsdKeyref != null)
1174                                 EndKeyrefValidation (seq, xsdKeyref.Target);
1175                 }
1176
1177                 private void EndKeyrefValidation (XsdKeyTable seq, XmlSchemaIdentityConstraint targetIdent)
1178                 {
1179                         for (int i = this.keyTables.Count - 1; i >= 0; i--) {
1180                                 XsdKeyTable target = this.keyTables [i] as XsdKeyTable;
1181                                 if (target.SourceSchemaIdentity != targetIdent)
1182                                         continue;
1183                                 seq.ReferencedKey = target;
1184                                 for (int j = 0; j < seq.FinishedEntries.Count; j++) {
1185                                         XsdKeyEntry entry = (XsdKeyEntry) seq.FinishedEntries [j];
1186                                         for (int k = 0; k < target.FinishedEntries.Count; k++) {
1187                                                 XsdKeyEntry targetEntry = (XsdKeyEntry) target.FinishedEntries [k];
1188                                                 if (entry.CompareIdentity (targetEntry)) {
1189                                                         entry.KeyRefFound = true;
1190                                                         break;
1191                                                 }
1192                                         }
1193                                 }
1194                         }
1195                         if (seq.ReferencedKey == null)
1196                                 HandleError ("Target key was not found.");
1197                         ArrayList errors = null;
1198                         for (int i = 0; i < seq.FinishedEntries.Count; i++) {
1199                                 XsdKeyEntry entry = (XsdKeyEntry) seq.FinishedEntries [i];
1200                                 if (!entry.KeyRefFound) {
1201                                         if (errors == null)
1202                                                 errors = new ArrayList ();
1203                                         errors.Add (" line " + entry.SelectorLineNumber + ", position " + entry.SelectorLinePosition);
1204                                 }
1205                         }
1206                         if (errors != null)
1207                                 HandleError ("Invalid identity constraints were found. Referenced key was not found: "
1208                                         + String.Join (" / ", errors.ToArray (typeof (string)) as string []));
1209                 }
1210 #endregion
1211
1212                 // Overrided Methods
1213
1214                 public override void Close ()
1215                 {
1216                         reader.Close ();
1217                 }
1218
1219                 public override string GetAttribute (int i)
1220                 {
1221                         switch (reader.NodeType) {
1222                         case XmlNodeType.XmlDeclaration:
1223                         case XmlNodeType.DocumentType:
1224                                 return reader.GetAttribute (i);
1225                         }
1226
1227                         if (reader.AttributeCount > i)
1228                                 reader.GetAttribute (i);
1229                         int defIdx = i - reader.AttributeCount;
1230                         if (i < AttributeCount)
1231                                 return defaultAttributes [defIdx].DefaultValue;
1232
1233                         throw new ArgumentOutOfRangeException ("i", i, "Specified attribute index is out of range.");
1234                 }
1235
1236                 public override string GetAttribute (string name)
1237                 {
1238                         switch (reader.NodeType) {
1239                         case XmlNodeType.XmlDeclaration:
1240                         case XmlNodeType.DocumentType:
1241                                 return reader.GetAttribute (name);
1242                         }
1243
1244                         string value = reader.GetAttribute (name);
1245                         if (value != null)
1246                                 return value;
1247
1248                         QName qname = SplitQName (name);
1249                         return GetDefaultAttribute (qname.Name, qname.Namespace);
1250                 }
1251
1252                 private QName SplitQName (string name)
1253                 {
1254                         if (!XmlChar.IsName (name))
1255                                 throw new ArgumentException ("Invalid name was specified.", "name");
1256
1257                         Exception ex = null;
1258                         QName qname = XmlSchemaUtil.ToQName (reader, name, out ex);
1259                         if (ex != null)
1260                                 return QName.Empty;
1261                         else
1262                                 return qname;
1263                 }
1264
1265                 public override string GetAttribute (string localName, string ns)
1266                 {
1267                         switch (reader.NodeType) {
1268                         case XmlNodeType.XmlDeclaration:
1269                         case XmlNodeType.DocumentType:
1270                                 return reader.GetAttribute (localName, ns);
1271                         }
1272
1273                         string value = reader.GetAttribute (localName, ns);
1274                         if (value != null)
1275                                 return value;
1276
1277                         return GetDefaultAttribute (localName, ns);
1278                 }
1279
1280                 private string GetDefaultAttribute (string localName, string ns)
1281                 {
1282                         int idx = this.FindDefaultAttribute (localName, ns);
1283                         if (idx < 0)
1284                                 return null;
1285                         string value = defaultAttributes [idx].ValidatedDefaultValue;
1286                         if (value == null)
1287                                 value = defaultAttributes [idx].ValidatedFixedValue;
1288                         return value;
1289                 }
1290
1291                 private int FindDefaultAttribute (string localName, string ns)
1292                 {
1293                         for (int i = 0; i < this.defaultAttributes.Length; i++) {
1294                                 XsAttribute attr = defaultAttributes [i];
1295                                 if (attr.QualifiedName.Name == localName &&
1296                                         (ns == null || attr.QualifiedName.Namespace == ns))
1297                                         return i;
1298                         }
1299                         return -1;
1300                 }
1301
1302                 public bool HasLineInfo ()
1303                 {
1304                         return readerLineInfo != null && readerLineInfo.HasLineInfo ();
1305                 }
1306
1307                 public override string LookupNamespace (string prefix)
1308                 {
1309                         return reader.LookupNamespace (prefix);
1310                 }
1311
1312                 public override void MoveToAttribute (int i)
1313                 {
1314                         switch (reader.NodeType) {
1315                         case XmlNodeType.XmlDeclaration:
1316                         case XmlNodeType.DocumentType:
1317                                 reader.MoveToAttribute (i);
1318                                 return;
1319                         }
1320
1321                         currentAttrType = null;
1322                         if (i < reader.AttributeCount) {
1323                                 reader.MoveToAttribute (i);
1324                                 this.currentDefaultAttribute = -1;
1325                                 this.defaultAttributeConsumed = false;
1326                         }
1327
1328                         if (i < AttributeCount) {
1329                                 this.currentDefaultAttribute = i - reader.AttributeCount;
1330                                 this.defaultAttributeConsumed = false;
1331                         }
1332                         else
1333                                 throw new ArgumentOutOfRangeException ("i", i, "Attribute index is out of range.");
1334                 }
1335
1336                 public override bool MoveToAttribute (string name)
1337                 {
1338                         switch (reader.NodeType) {
1339                         case XmlNodeType.XmlDeclaration:
1340                         case XmlNodeType.DocumentType:
1341                                 return reader.MoveToAttribute (name);
1342                         }
1343
1344                         currentAttrType = null;
1345                         bool b = reader.MoveToAttribute (name);
1346                         if (b) {
1347                                 this.currentDefaultAttribute = -1;
1348                                 this.defaultAttributeConsumed = false;
1349                                 return true;
1350                         }
1351
1352                         return MoveToDefaultAttribute (name, null);
1353                 }
1354
1355                 public override bool MoveToAttribute (string localName, string ns)
1356                 {
1357                         switch (reader.NodeType) {
1358                         case XmlNodeType.XmlDeclaration:
1359                         case XmlNodeType.DocumentType:
1360                                 return reader.MoveToAttribute (localName, ns);
1361                         }
1362
1363                         currentAttrType = null;
1364                         bool b = reader.MoveToAttribute (localName, ns);
1365                         if (b) {
1366                                 this.currentDefaultAttribute = -1;
1367                                 this.defaultAttributeConsumed = false;
1368                                 return true;
1369                         }
1370
1371                         return MoveToDefaultAttribute (localName, ns);
1372                 }
1373
1374                 private bool MoveToDefaultAttribute (string localName, string ns)
1375                 {
1376                         int idx = this.FindDefaultAttribute (localName, ns);
1377                         if (idx < 0)
1378                                 return false;
1379                         currentDefaultAttribute = idx;
1380                         defaultAttributeConsumed = false;
1381                         return true;
1382                 }
1383
1384                 public override bool MoveToElement ()
1385                 {
1386                         currentDefaultAttribute = -1;
1387                         defaultAttributeConsumed = false;
1388                         currentAttrType = null;
1389                         return reader.MoveToElement ();
1390                 }
1391
1392                 public override bool MoveToFirstAttribute ()
1393                 {
1394                         switch (reader.NodeType) {
1395                         case XmlNodeType.XmlDeclaration:
1396                         case XmlNodeType.DocumentType:
1397                                 return reader.MoveToFirstAttribute ();
1398                         }
1399
1400                         currentAttrType = null;
1401                         if (reader.AttributeCount > 0) {
1402                                 bool b = reader.MoveToFirstAttribute ();
1403                                 if (b) {
1404                                         currentDefaultAttribute = -1;
1405                                         defaultAttributeConsumed = false;
1406                                 }
1407                                 return b;
1408                         }
1409
1410                         if (this.defaultAttributes.Length > 0) {
1411                                 currentDefaultAttribute = 0;
1412                                 defaultAttributeConsumed = false;
1413                                 return true;
1414                         }
1415                         else
1416                                 return false;
1417                 }
1418
1419                 public override bool MoveToNextAttribute ()
1420                 {
1421                         switch (reader.NodeType) {
1422                         case XmlNodeType.XmlDeclaration:
1423                         case XmlNodeType.DocumentType:
1424                                 return reader.MoveToNextAttribute ();
1425                         }
1426
1427                         currentAttrType = null;
1428                         if (currentDefaultAttribute >= 0) {
1429                                 if (defaultAttributes.Length == currentDefaultAttribute + 1)
1430                                         return false;
1431                                 currentDefaultAttribute++;
1432                                 defaultAttributeConsumed = false;
1433                                 return true;
1434                         }
1435
1436                         bool b = reader.MoveToNextAttribute ();
1437                         if (b) {
1438                                 currentDefaultAttribute = -1;
1439                                 defaultAttributeConsumed = false;
1440                                 return true;
1441                         }
1442
1443                         if (defaultAttributes.Length > 0) {
1444                                 currentDefaultAttribute = 0;
1445                                 defaultAttributeConsumed = false;
1446                                 return true;
1447                         }
1448                         else
1449                                 return false;
1450                 }
1451
1452                 private XmlSchema ReadExternalSchema (string uri)
1453                 {
1454                         Uri absUri = resolver.ResolveUri ((BaseURI != "" ? new Uri (BaseURI) : null), uri);
1455                         string absUriString = absUri != null ? absUri.ToString () : String.Empty;
1456                         XmlTextReader xtr = null;
1457                         try {
1458                                 xtr = new XmlTextReader (absUriString,
1459                                         (Stream) resolver.GetEntity (
1460                                                 absUri, null, typeof (Stream)),
1461                                         NameTable);
1462                                 return XmlSchema.Read (
1463                                         xtr, ValidationEventHandler);
1464                         } finally {
1465                                 if (xtr != null)
1466                                         xtr.Close ();
1467                         }
1468                 }
1469
1470                 private void ExamineAdditionalSchema ()
1471                 {
1472                         if (resolver == null)
1473                                 return;
1474                         XmlSchema schema = null;
1475                         string schemaLocation = reader.GetAttribute ("schemaLocation", XmlSchema.InstanceNamespace);
1476                         bool schemaAdded = false;
1477                         if (schemaLocation != null) {
1478                                 string [] tmp = null;
1479                                 try {
1480                                         schemaLocation = XsDatatype.FromName ("token", XmlSchema.Namespace).Normalize (schemaLocation);
1481                                         tmp = schemaLocation.Split (XmlChar.WhitespaceChars);
1482                                 } catch (Exception ex) {
1483                                         if (schemas.Count == 0)
1484                                                 HandleError ("Invalid schemaLocation attribute format.", ex, true);
1485                                         tmp = new string [0];
1486                                 }
1487                                 if (tmp.Length % 2 != 0)
1488                                         if (schemas.Count == 0)
1489                                                 HandleError ("Invalid schemaLocation attribute format.");
1490                                 int i=0;
1491                                 do {
1492                                         try {
1493                                                 for (; i < tmp.Length; i += 2) {
1494                                                         schema = ReadExternalSchema (tmp [i + 1]);
1495                                                         if (schema.TargetNamespace == null)
1496                                                                 schema.TargetNamespace = tmp [i];
1497                                                         else if (schema.TargetNamespace != tmp [i])
1498                                                                 HandleError ("Specified schema has different target namespace.");
1499                                                         if (schema != null) {
1500                                                                 if (!schemas.Contains (schema.TargetNamespace)) {
1501                                                                         schemaAdded = true;
1502                                                                         schemas.Add (schema);
1503                                                                 }
1504                                                                 schema = null;
1505                                                         }
1506                                                 }
1507                                         } catch (Exception) {
1508                                                 if (!schemas.Contains (tmp [i]))
1509                                                         HandleError (String.Format ("Could not resolve schema location URI: {0}",
1510                                                                 i + 1 < tmp.Length ? tmp [i + 1] : String.Empty), null, true);
1511                                                 i += 2;
1512                                                 continue;
1513                                         }
1514                                 } while (i < tmp.Length);
1515                         }
1516                         string noNsSchemaLocation = reader.GetAttribute ("noNamespaceSchemaLocation", XmlSchema.InstanceNamespace);
1517                         if (noNsSchemaLocation != null) {
1518                                 try {
1519                                         schema = ReadExternalSchema (noNsSchemaLocation);
1520                                 } catch (Exception) { // FIXME: (wishlist) It is bad manner ;-(
1521                                         if (schemas.Count != 0)
1522                                                 HandleError ("Could not resolve schema location URI: " + noNsSchemaLocation, null, true);
1523                                 }
1524                                 if (schema != null && schema.TargetNamespace != null)
1525                                         HandleError ("Specified schema has different target namespace.");
1526                         }
1527                         if (schema != null) {
1528                                 if (!schemas.Contains (schema.TargetNamespace)) {
1529                                         schemaAdded = true;
1530                                         schemas.Add (schema);
1531                                 }
1532                         }
1533                         // FIXME: should call Reprocess()?
1534                         if (schemaAdded)
1535                                 schemas.Compile ();
1536                 }
1537
1538                 public override bool Read ()
1539                 {
1540                         validationStarted = true;
1541                         currentDefaultAttribute = -1;
1542                         defaultAttributeConsumed = false;
1543                         currentAttrType = null;
1544                         defaultAttributes = emptyAttributeArray;
1545
1546                         bool result = reader.Read ();
1547
1548                         // FIXME: schemaLocation could be specified 
1549                         // at any Depth.
1550                         if (reader.Depth == 0 &&
1551                                 reader.NodeType == XmlNodeType.Element) {
1552                                 // If the reader is DTDValidatingReader (it
1553                                 // is the default behavior of 
1554                                 // XmlValidatingReader) and DTD didn't appear,
1555                                 // we could just use its source XmlReader.
1556                                 DTDValidatingReader dtdr = reader as DTDValidatingReader;
1557                                 if (dtdr != null && dtdr.DTD == null)
1558                                         reader = dtdr.Source;
1559
1560                                 ExamineAdditionalSchema ();
1561                         }
1562                         if (schemas.Count == 0)
1563                                 return result;
1564                         if (!schemas.IsCompiled)
1565                                 schemas.Compile ();
1566
1567 #region ID Constraints
1568                         if (this.checkIdentity)
1569                                 idManager.OnStartElement ();
1570
1571                         // 3.3.4 ElementLocallyValidElement 7 = Root Valid.
1572                         if (!result && this.checkIdentity &&
1573                                 idManager.HasMissingIDReferences ())
1574                                 HandleError ("There are missing ID references: " + idManager.GetMissingIDString ());
1575 #endregion
1576
1577                         switch (reader.NodeType) {
1578                         case XmlNodeType.Element:
1579 #region Key Constraints
1580                                 if (checkKeyConstraints)
1581                                         this.elementQNameStack.Add (new QName (reader.LocalName, reader.NamespaceURI));
1582 #endregion
1583
1584                                 // If there is no schema information, then no validation is performed.
1585                                 if (skipValidationDepth < 0 || reader.Depth <= skipValidationDepth) {
1586                                         ValidateEndSimpleContent ();
1587                                         AssessStartElementSchemaValidity ();
1588                                 }
1589
1590                                 if (reader.IsEmptyElement)
1591                                         goto case XmlNodeType.EndElement;
1592                                 else
1593                                         shouldValidateCharacters = true;
1594                                 break;
1595                         case XmlNodeType.EndElement:
1596                                 if (reader.Depth == skipValidationDepth)
1597                                         skipValidationDepth = -1;
1598                                 else if (skipValidationDepth < 0 || reader.Depth <= skipValidationDepth)
1599                                         AssessEndElementSchemaValidity ();
1600
1601                                 if (checkKeyConstraints)
1602                                         elementQNameStack.RemoveAt (elementQNameStack.Count - 1);
1603                                 break;
1604
1605                         case XmlNodeType.CDATA:
1606                         case XmlNodeType.SignificantWhitespace:
1607                         case XmlNodeType.Whitespace:
1608                         case XmlNodeType.Text:
1609                                 // FIXME: does this check make sense?
1610                                 ComplexType ct = Context.ActualType as ComplexType;
1611                                 if (ct != null && storedCharacters.Length > 0) {
1612                                         switch (ct.ContentType) {
1613                                         case XmlSchemaContentType.ElementOnly:
1614                                         case XmlSchemaContentType.Empty:
1615                                                 if (reader.NodeType != XmlNodeType.Whitespace)
1616                                                         HandleError ("Not allowed character content was found.");
1617                                                 break;
1618                                         }
1619                                 }
1620
1621                                 ValidateCharacters ();
1622                                 break;
1623                         }
1624
1625                         return result;
1626                 }
1627
1628                 public override bool ReadAttributeValue ()
1629                 {
1630                         if (currentDefaultAttribute < 0)
1631                                 return reader.ReadAttributeValue ();
1632
1633                         if (this.defaultAttributeConsumed)
1634                                 return false;
1635
1636                         defaultAttributeConsumed = true;
1637                         return true;
1638                 }
1639
1640 #if NET_1_0
1641                 public override string ReadInnerXml ()
1642                 {
1643                         // MS.NET 1.0 has a serious bug here. It skips validation.
1644                         return reader.ReadInnerXml ();
1645                 }
1646
1647                 public override string ReadOuterXml ()
1648                 {
1649                         // MS.NET 1.0 has a serious bug here. It skips validation.
1650                         return reader.ReadOuterXml ();
1651                 }
1652 #endif
1653
1654                 // XmlReader.ReadString() should call derived this.Read().
1655                 public override string ReadString ()
1656                 {
1657 #if NET_1_0
1658                         return reader.ReadString ();
1659 #else
1660                         return base.ReadString ();
1661 #endif
1662                 }
1663
1664                 // This class itself does not have this feature.
1665                 public override void ResolveEntity ()
1666                 {
1667                         reader.ResolveEntity ();
1668                 }
1669         }
1670
1671         internal class XsdValidationContext
1672         {
1673                 public XsdValidationContext ()
1674                 {
1675                 }
1676
1677                 // Some of them might be missing (See the spec section 5.3, and also 3.3.4).
1678                 public XsElement Element;
1679                 public object XsiType; // xsi:type
1680                 internal XsdValidationState State;
1681
1682                 // Note that it represents current element's type.
1683                 public object ActualType {
1684                         get {
1685                                 if (XsiType != null)
1686                                         return XsiType;
1687                                 else
1688                                         return Element != null ? Element.ElementType : null;
1689                         }
1690                 }
1691
1692 #if NET_2_0
1693                 public XmlSchemaType ActualSchemaType {
1694                         get {
1695                                 object at = ActualType;
1696                                 if (at == null)
1697                                         return null;
1698                                 XmlSchemaType st = at as XmlSchemaType;
1699                                 if (st == null)
1700                                         st = XmlSchemaType.GetBuiltInSimpleType (
1701                                         ((XmlSchemaDatatype) at).TypeCode);
1702                                 return st;
1703                         }
1704                 }
1705 #endif
1706
1707                 public bool IsInvalid {
1708                         get { return State == XsdValidationState.Invalid; }
1709                 }
1710
1711                 public object Clone ()
1712                 {
1713                         return MemberwiseClone ();
1714                 }
1715
1716                 public void EvaluateStartElement (
1717                         string localName, string ns)
1718                 {
1719                         State = State.EvaluateStartElement (localName, ns);
1720                 }
1721
1722                 public bool EvaluateEndElement ()
1723                 {
1724                         return State.EvaluateEndElement ();
1725                 }
1726
1727                 public void SetElement (XsElement element)
1728                 {
1729                         Element = element;
1730                 }
1731         }
1732
1733         internal class XsdIDManager
1734         {
1735                 public XsdIDManager ()
1736                 {
1737                 }
1738
1739                 Hashtable idList = new Hashtable ();
1740                 ArrayList missingIDReferences;
1741                 string thisElementId;
1742
1743                 private ArrayList MissingIDReferences {
1744                         get {
1745                                 if (missingIDReferences == null)
1746                                         missingIDReferences = new ArrayList ();
1747                                 return missingIDReferences;
1748                         }
1749                 }
1750
1751                 public void OnStartElement ()
1752                 {
1753                         thisElementId = null;
1754                 }
1755
1756                 // 3.4.4-5 wild IDs
1757                 public string AssessEachAttributeIdentityConstraint (
1758                         XsDatatype dt, object parsedValue, string elementName)
1759                 {
1760                         // Validate identity constraints.
1761                         string str = parsedValue as string;
1762                         switch (dt.TokenizedType) {
1763                         case XmlTokenizedType.ID:
1764                                 if (thisElementId != null)
1765                                         return "ID type attribute was already assigned in the containing element.";
1766                                 else
1767                                         thisElementId = str;
1768                                 if (idList.ContainsKey (str))
1769                                         return "Duplicate ID value was found.";
1770                                 else
1771                                         idList.Add (str, elementName);
1772                                 if (MissingIDReferences.Contains (str))
1773                                         MissingIDReferences.Remove (str);
1774                                 break;
1775                         case XmlTokenizedType.IDREF:
1776                                 if (!idList.Contains (str))
1777                                         MissingIDReferences.Add (str);
1778                                 break;
1779                         case XmlTokenizedType.IDREFS:
1780                                 string [] idrefs = (string []) parsedValue;
1781                                 for (int i = 0; i < idrefs.Length; i++) {
1782                                         string id = idrefs [i];
1783                                         if (!idList.Contains (id))
1784                                                 MissingIDReferences.Add (id);
1785                                 }
1786                                 break;
1787                         }
1788                         return null;
1789                 }
1790
1791                 public bool HasMissingIDReferences ()
1792                 {
1793                         return missingIDReferences != null
1794                                 && missingIDReferences.Count > 0;
1795                 }
1796
1797                 public string GetMissingIDString ()
1798                 {
1799                         return String.Join (" ",
1800                                 MissingIDReferences.ToArray (typeof (string))
1801                                         as string []);
1802                 }
1803         }
1804 }