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