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