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