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