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