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