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