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