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