Merge pull request #439 from mono-soc-2012/garyb/iconfix
[mono.git] / mcs / class / System.XML / System.Xml.Schema / XmlSchemaValidator.cs
1 //
2 // XmlSchemaValidator.cs
3 //
4 // Author:
5 //      Atsushi Enomoto  <atsushi@xamarin.com>
6 //
7 // (C)2004 Novell Inc,
8 // Copyright (C) 2012 Xamarin Inc.
9 //
10
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 //
33 // LAMESPEC:
34 //      - There is no assurance that xsi:type precedes to any other attributes,
35 //        or xsi:type is not handled.
36 //      - There is no SourceUri provision.
37 //
38
39 #if NET_2_0
40
41 using System;
42 using System.Collections;
43 using System.IO;
44 using System.Text;
45 using System.Xml;
46 using Mono.Xml.Schema;
47
48 using QName = System.Xml.XmlQualifiedName;
49 using Form = System.Xml.Schema.XmlSchemaForm;
50 using Use = System.Xml.Schema.XmlSchemaUse;
51 using ContentType = System.Xml.Schema.XmlSchemaContentType;
52 using Validity = System.Xml.Schema.XmlSchemaValidity;
53 using ValidationFlags = System.Xml.Schema.XmlSchemaValidationFlags;
54 using ContentProc = System.Xml.Schema.XmlSchemaContentProcessing;
55 using SOMList = System.Xml.Schema.XmlSchemaObjectCollection;
56 using SOMObject = System.Xml.Schema.XmlSchemaObject;
57 using XsElement = System.Xml.Schema.XmlSchemaElement;
58 using XsAttribute = System.Xml.Schema.XmlSchemaAttribute;
59 using AttrGroup = System.Xml.Schema.XmlSchemaAttributeGroup;
60 using AttrGroupRef = System.Xml.Schema.XmlSchemaAttributeGroupRef;
61 using XsDatatype = System.Xml.Schema.XmlSchemaDatatype;
62 using SimpleType = System.Xml.Schema.XmlSchemaSimpleType;
63 using ComplexType = System.Xml.Schema.XmlSchemaComplexType;
64 using SimpleModel = System.Xml.Schema.XmlSchemaSimpleContent;
65 using SimpleExt = System.Xml.Schema.XmlSchemaSimpleContentExtension;
66 using SimpleRst = System.Xml.Schema.XmlSchemaSimpleContentRestriction;
67 using ComplexModel = System.Xml.Schema.XmlSchemaComplexContent;
68 using ComplexExt = System.Xml.Schema.XmlSchemaComplexContentExtension;
69 using ComplexRst = System.Xml.Schema.XmlSchemaComplexContentRestriction;
70 using SimpleTypeRest = System.Xml.Schema.XmlSchemaSimpleTypeRestriction;
71 using SimpleTypeList = System.Xml.Schema.XmlSchemaSimpleTypeList;
72 using SimpleTypeUnion = System.Xml.Schema.XmlSchemaSimpleTypeUnion;
73 using SchemaFacet = System.Xml.Schema.XmlSchemaFacet;
74 using LengthFacet = System.Xml.Schema.XmlSchemaLengthFacet;
75 using MinLengthFacet = System.Xml.Schema.XmlSchemaMinLengthFacet;
76 using Particle = System.Xml.Schema.XmlSchemaParticle;
77 using Sequence = System.Xml.Schema.XmlSchemaSequence;
78 using Choice = System.Xml.Schema.XmlSchemaChoice;
79 using ValException = System.Xml.Schema.XmlSchemaValidationException;
80
81
82 namespace System.Xml.Schema
83 {
84         public sealed class XmlSchemaValidator
85         {
86                 enum Transition {
87                         None,
88                         Content,
89                         StartTag,
90                         Finished
91                 }
92
93                 static readonly XsAttribute [] emptyAttributeArray =
94                         new XsAttribute [0];
95
96                 public XmlSchemaValidator (
97                         XmlNameTable nameTable,
98                         XmlSchemaSet schemas,
99                         IXmlNamespaceResolver namespaceResolver,
100                         ValidationFlags validationFlags)
101                 {
102                         this.nameTable = nameTable;
103                         this.schemas = schemas;
104                         this.nsResolver = namespaceResolver;
105                         this.options = validationFlags;
106                 }
107
108                 #region Fields
109
110                 // XmlReader/XPathNavigator themselves
111                 object nominalEventSender;
112                 IXmlLineInfo lineInfo;
113                 IXmlNamespaceResolver nsResolver;
114                 Uri sourceUri;
115
116                 // These fields will be from XmlReaderSettings or 
117                 // XPathNavigator.CheckValidity(). BTW, I think we could
118                 // implement XPathNavigator.CheckValidity() with
119                 // XsdValidatingReader.
120                 XmlNameTable nameTable;
121                 XmlSchemaSet schemas;
122                 XmlResolver xmlResolver = new XmlUrlResolver ();
123
124                 // "partialValidationType". but not sure how it will be used.
125                 SOMObject startType;
126
127                 // It is perhaps from XmlReaderSettings, but XPathNavigator
128                 // does not have it.
129                 ValidationFlags options;
130
131                 // Validation state
132                 bool initial = true;
133                 Transition transition;
134                 XsdParticleStateManager state;
135
136                 ArrayList occuredAtts = new ArrayList ();
137                 XsAttribute [] defaultAttributes = emptyAttributeArray;
138                 ArrayList defaultAttributesCache = new ArrayList ();
139
140 #region ID Constraints
141                 XsdIDManager idManager = new XsdIDManager ();
142 #endregion
143
144 #region Key Constraints
145                 ArrayList keyTables = new ArrayList ();
146                 ArrayList currentKeyFieldConsumers = new ArrayList ();
147                 ArrayList tmpKeyrefPool;
148 #endregion
149                 ArrayList elementQNameStack = new ArrayList ();
150
151                 StringBuilder storedCharacters = new StringBuilder ();
152                 bool shouldValidateCharacters;
153
154                 int depth;
155                 int xsiNilDepth = -1;
156                 int skipValidationDepth = -1;
157
158                 // LAMESPEC: XmlValueGetter is bogus by design because there
159                 // is no way to get associated schema type for current value.
160                 // Here XmlSchemaValidatingReader needs "current type"
161                 // information to validate attribute values.
162                 internal XmlSchemaDatatype CurrentAttributeType;
163
164                 XmlSchemaInfo current_info;
165
166                 #endregion
167
168                 #region Public properties
169
170                 // Settable Properties
171
172                 // IMHO It should just be an event that fires another event.
173                 public event ValidationEventHandler ValidationEventHandler;
174
175                 public object ValidationEventSender {
176                         get { return nominalEventSender; }
177                         set { nominalEventSender = value; }
178                 }
179
180                 // (kinda) Construction Properties
181
182                 public IXmlLineInfo LineInfoProvider {
183                         get { return lineInfo; }
184                         set { lineInfo = value; }
185                 }
186
187                 public XmlResolver XmlResolver {
188                         set { xmlResolver = value; }
189                 }
190
191                 public Uri SourceUri {
192                         get { return sourceUri; }
193                         set { sourceUri = value; }
194                 }
195                 #endregion
196
197                 #region Private properties
198
199                 private string BaseUri {
200                         get { return sourceUri != null ? sourceUri.AbsoluteUri : String.Empty; }
201                 }
202
203                 private XsdValidationContext Context {
204                         get { return state.Context; }
205                 }
206
207                 private bool IgnoreWarnings {
208                         get { return (options & ValidationFlags
209                                 .ReportValidationWarnings) == 0; }
210                 }
211
212                 private bool IgnoreIdentity {
213                         get { return (options & ValidationFlags
214                                 .ProcessIdentityConstraints) == 0; }
215                 }
216
217                 #endregion
218
219                 #region Public methods
220
221                 // State Monitor
222
223                 public XmlSchemaAttribute [] GetExpectedAttributes ()
224                 {
225                         ComplexType cType = Context.ActualType as ComplexType;
226                         if (cType == null)
227                                 return emptyAttributeArray;
228                         ArrayList al = new ArrayList ();
229                         foreach (DictionaryEntry entry in cType.AttributeUses)
230                                 if (!occuredAtts.Contains ((QName) entry.Key))
231                                         al.Add (entry.Value);
232                         return (XsAttribute [])
233                                 al.ToArray (typeof (XsAttribute));
234                 }
235
236                 private void CollectAtomicParticles (XmlSchemaParticle p,
237                         ArrayList al)
238                 {
239                         if (p is XmlSchemaGroupBase) {
240                                 foreach (XmlSchemaParticle c in 
241                                         ((XmlSchemaGroupBase) p).Items)
242                                         CollectAtomicParticles (c, al);
243                         }
244                         else
245                                 al.Add (p);
246                 }
247
248                 [MonoTODO] // Need some tests.
249                 // Its behavior is not obvious. For example, it does not
250                 // contain groups (xs:sequence/xs:choice/xs:all). Since it
251                 // might contain xs:any, it could not be of type element[].
252                 public XmlSchemaParticle [] GetExpectedParticles ()
253                 {
254                         ArrayList al = new ArrayList ();
255                         Context.State.GetExpectedParticles (al);
256                         ArrayList ret = new ArrayList ();
257
258                         foreach (XmlSchemaParticle p in al)
259                                 CollectAtomicParticles (p, ret);
260
261                         return (XmlSchemaParticle []) ret.ToArray (
262                                 typeof (XmlSchemaParticle));
263                 }
264
265                 public void GetUnspecifiedDefaultAttributes (ArrayList defaultAttributes)
266                 {
267                         if (defaultAttributes == null)
268                                 throw new ArgumentNullException ("defaultAttributes");
269
270                         if (transition != Transition.StartTag)
271                                 throw new InvalidOperationException ("Method 'GetUnsoecifiedDefaultAttributes' works only when the validator state is inside a start tag.");
272                         foreach (XmlSchemaAttribute attr
273                                 in GetExpectedAttributes ())
274                                 if (attr.ValidatedDefaultValue != null || attr.ValidatedFixedValue != null)
275                                         defaultAttributes.Add (attr);
276
277                         defaultAttributes.AddRange (defaultAttributes);
278                 }
279
280                 // State Controller
281
282                 public void AddSchema (XmlSchema schema)
283                 {
284                         if (schema == null)
285                                 throw new ArgumentNullException ("schema");
286                         schemas.Add (schema);
287                         schemas.Compile ();
288                 }
289
290                 public void Initialize ()
291                 {
292                         transition = Transition.Content;
293                         state = new XsdParticleStateManager ();
294                         if (!schemas.IsCompiled)
295                                 schemas.Compile ();
296                 }
297
298                 public void Initialize (SOMObject partialValidationType)
299                 {
300                         if (partialValidationType == null)
301                                 throw new ArgumentNullException ("partialValidationType");
302                         this.startType = partialValidationType;
303                         Initialize ();
304                 }
305
306                 // It must be called at the end of the validation (to check
307                 // identity constraints etc.).
308                 public void EndValidation ()
309                 {
310                         CheckState (Transition.Content);
311                         transition = Transition.Finished;
312
313                         if (schemas.Count == 0)
314                                 return;
315
316                         if (depth > 0)
317                                 throw new InvalidOperationException (String.Format ("There are {0} open element(s). ValidateEndElement() must be called for each open element.", depth));
318
319                         // 3.3.4 ElementLocallyValidElement 7 = Root Valid.
320                         if (!IgnoreIdentity &&
321                                 idManager.HasMissingIDReferences ())
322                                 HandleError ("There are missing ID references: " + idManager.GetMissingIDString ());
323                 }
324
325                 // I guess it is for validation error recovery
326                 [MonoTODO] // FIXME: Find out how XmlSchemaInfo is used.
327                 public void SkipToEndElement (XmlSchemaInfo schemaInfo)
328                 {
329                         CheckState (Transition.Content);
330                         if (schemas.Count == 0)
331                                 return;
332                         state.PopContext ();
333                 }
334
335                 public object ValidateAttribute (
336                         string localName,
337                         string namespaceUri,
338                         string attributeValue,
339                         XmlSchemaInfo schemaInfo)
340                 {
341                         if (attributeValue == null)
342                                 throw new ArgumentNullException ("attributeValue");
343                         return ValidateAttribute (localName, namespaceUri, delegate () { return attributeValue; }, schemaInfo);
344                 }
345
346                 // I guess this weird XmlValueGetter is for such case that
347                 // value might not be required (and thus it improves 
348                 // performance in some cases. Doh).
349
350                 // The return value is typed primitive, if possible.
351                 // AttDeriv
352                 public object ValidateAttribute (
353                         string localName,
354                         string namespaceUri,
355                         XmlValueGetter attributeValue,
356                         XmlSchemaInfo schemaInfo)
357                 {
358                         if (localName == null)
359                                 throw new ArgumentNullException ("localName");
360                         if (namespaceUri == null)
361                                 throw new ArgumentNullException ("namespaceUri");
362                         if (attributeValue == null)
363                                 throw new ArgumentNullException ("attributeValue");
364
365                         SetCurrentInfo (schemaInfo);
366                         try {
367
368                         bool wasInitial = initial;
369                         if (initial)
370                                 initial = false;
371                         else
372                                 CheckState (Transition.StartTag);
373
374                         QName qname = new QName (localName, namespaceUri);
375                         if (occuredAtts.Contains (qname))
376                                 throw new InvalidOperationException (String.Format ("Attribute '{0}' has already been validated in the same element.", qname));
377                         occuredAtts.Add (qname);
378
379                         if (namespaceUri == XmlNamespaceManager.XmlnsXmlns)
380                                 return null;
381
382                         if (schemas.Count == 0)
383                                 return null;
384
385                         if (wasInitial) {
386                                 var xa = startType as XmlSchemaAttribute;
387                                 if (xa == null)
388                                         return null;
389                                 return AssessAttributeLocallyValid (xa, schemaInfo, attributeValue);
390                         }
391
392                         if (Context.Element != null && Context.XsiType == null) {
393
394                                 // 3.3.4 Element Locally Valid (Type) - attribute
395                                 if (Context.ActualType is ComplexType)
396                                         return AssessAttributeElementLocallyValidType (localName, namespaceUri, attributeValue, schemaInfo);
397                                 else
398                                         HandleError ("Current simple type cannot accept attributes other than schema instance namespace.");
399                         }
400                         return null;
401                         
402                         } finally {
403                                 current_info = null;
404                         }
405                 }
406
407                 // StartTagOpenDeriv
408                 public void ValidateElement (
409                         string localName,
410                         string namespaceUri,
411                         XmlSchemaInfo schemaInfo)
412                 {
413                         ValidateElement (localName, namespaceUri, schemaInfo, null, null, null, null);
414                 }
415
416                 public void ValidateElement (
417                         string localName,
418                         string namespaceUri,
419                         XmlSchemaInfo schemaInfo,
420                         string xsiType,
421                         string xsiNil,
422                         string xsiSchemaLocation,
423                         string xsiNoNamespaceSchemaLocation)
424                 {
425                         if (localName == null)
426                                 throw new ArgumentNullException ("localName");
427                         if (namespaceUri == null)
428                                 throw new ArgumentNullException ("namespaceUri");
429                         SetCurrentInfo (schemaInfo);
430                         try {
431
432                         CheckState (Transition.Content);
433                         transition = Transition.StartTag;
434
435                         if (xsiSchemaLocation != null)
436                                 HandleSchemaLocation (xsiSchemaLocation);
437                         if (xsiNoNamespaceSchemaLocation != null)
438                                 HandleNoNSSchemaLocation (xsiNoNamespaceSchemaLocation);
439
440                         elementQNameStack.Add (new XmlQualifiedName (localName, namespaceUri));
441
442                         if (schemas.Count == 0)
443                                 return;
444
445 #region ID Constraints
446                         if (!IgnoreIdentity)
447                                 idManager.OnStartElement ();
448 #endregion
449                         defaultAttributes = emptyAttributeArray;
450
451                         // If there is no schema information, then no validation is performed.
452                         if (skipValidationDepth < 0 || depth <= skipValidationDepth) {
453                                 if (shouldValidateCharacters)
454                                         ValidateEndSimpleContent (null, null);
455
456                                 AssessOpenStartElementSchemaValidity (localName, namespaceUri);
457                         }
458
459                         if (xsiNil != null)
460                                 HandleXsiNil (xsiNil, schemaInfo);
461                         if (xsiType != null)
462                                 HandleXsiType (xsiType);
463
464                         if (xsiNilDepth < depth)
465                                 shouldValidateCharacters = true;
466
467                         if (schemaInfo != null) {
468                                 schemaInfo.IsNil = xsiNilDepth >= 0;
469                                 schemaInfo.SchemaElement = Context.Element;
470                                 schemaInfo.SchemaType = Context.ActualSchemaType;
471                                 schemaInfo.SchemaAttribute = null;
472                                 schemaInfo.IsDefault = false;
473                                 schemaInfo.MemberType = null;
474                                 // FIXME: supply Validity (really useful?)
475                         }
476
477                         } finally {
478                                 current_info = null;
479                         }
480                 }
481
482                 public object ValidateEndElement (XmlSchemaInfo schemaInfo)
483                 {
484                         return ValidateEndElement (schemaInfo, null);
485                 }
486
487                 // The return value is typed primitive, if supplied.
488                 // Parameter 'var' seems to be converted into the type
489                 // represented by current simple content type. (try passing
490                 // some kind of object to this method to check the behavior.)
491                 // EndTagDeriv
492                 public object ValidateEndElement (XmlSchemaInfo schemaInfo,
493                         object typedValue)
494                 {
495                         SetCurrentInfo (schemaInfo);
496                         try {
497
498                         // If it is going to validate an empty element, then
499                         // first validate end of attributes.
500                         if (transition == Transition.StartTag) {
501                                 current_info = null;
502                                 ValidateEndOfAttributes (schemaInfo);
503                         }
504
505                         CheckState (Transition.Content);
506
507                         elementQNameStack.RemoveAt (elementQNameStack.Count - 1);
508
509                         if (schemas.Count == 0)
510                                 return null;
511                         if (depth == 0)
512                                 throw new InvalidOperationException ("There was no corresponding call to 'ValidateElement' method.");
513
514                         depth--;
515
516                         object ret = null;
517                         if (depth == skipValidationDepth)
518                                 skipValidationDepth = -1;
519                         else if (skipValidationDepth < 0 || depth <= skipValidationDepth)
520                                 ret = AssessEndElementSchemaValidity (schemaInfo, typedValue);
521                         return ret;
522
523                         } finally {
524                                 current_info = null;
525                         }
526                 }
527
528                 // StartTagCloseDeriv
529                 // FIXME: fill validity inside this invocation.
530                 public void ValidateEndOfAttributes (XmlSchemaInfo schemaInfo)
531                 {
532                         try {
533                                 SetCurrentInfo (schemaInfo);
534
535                                 CheckState (Transition.StartTag);
536                                 transition = Transition.Content;
537                                 if (schemas.Count == 0)
538                                         return;
539
540                                 if (skipValidationDepth < 0 || depth <= skipValidationDepth)
541                                         AssessCloseStartElementSchemaValidity (schemaInfo);
542                                 depth++;
543                         } finally {
544                                 current_info = null;
545                                 occuredAtts.Clear ();
546                         }
547                 }
548
549                 // LAMESPEC: It should also receive XmlSchemaInfo so that
550                 // a validator application can receive simple type or
551                 // or content type validation errors.
552                 public void ValidateText (string elementValue)
553                 {
554                         if (elementValue == null)
555                                 throw new ArgumentNullException ("elementValue");
556                         ValidateText (delegate () { return elementValue; });
557                 }
558
559                 // TextDeriv ... without text. Maybe typed check is done by
560                 // ValidateAtomicValue().
561                 public void ValidateText (XmlValueGetter elementValue)
562                 {
563                         if (elementValue == null)
564                                 throw new ArgumentNullException ("elementValue");
565
566                         CheckState (Transition.Content);
567                         if (schemas.Count == 0)
568                                 return;
569
570                         if (skipValidationDepth >= 0 && depth > skipValidationDepth)
571                                 return;
572
573                         ComplexType ct = Context.ActualType as ComplexType;
574                         if (ct != null) {
575                                 switch (ct.ContentType) {
576                                 case XmlSchemaContentType.Empty:
577                                         HandleError ("Not allowed character content was found.");
578                                         break;
579                                 case XmlSchemaContentType.ElementOnly:
580                                         string s = storedCharacters.ToString ();
581                                         if (s.Length > 0 && !XmlChar.IsWhitespace (s))
582                                                 HandleError ("Not allowed character content was found.");
583                                         break;
584                                 }
585                         }
586
587                         ValidateCharacters (elementValue);
588                 }
589
590                 public void ValidateWhitespace (string elementValue)
591                 {
592                         if (elementValue == null)
593                                 throw new ArgumentNullException ("elementValue");
594                         ValidateWhitespace (delegate () { return elementValue; });
595                 }
596
597                 // TextDeriv. It should do the same as ValidateText() in our actual implementation (whitespaces are conditioned).
598                 public void ValidateWhitespace (XmlValueGetter elementValue)
599                 {
600                         ValidateText (elementValue);
601                 }
602
603                 #endregion
604
605                 #region Error handling
606
607                 private void HandleError (string message)
608                 {
609                         HandleError (message, null, false);
610                 }
611
612                 private void HandleError (
613                         string message, Exception innerException)
614                 {
615                         HandleError (message, innerException, false);
616                 }
617
618                 private void HandleError (string message,
619                         Exception innerException, bool isWarning)
620                 {
621                         if (current_info != null)
622                                 current_info.Validity = XmlSchemaValidity.Invalid;
623                         if (isWarning && IgnoreWarnings)
624                                 return;
625
626                         ValException vex = new ValException (
627                                 message, nominalEventSender, BaseUri,
628                                 null, innerException);
629                         HandleError (vex, isWarning);
630                 }
631
632                 private void HandleError (ValException exception)
633                 {
634                         HandleError (exception, false);
635                 }
636
637                 private void HandleError (ValException exception, bool isWarning)
638                 {
639                         if (current_info != null)
640                                 current_info.Validity = XmlSchemaValidity.Invalid;
641
642                         if (isWarning && IgnoreWarnings)
643                                 return;
644
645                         if (ValidationEventHandler == null)
646                                 throw exception;
647
648                         ValidationEventArgs e = new ValidationEventArgs (
649                                 exception,
650                                 exception.Message,
651                                 isWarning ? XmlSeverityType.Warning :
652                                         XmlSeverityType.Error);
653                         ValidationEventHandler (nominalEventSender, e);
654                 }
655
656                 #endregion
657
658                 // call this at entry point of every public method.
659                 private void SetCurrentInfo (XmlSchemaInfo info)
660                 {
661                         if (current_info != null)
662                                 throw new InvalidOperationException ("Not allowed concurrent call to validation method");
663                         current_info = info;
664                         if (info != null && info.Validity == XmlSchemaValidity.NotKnown)
665                                 current_info.Validity = XmlSchemaValidity.Valid;
666                 }
667
668                 private void CheckState (Transition expected)
669                 {
670                         initial = false;
671                         if (transition != expected) {
672                                 if (transition == Transition.None)
673                                         throw new InvalidOperationException ("Initialize() must be called before processing validation.");
674                                 else
675                                         throw new InvalidOperationException (
676                                                 String.Format ("Unexpected attempt to validate state transition from {0} to {1}.",
677                                                         transition,
678                                                         expected));
679                         }
680                 }
681
682                 private XsElement FindElement (string name, string ns)
683                 {
684                         return (XsElement) schemas.GlobalElements [new XmlQualifiedName (name, ns)];
685                 }
686
687                 private XmlSchemaType FindType (XmlQualifiedName qname)
688                 {
689                         return (XmlSchemaType) schemas.GlobalTypes [qname];
690                 }
691
692                 #region Type Validation
693
694                 private void ValidateStartElementParticle (
695                         string localName, string ns)
696                 {
697                         if (Context.State == null)
698                                 return;
699                         Context.XsiType = null;
700                         state.CurrentElement = null;
701                         Context.EvaluateStartElement (localName,
702                                 ns);
703                         if (Context.IsInvalid)
704                                 HandleError ("Invalid start element: " + ns + ":" + localName);
705
706                         Context.PushCurrentElement (state.CurrentElement);
707                 }
708
709                 private void AssessOpenStartElementSchemaValidity (
710                         string localName, string ns)
711                 {
712                         // If the reader is inside xsi:nil (and failed
713                         // on validation), then simply skip its content.
714                         if (xsiNilDepth >= 0 && xsiNilDepth < depth)
715                                 HandleError ("Element item appeared, while current element context is nil.");
716
717                         ValidateStartElementParticle (localName, ns);
718
719                         // Create Validation Root, if not exist.
720                         // [Schema Validity Assessment (Element) 1.1]
721                         if (Context.Element == null) {
722                                 state.CurrentElement = FindElement (localName, ns);
723                                 Context.PushCurrentElement (state.CurrentElement);
724                         }
725
726 #region Key Constraints
727                         if (!IgnoreIdentity) {
728                                 ValidateKeySelectors ();
729                                 ValidateKeyFields (false, xsiNilDepth == depth,
730                                         Context.ActualType, null, null, null);
731                         }
732 #endregion
733                 }
734
735                 private void AssessCloseStartElementSchemaValidity (XmlSchemaInfo info)
736                 {
737                         if (Context.XsiType != null)
738                                 AssessCloseStartElementLocallyValidType (info);
739                         else if (Context.Element != null) {
740                                 // element locally valid is checked only when
741                                 // xsi:type does not exist.
742                                 AssessElementLocallyValidElement ();
743                                 if (Context.Element.ElementType != null)
744                                         AssessCloseStartElementLocallyValidType (info);
745                         }
746
747                         if (Context.Element == null) {
748                                 switch (state.ProcessContents) {
749                                 case ContentProc.Skip:
750                                         break;
751                                 case ContentProc.Lax:
752                                         break;
753                                 default:
754                                         QName current = (QName) elementQNameStack [elementQNameStack.Count - 1];
755                                         if (Context.XsiType == null &&
756                                                 (schemas.Contains (current.Namespace) ||
757                                                 !schemas.MissedSubComponents (current.Namespace)))
758                                                 HandleError ("Element declaration for " + current + " is missing.");
759                                         break;
760                                 }
761                         }
762
763                         // Proceed to the next depth.
764
765                         state.PushContext ();
766
767                         XsdValidationState next = null;
768                         if (state.ProcessContents == ContentProc.Skip)
769                                 skipValidationDepth = depth;
770                         else {
771                                 // create child particle state.
772                                 ComplexType xsComplexType = Context.ActualType as ComplexType;
773                                 if (xsComplexType != null)
774                                         next = state.Create (xsComplexType.ValidatableParticle);
775                                 else if (state.ProcessContents == ContentProc.Lax)
776                                         next = state.Create (XmlSchemaAny.AnyTypeContent);
777                                 else
778                                         next = state.Create (XmlSchemaParticle.Empty);
779                         }
780                         Context.State = next;
781                 }
782
783                 // It must be invoked after xsi:nil turned out not to be in
784                 // this element.
785                 private void AssessElementLocallyValidElement ()
786                 {
787                         XsElement element = Context.Element;
788                         XmlQualifiedName qname = (XmlQualifiedName) elementQNameStack [elementQNameStack.Count - 1];
789                         // 1.
790                         if (element == null)
791                                 HandleError ("Element declaration is required for " + qname);
792                         // 2.
793                         if (element.ActualIsAbstract)
794                                 HandleError ("Abstract element declaration was specified for " + qname);
795                         // 3. is checked inside ValidateAttribute().
796                 }
797
798                 // 3.3.4 Element Locally Valid (Type)
799                 private void AssessCloseStartElementLocallyValidType (XmlSchemaInfo info)
800                 {
801                         object schemaType = Context.ActualType;
802                         if (schemaType == null) {       // 1.
803                                 HandleError ("Schema type does not exist.");
804                                 return;
805                         }
806                         ComplexType cType = schemaType as ComplexType;
807                         SimpleType sType = schemaType as SimpleType;
808                         if (sType != null) {
809                                 // 3.1.1.
810                                 // Attributes are checked in ValidateAttribute().
811                         } else if (cType != null) {
812                                 // 3.2. Also, 2. is checked there.
813                                 AssessCloseStartElementLocallyValidComplexType (cType, info);
814                         }
815                 }
816
817                 // 3.4.4 Element Locally Valid (Complex Type)
818                 // FIXME: use SchemaInfo for somewhere (? it is passed to ValidateEndOfAttributes() for some reason)
819                 private void AssessCloseStartElementLocallyValidComplexType (ComplexType cType, XmlSchemaInfo info)
820                 {
821                         // 1.
822                         if (cType.IsAbstract) {
823                                 HandleError ("Target complex type is abstract.");
824                                 return;
825                         }
826
827                         // 2 (xsi:nil and content prohibition)
828                         // See AssessStartElementSchemaValidity() and ValidateCharacters()
829                         // 3. attribute uses and  5. wild IDs are handled at
830                         // ValidateAttribute(), except for default/fixed values.
831
832                         // Collect default attributes.
833                         // 4.
834                         foreach (XsAttribute attr in GetExpectedAttributes ()) {
835                                 if (attr.ValidatedUse == XmlSchemaUse.Required && 
836                                         attr.ValidatedFixedValue == null)
837                                         HandleError ("Required attribute " + attr.QualifiedName + " was not found.");
838                                 else if (attr.ValidatedDefaultValue != null || attr.ValidatedFixedValue != null)
839                                         defaultAttributesCache.Add (attr);
840                         }
841                         if (defaultAttributesCache.Count == 0)
842                                 defaultAttributes = emptyAttributeArray;
843                         else
844                                 defaultAttributes = (XsAttribute []) 
845                                         defaultAttributesCache.ToArray (
846                                                 typeof (XsAttribute));
847                         defaultAttributesCache.Clear ();
848                         // 5. wild IDs was already checked at ValidateAttribute().
849
850                         // 3. - handle default attributes
851 #region ID Constraints
852                         if (!IgnoreIdentity) {
853                                 foreach (XsAttribute a in defaultAttributes) {
854                                         var atype = a.AttributeType as XmlSchemaDatatype ?? a.AttributeSchemaType.Datatype;
855                                         object avalue = a.ValidatedFixedValue ?? a.ValidatedDefaultValue;
856                                         string error = idManager.AssessEachAttributeIdentityConstraint (atype, avalue, ((QName) elementQNameStack [elementQNameStack.Count - 1]).Name);
857                                         if (error != null)
858                                                 HandleError (error);
859                                 }
860                         }
861 #endregion
862
863 #region Key Constraints
864                         if (!IgnoreIdentity)
865                                 foreach (XsAttribute a in defaultAttributes)
866                                         ValidateKeyFieldsAttribute (a, a.ValidatedFixedValue ?? a.ValidatedDefaultValue);
867 #endregion
868                 }
869
870                 private object AssessAttributeElementLocallyValidType (string localName, string ns, XmlValueGetter getter, XmlSchemaInfo info)
871                 {
872                         ComplexType cType = Context.ActualType as ComplexType;
873                         XmlQualifiedName qname = new XmlQualifiedName (localName, ns);
874                         // including 3.10.4 Item Valid (Wildcard)
875                         XmlSchemaObject attMatch = XmlSchemaUtil.FindAttributeDeclaration (ns, schemas, cType, qname);
876                         if (attMatch == null)
877                                 HandleError ("Attribute declaration was not found for " + qname);
878                         XsAttribute attdecl = attMatch as XsAttribute;
879                         if (attdecl != null) {
880                                 AssessAttributeLocallyValidUse (attdecl);
881                                 return AssessAttributeLocallyValid (attdecl, info, getter);
882                         } // otherwise anyAttribute or null.
883                         return null;
884                 }
885
886                 // 3.2.4 Attribute Locally Valid and 3.4.4
887                 private object AssessAttributeLocallyValid (XsAttribute attr, XmlSchemaInfo info, XmlValueGetter getter)
888                 {
889                         if (info != null) {
890                                 info.SchemaAttribute = attr;
891                                 info.SchemaType = attr.AttributeSchemaType;
892                         }
893
894                         // 2. - 4.
895                         if (attr.AttributeType == null)
896                                 HandleError ("Attribute type is missing for " + attr.QualifiedName);
897                         XsDatatype dt = attr.AttributeType as XsDatatype;
898                         if (dt == null)
899                                 dt = ((SimpleType) attr.AttributeType).Datatype;
900
901                         object parsedValue = null;
902
903                         // It is a bit heavy process, so let's omit as long as possible ;-)
904                         if (dt != SimpleType.AnySimpleType || attr.ValidatedFixedValue != null) {
905                                 try {
906                                         CurrentAttributeType = dt;
907                                         parsedValue = getter ();
908                                 } catch (Exception ex) { // It is inevitable and bad manner.
909                                         HandleError (String.Format ("Attribute value is invalid against its data type {0}", dt != null ? dt.TokenizedType : default (XmlTokenizedType)), ex);
910                                 }
911
912                                 // check part of 3.14.4 StringValid
913                                 SimpleType st = attr.AttributeSchemaType;
914                                 if (st != null) {
915                                         string xav = null;
916                                         try {
917                                                 xav = new XmlAtomicValue (parsedValue, attr.AttributeSchemaType).Value;
918                                         } catch (Exception ex) {
919                                                 HandleError (String.Format ("Failed to convert attribute value to type {0}", st.QualifiedName), ex);
920                                         }
921                                         if (xav != null)
922                                                 ValidateRestrictedSimpleTypeValue (st, ref dt, xav);
923                                 }
924
925                                 if (attr.ValidatedFixedValue != null) {
926                                         if (!XmlSchemaUtil.AreSchemaDatatypeEqual (attr.AttributeSchemaType, attr.ValidatedFixedTypedValue, attr.AttributeSchemaType, parsedValue))
927                                                 HandleError (String.Format ("The value of the attribute {0} does not match with its fixed value '{1}' in the space of type {2}", attr.QualifiedName, attr.ValidatedFixedValue, dt));
928                                         parsedValue = attr.ValidatedFixedTypedValue;
929                                 }
930                         }
931
932 #region ID Constraints
933                         if (!IgnoreIdentity) {
934                                 string error = idManager.AssessEachAttributeIdentityConstraint (dt, parsedValue, ((QName) elementQNameStack [elementQNameStack.Count - 1]).Name);
935                                 if (error != null)
936                                         HandleError (error);
937                         }
938 #endregion
939
940 #region Key Constraints
941                         if (!IgnoreIdentity)
942                                 ValidateKeyFieldsAttribute (attr, parsedValue);
943 #endregion
944
945                         return parsedValue;
946                 }
947
948                 private void AssessAttributeLocallyValidUse (XsAttribute attr)
949                 {
950                         // This is extra check than spec 3.5.4
951                         if (attr.ValidatedUse == XmlSchemaUse.Prohibited)
952                                 HandleError ("Attribute " + attr.QualifiedName + " is prohibited in this context.");
953                 }
954
955                 private object AssessEndElementSchemaValidity (
956                         XmlSchemaInfo info, object var)
957                 {
958                         object ret = ValidateEndSimpleContent (info, var);
959
960                         ValidateEndElementParticle ();  // validate against childrens' state.
961
962                         // 3.3.4 Assess ElementLocallyValidElement 5: value constraints.
963                         // 3.3.4 Assess ElementLocallyValidType 3.1.3. = StringValid(3.14.4)
964                         // => ValidateEndSimpleContent ().
965
966 #region Key Constraints
967                         if (!IgnoreIdentity)
968                                 ValidateEndElementKeyConstraints ();
969 #endregion
970
971                         // Reset xsi:nil, if required.
972                         if (xsiNilDepth == depth)
973                                 xsiNilDepth = -1;
974                         return ret;
975                 }
976
977                 private void ValidateEndElementParticle ()
978                 {
979                         if (Context.State != null) {
980                                 if (!Context.EvaluateEndElement ()) {
981                                         HandleError ("Invalid end element. There are still required content items.");
982                                 }
983                         }
984                         Context.PopCurrentElement ();
985                         state.PopContext ();
986                         Context.XsiType = null; // FIXME: this is hack. should be stacked as well as element.
987                 }
988
989                 // Utility for missing validation completion related to child items.
990                 private void ValidateCharacters (XmlValueGetter getter)
991                 {
992                         if (xsiNilDepth >= 0 && xsiNilDepth < depth)
993                                 HandleError ("Element item appeared, while current element context is nil.");
994
995                         if (shouldValidateCharacters) {
996                                 CurrentAttributeType = null;
997                                 storedCharacters.Append (getter ());
998                         }
999                 }
1000
1001
1002                 // Utility for missing validation completion related to child items.
1003                 private object ValidateEndSimpleContent (XmlSchemaInfo info, object var)
1004                 {
1005                         object ret = null;
1006                         if (shouldValidateCharacters)
1007                                 ret = ValidateEndSimpleContentCore (info, var);
1008                         shouldValidateCharacters = false;
1009                         storedCharacters.Length = 0;
1010                         return ret;
1011                 }
1012
1013                 private object ValidateEndSimpleContentCore (XmlSchemaInfo info, object var)
1014                 {
1015                         if (Context.ActualType == null)
1016                                 return null;
1017
1018                         XsDatatype dt = Context.ActualType as XsDatatype;
1019                         SimpleType st = Context.ActualType as SimpleType;
1020
1021                         XmlSchemaContentType contentType = XmlSchemaContentType.TextOnly;
1022
1023                         if (dt == null) {
1024                                 if (st != null) {
1025                                         dt = st.Datatype;
1026                                 } else {
1027                                         ComplexType ct = Context.ActualType as ComplexType;
1028                                         var ctsm = ct.ContentModel as XmlSchemaSimpleContent;
1029                                         if (ctsm != null) {
1030                                                 var scr = ctsm.Content as XmlSchemaSimpleContentRestriction;
1031                                                 if (scr != null)
1032                                                         st = FindSimpleBaseType (scr.BaseType ?? FindType (scr.BaseTypeName));
1033                                                 var sce = ctsm.Content as XmlSchemaSimpleContentExtension;
1034                                                 if (sce != null)
1035                                                         st = FindSimpleBaseType (FindType (sce.BaseTypeName));
1036                                         }
1037
1038                                         dt = ct.Datatype;
1039                                         contentType = ct.ContentType;
1040                                 }
1041                         }
1042
1043                         string value = var != null ? dt.ValueConverter.ToString (var) : storedCharacters.ToString ();
1044                         object ret = null;
1045
1046                         switch (contentType) {
1047                         case XmlSchemaContentType.ElementOnly:
1048                                 if (value.Length > 0 && !XmlChar.IsWhitespace (value))
1049                                         HandleError ("Character content not allowed in an elementOnly model.");
1050                                 break;
1051                         case XmlSchemaContentType.Empty:
1052                                 if (value.Length > 0)
1053                                         HandleError ("Character content not allowed in an empty model.");
1054                                 break;
1055                         }
1056
1057                         if (value.Length == 0) {
1058                                 // 3.3.4 Element Locally Valid (Element) 5.1.2
1059                                 if (Context.Element != null) {
1060                                         if (Context.Element.ValidatedDefaultValue != null)
1061                                                 value = Context.Element.ValidatedDefaultValue;
1062                                 }                                       
1063                         }
1064
1065                         if (dt != null) {
1066                                 // 3.3.4 Element Locally Valid (Element) :: 5.2.2.2. Fixed value constraints
1067                                 if (Context.Element != null && Context.Element.ValidatedFixedValue != null)
1068                                         if (value != Context.Element.ValidatedFixedValue)
1069                                                 HandleError ("Fixed value constraint was not satisfied.");
1070                                 ret = AssessStringValid (st, dt, value);
1071                         }
1072
1073 #region Key Constraints
1074                         if (!IgnoreIdentity)
1075                                 ValidateSimpleContentIdentity (dt, value);
1076 #endregion
1077
1078                         shouldValidateCharacters = false;
1079
1080                         if (info != null) {
1081                                 info.IsNil = xsiNilDepth >= 0;
1082                                 info.SchemaElement = null;
1083                                 info.SchemaType = Context.ActualType as XmlSchemaType;
1084                                 if (info.SchemaType == null)
1085                                         info.SchemaType = XmlSchemaType.GetBuiltInSimpleType (dt.TypeCode);
1086                                 info.SchemaAttribute = null;
1087                                 info.IsDefault = false; // FIXME: might be true
1088                                 info.MemberType = null; // FIXME: check
1089                                 // FIXME: supply Validity (really useful?)
1090                         }
1091
1092                         return ret;
1093                 }
1094
1095                 SimpleType FindSimpleBaseType (XmlSchemaType xt)
1096                 {
1097                         var st = xt as SimpleType;
1098                         if (st != null)
1099                                 return st;
1100                         if (xt == null)
1101                                 return null;
1102                         return FindSimpleBaseType (xt.BaseXmlSchemaType);
1103                 }
1104
1105                 // 3.14.4 String Valid 
1106                 private object AssessStringValid (SimpleType st,
1107                         XsDatatype dt, string value)
1108                 {
1109                         XsDatatype validatedDatatype = dt;
1110                         object ret = null;
1111                         if (st != null) {
1112                                 string normalized = validatedDatatype.Normalize (value);
1113                                 string [] values;
1114                                 XsDatatype itemDatatype;
1115                                 SimpleType itemSimpleType;
1116                                 switch (st.DerivedBy) {
1117                                 case XmlSchemaDerivationMethod.List:
1118                                         SimpleTypeList listContent = st.Content as SimpleTypeList;
1119                                         values = normalized.Split (XmlChar.WhitespaceChars);
1120                                         // LAMESPEC: Types of each element in
1121                                         // the returned list might be 
1122                                         // inconsistent, so basically returning 
1123                                         // value does not make sense without 
1124                                         // explicit runtime type information 
1125                                         // for base primitive type.
1126                                         object [] retValues = new object [values.Length];
1127                                         itemDatatype = listContent.ValidatedListItemType as XsDatatype;
1128                                         itemSimpleType = listContent.ValidatedListItemType as SimpleType;
1129                                         for (int vi = 0; vi < values.Length; vi++) {
1130                                                 string each = values [vi];
1131                                                 if (each == String.Empty)
1132                                                         continue;
1133                                                 // validate against ValidatedItemType
1134                                                 if (itemDatatype != null) {
1135                                                         try {
1136                                                                 retValues [vi] = itemDatatype.ParseValue (each, nameTable, nsResolver);
1137                                                         } catch (Exception ex) { // It is inevitable and bad manner.
1138                                                                 HandleError ("List type value contains one or more invalid values.", ex);
1139                                                                 break;
1140                                                         }
1141                                                 }
1142                                                 else
1143                                                         AssessStringValid (itemSimpleType, itemSimpleType.Datatype, each);
1144                                         }
1145                                         ret = retValues;
1146                                         break;
1147                                 case XmlSchemaDerivationMethod.Union:
1148                                         SimpleTypeUnion union = st.Content as SimpleTypeUnion;
1149                                         {
1150                                                 string each = normalized;
1151                                                 // validate against ValidatedItemType
1152                                                 bool passed = false;
1153                                                 foreach (object eachType in union.ValidatedTypes) {
1154                                                         itemDatatype = eachType as XsDatatype;
1155                                                         itemSimpleType = eachType as SimpleType;
1156                                                         if (itemDatatype != null) {
1157                                                                 try {
1158                                                                         ret = itemDatatype.ParseValue (each, nameTable, nsResolver);
1159                                                                 } catch (Exception) { // It is inevitable and bad manner.
1160                                                                         continue;
1161                                                                 }
1162                                                         }
1163                                                         else {
1164                                                                 try {
1165                                                                         ret = AssessStringValid (itemSimpleType, itemSimpleType.Datatype, each);
1166                                                                 } catch (ValException) {
1167                                                                         continue;
1168                                                                 }
1169                                                         }
1170                                                         passed = true;
1171                                                         break;
1172                                                 }
1173                                                 if (!passed) {
1174                                                         HandleError ("Union type value contains one or more invalid values.");
1175                                                         break;
1176                                                 }
1177                                         }
1178                                         break;
1179                                 case XmlSchemaDerivationMethod.Restriction:
1180                                         SimpleTypeRest str = st.Content as SimpleTypeRest;
1181                                         // facet validation
1182                                         if (str != null) {
1183                                                 /* Don't forget to validate against inherited type's facets 
1184                                                  * Could we simplify this by assuming that the basetype will also
1185                                                  * be restriction?
1186                                                  * */
1187                                                  // mmm, will check later.
1188                                                 SimpleType baseType = st.BaseXmlSchemaType as SimpleType;
1189                                                 if (baseType != null) {
1190                                                          ret = AssessStringValid (baseType, dt, value);
1191                                                 }
1192                                                 if (!str.ValidateValueWithFacets (value, nameTable, nsResolver)) {
1193                                                         HandleError ("Specified value was invalid against the facets.");
1194                                                         break;
1195                                                 }
1196                                         }
1197                                         validatedDatatype = st.Datatype;
1198                                         break;
1199                                 }
1200                         }
1201                         if (validatedDatatype != null) {
1202                                 try {
1203                                         ret = validatedDatatype.ParseValue (value, nameTable, nsResolver);
1204                                 } catch (Exception ex) { // It is inevitable and bad manner.
1205                                         HandleError ("Invalidly typed data was specified", ex);
1206                                 }
1207                         }
1208                         return ret;
1209                 }
1210
1211                 private void ValidateRestrictedSimpleTypeValue (SimpleType st, ref XsDatatype dt, string normalized)
1212                 {
1213                         {
1214                                 string [] values;
1215                                 XsDatatype itemDatatype;
1216                                 SimpleType itemSimpleType;
1217                                 switch (st.DerivedBy) {
1218                                 case XmlSchemaDerivationMethod.List:
1219                                         SimpleTypeList listContent = st.Content as SimpleTypeList;
1220                                         values = normalized.Split (XmlChar.WhitespaceChars);
1221                                         itemDatatype = listContent.ValidatedListItemType as XsDatatype;
1222                                         itemSimpleType = listContent.ValidatedListItemType as SimpleType;
1223                                         for (int vi = 0; vi < values.Length; vi++) {
1224                                                 string each = values [vi];
1225                                                 if (each == String.Empty)
1226                                                         continue;
1227                                                 // validate against ValidatedItemType
1228                                                 if (itemDatatype != null) {
1229                                                         try {
1230                                                                 itemDatatype.ParseValue (each, nameTable, nsResolver);
1231                                                         } catch (Exception ex) { // FIXME: (wishlist) better exception handling ;-(
1232                                                                 HandleError ("List type value contains one or more invalid values.", ex);
1233                                                                 break;
1234                                                         }
1235                                                 }
1236                                                 else
1237                                                         AssessStringValid (itemSimpleType, itemSimpleType.Datatype, each);
1238                                         }
1239                                         break;
1240                                 case XmlSchemaDerivationMethod.Union:
1241                                         SimpleTypeUnion union = st.Content as SimpleTypeUnion;
1242                                         {
1243                                                 string each = normalized;
1244                                                 // validate against ValidatedItemType
1245                                                 bool passed = false;
1246                                                 foreach (object eachType in union.ValidatedTypes) {
1247                                                         itemDatatype = eachType as XsDatatype;
1248                                                         itemSimpleType = eachType as SimpleType;
1249                                                         if (itemDatatype != null) {
1250                                                                 try {
1251                                                                         itemDatatype.ParseValue (each, nameTable, nsResolver);
1252                                                                 } catch (Exception) { // FIXME: (wishlist) better exception handling ;-(
1253                                                                         continue;
1254                                                                 }
1255                                                         }
1256                                                         else {
1257                                                                 try {
1258                                                                         AssessStringValid (itemSimpleType, itemSimpleType.Datatype, each);
1259                                                                 } catch (ValException) {
1260                                                                         continue;
1261                                                                 }
1262                                                         }
1263                                                         passed = true;
1264                                                         break;
1265                                                 }
1266                                                 if (!passed) {
1267                                                         HandleError ("Union type value contains one or more invalid values.");
1268                                                         break;
1269                                                 }
1270                                         }
1271                                         break;
1272                                 case XmlSchemaDerivationMethod.Restriction:
1273                                         SimpleTypeRest str = st.Content as SimpleTypeRest;
1274                                         // facet validation
1275                                         if (str != null) {
1276                                                 /* Don't forget to validate against inherited type's facets 
1277                                                  * Could we simplify this by assuming that the basetype will also
1278                                                  * be restriction?
1279                                                  * */
1280                                                  // mmm, will check later.
1281                                                 SimpleType baseType = st.BaseXmlSchemaType as SimpleType;
1282                                                 if (baseType != null) {
1283                                                          AssessStringValid(baseType, dt, normalized);
1284                                                 }
1285                                                 if (!str.ValidateValueWithFacets (normalized, nameTable, nsResolver)) {
1286                                                         HandleError ("Specified value was invalid against the facets.");
1287                                                         break;
1288                                                 }
1289                                         }
1290                                         dt = st.Datatype;
1291                                         break;
1292                                 }
1293                         }
1294                 }
1295
1296                 #endregion
1297
1298                 #region Key Constraints Validation
1299                 private XsdKeyTable CreateNewKeyTable (XmlSchemaIdentityConstraint ident)
1300                 {
1301                         XsdKeyTable seq = new XsdKeyTable (ident);
1302                         seq.StartDepth = depth;
1303                         this.keyTables.Add (seq);
1304                         return seq;
1305                 }
1306
1307                 // 3.11.4 Identity Constraint Satisfied
1308                 private void ValidateKeySelectors ()
1309                 {
1310                         if (tmpKeyrefPool != null)
1311                                 tmpKeyrefPool.Clear ();
1312                         if (Context.Element != null && Context.Element.Constraints.Count > 0) {
1313                                 // (a) Create new key sequences, if required.
1314                                 for (int i = 0; i < Context.Element.Constraints.Count; i++) {
1315                                         XmlSchemaIdentityConstraint ident = (XmlSchemaIdentityConstraint) Context.Element.Constraints [i];
1316                                         XsdKeyTable seq = CreateNewKeyTable (ident);
1317                                         if (ident is XmlSchemaKeyref) {
1318                                                 if (tmpKeyrefPool == null)
1319                                                         tmpKeyrefPool = new ArrayList ();
1320                                                 tmpKeyrefPool.Add (seq);
1321                                         }
1322                                 }
1323                         }
1324
1325                         // (b) Evaluate current key sequences.
1326                         for (int i = 0; i < keyTables.Count; i++) {
1327                                 XsdKeyTable seq  = (XsdKeyTable) keyTables [i];
1328                                 if (seq.SelectorMatches (this.elementQNameStack, depth) != null) {
1329                                         // creates and registers new entry.
1330                                         XsdKeyEntry entry = new XsdKeyEntry (seq, depth, lineInfo);
1331                                         seq.Entries.Add (entry);
1332                                 }
1333                         }
1334                 }
1335
1336                 private void ValidateKeyFieldsAttribute (XsAttribute attr, object value)
1337                 {
1338                         ValidateKeyFields (true, false, attr.AttributeType, attr.QualifiedName.Name, attr.QualifiedName.Namespace, value);
1339                 }
1340
1341                 private void ValidateKeyFields (bool isAttr, bool isNil, object schemaType, string attrName, string attrNs, object value)
1342                 {
1343                         // (c) Evaluate field paths.
1344                         for (int i = 0; i < keyTables.Count; i++) {
1345                                 XsdKeyTable seq  = (XsdKeyTable) keyTables [i];
1346                                 // If possible, create new field entry candidates.
1347                                 for (int j = 0; j < seq.Entries.Count; j++) {
1348                                         CurrentAttributeType = null;
1349                                         try {
1350                                                 seq.Entries [j].ProcessMatch (
1351                                                         isAttr,
1352                                                         elementQNameStack,
1353                                                         nominalEventSender,
1354                                                         nameTable,
1355                                                         BaseUri,
1356                                                         schemaType,
1357                                                         nsResolver,
1358                                                         lineInfo,
1359                                                         isAttr ? depth + 1 : depth,
1360                                                         attrName,
1361                                                         attrNs,
1362                                                         value,
1363                                                         isNil, 
1364                                                         currentKeyFieldConsumers);
1365                                         } catch (ValException ex) {
1366                                                 HandleError (ex);
1367                                         }
1368                                 }
1369                         }
1370                 }
1371
1372                 private void ValidateEndElementKeyConstraints ()
1373                 {
1374                         // Reset Identity constraints.
1375                         for (int i = 0; i < keyTables.Count; i++) {
1376                                 XsdKeyTable seq = this.keyTables [i] as XsdKeyTable;
1377                                 if (seq.StartDepth == depth) {
1378                                         ValidateEndKeyConstraint (seq);
1379                                 } else {
1380                                         for (int k = 0; k < seq.Entries.Count; k++) {
1381                                                 XsdKeyEntry entry = seq.Entries [k] as XsdKeyEntry;
1382                                                 // Remove finished (maybe key not found) entries.
1383                                                 if (entry.StartDepth == depth) {
1384                                                         if (entry.KeyFound)
1385                                                                 seq.FinishedEntries.Add (entry);
1386                                                         else if (seq.SourceSchemaIdentity is XmlSchemaKey)
1387                                                                 HandleError ("Key sequence is missing.");
1388                                                         seq.Entries.RemoveAt (k);
1389                                                         k--;
1390                                                 }
1391                                                 // Pop validated key depth to find two or more fields.
1392                                                 else {
1393                                                         for (int j = 0; j < entry.KeyFields.Count; j++) {
1394                                                                 XsdKeyEntryField kf = entry.KeyFields [j];
1395                                                                 if (!kf.FieldFound && kf.FieldFoundDepth == depth) {
1396                                                                         kf.FieldFoundDepth = 0;
1397                                                                         kf.FieldFoundPath = null;
1398                                                                 }
1399                                                         }
1400                                                 }
1401                                         }
1402                                 }
1403                         }
1404                         for (int i = 0; i < keyTables.Count; i++) {
1405                                 XsdKeyTable seq = this.keyTables [i] as XsdKeyTable;
1406                                 if (seq.StartDepth == depth) {
1407                                         keyTables.RemoveAt (i);
1408                                         i--;
1409                                 }
1410                         }
1411                 }
1412
1413                 private void ValidateEndKeyConstraint (XsdKeyTable seq)
1414                 {
1415                         ArrayList errors = new ArrayList ();
1416                         for (int i = 0; i < seq.Entries.Count; i++) {
1417                                 XsdKeyEntry entry = (XsdKeyEntry) seq.Entries [i];
1418                                 if (entry.KeyFound)
1419                                         continue;
1420                                 if (seq.SourceSchemaIdentity is XmlSchemaKey)
1421                                         errors.Add ("line " + entry.SelectorLineNumber + "position " + entry.SelectorLinePosition);
1422                         }
1423                         if (errors.Count > 0)
1424                                 HandleError ("Invalid identity constraints were found. Key was not found. "
1425                                         + String.Join (", ", errors.ToArray (typeof (string)) as string []));
1426
1427                         errors.Clear ();
1428                         // Find reference target
1429                         XmlSchemaKeyref xsdKeyref = seq.SourceSchemaIdentity as XmlSchemaKeyref;
1430                         if (xsdKeyref != null) {
1431                                 for (int i = this.keyTables.Count - 1; i >= 0; i--) {
1432                                         XsdKeyTable target = this.keyTables [i] as XsdKeyTable;
1433                                         if (target.SourceSchemaIdentity == xsdKeyref.Target) {
1434                                                 seq.ReferencedKey = target;
1435                                                 for (int j = 0; j < seq.FinishedEntries.Count; j++) {
1436                                                         XsdKeyEntry entry = (XsdKeyEntry) seq.FinishedEntries [j];
1437                                                         for (int k = 0; k < target.FinishedEntries.Count; k++) {
1438                                                                 XsdKeyEntry targetEntry = (XsdKeyEntry) target.FinishedEntries [k];
1439                                                                 if (entry.CompareIdentity (targetEntry)) {
1440                                                                         entry.KeyRefFound = true;
1441                                                                         break;
1442                                                                 }
1443                                                         }
1444                                                 }
1445                                         }
1446                                 }
1447                                 if (seq.ReferencedKey == null)
1448                                         HandleError ("Target key was not found.");
1449                                 for (int i = 0; i < seq.FinishedEntries.Count; i++) {
1450                                         XsdKeyEntry entry = (XsdKeyEntry) seq.FinishedEntries [i];
1451                                         if (!entry.KeyRefFound)
1452                                                 errors.Add (" line " + entry.SelectorLineNumber + ", position " + entry.SelectorLinePosition);
1453                                 }
1454                                 if (errors.Count > 0)
1455                                         HandleError ("Invalid identity constraints were found. Referenced key was not found: "
1456                                                 + String.Join (" / ", errors.ToArray (typeof (string)) as string []));
1457                         }
1458                 }
1459
1460                 private void ValidateSimpleContentIdentity (
1461                         XmlSchemaDatatype dt, string value)
1462                 {
1463                         // Identity field value
1464                         if (currentKeyFieldConsumers != null) {
1465                                 while (this.currentKeyFieldConsumers.Count > 0) {
1466                                         XsdKeyEntryField field = this.currentKeyFieldConsumers [0] as XsdKeyEntryField;
1467                                         if (field.Identity != null)
1468                                                 HandleError ("Two or more identical field was found. Former value is '" + field.Identity + "' .");
1469                                         object identity = null; // This means empty value
1470                                         if (dt != null) {
1471                                                 try {
1472                                                         identity = dt.ParseValue (value, nameTable, nsResolver);
1473                                                 } catch (Exception ex) { // It is inevitable and bad manner.
1474                                                         HandleError ("Identity value is invalid against its data type " + dt.TokenizedType, ex);
1475                                                 }
1476                                         }
1477                                         if (identity == null)
1478                                                 identity = value;
1479
1480                                         if (!field.SetIdentityField (identity, depth == xsiNilDepth, dt as XsdAnySimpleType, depth, lineInfo))
1481                                                 HandleError ("Two or more identical key value was found: '" + value + "' .");
1482                                         this.currentKeyFieldConsumers.RemoveAt (0);
1483                                 }
1484                         }
1485                 }
1486                 #endregion
1487
1488                 #region xsi:type
1489                 private object GetXsiType (string name)
1490                 {
1491                         object xsiType = null;
1492                         XmlQualifiedName typeQName =
1493                                 XmlQualifiedName.Parse (name, nsResolver, true);
1494                         if (typeQName == ComplexType.AnyTypeName)
1495                                 xsiType = ComplexType.AnyType;
1496                         else if (XmlSchemaUtil.IsBuiltInDatatypeName (typeQName))
1497                                 xsiType = XsDatatype.FromName (typeQName);
1498                         else
1499                                 xsiType = FindType (typeQName);
1500                         return xsiType;
1501                 }
1502
1503                 private void HandleXsiType (string typename)
1504                 {
1505                         XsElement element = Context.Element;
1506                         object xsiType = GetXsiType (typename);
1507                         if (xsiType == null) {
1508                                 HandleError ("The instance type was not found: " + typename);
1509                                 return;
1510                         }
1511                         XmlSchemaType xsiSchemaType = xsiType as XmlSchemaType;
1512                         if (xsiSchemaType != null && Context.Element != null) {
1513                                 XmlSchemaType elemBaseType = element.ElementType as XmlSchemaType;
1514                                 if (elemBaseType != null && (xsiSchemaType.DerivedBy & elemBaseType.FinalResolved) != 0)
1515                                         HandleError ("The instance type is prohibited by the type of the context element.");
1516                                 if (elemBaseType != xsiType && (xsiSchemaType.DerivedBy & element.BlockResolved) != 0)
1517                                         HandleError ("The instance type is prohibited by the context element.");
1518                         }
1519                         ComplexType xsiComplexType = xsiType as ComplexType;
1520                         if (xsiComplexType != null && xsiComplexType.IsAbstract)
1521                                 HandleError ("The instance type is abstract: " + typename);
1522                         else {
1523                                 // If current schema type exists, then this xsi:type must be
1524                                 // valid extension of that type. See 1.2.1.2.4.
1525                                 if (element != null) {
1526                                         AssessLocalTypeDerivationOK (xsiType, element.ElementType, element.BlockResolved);
1527                                 }
1528                                 // See also ValidateEndOfAttributes().
1529                                 Context.XsiType = xsiType;
1530                         }
1531                 }
1532
1533                 // It is common to ElementLocallyValid::4 and SchemaValidityAssessment::1.2.1.2.4
1534                 private void AssessLocalTypeDerivationOK (object xsiType, object baseType, XmlSchemaDerivationMethod flag)
1535                 {
1536                         XmlSchemaType xsiSchemaType = xsiType as XmlSchemaType;
1537                         ComplexType baseComplexType = baseType as ComplexType;
1538                         ComplexType xsiComplexType = xsiSchemaType as ComplexType;
1539                         if (xsiType != baseType) {
1540                                 // Extracted (not extraneous) check for 3.4.6 TypeDerivationOK.
1541                                 if (baseComplexType != null)
1542                                         flag |= baseComplexType.BlockResolved;
1543                                 if (flag == XmlSchemaDerivationMethod.All) {
1544                                         HandleError ("Prohibited element type substitution.");
1545                                         return;
1546                                 } else if (xsiSchemaType != null && (flag & xsiSchemaType.DerivedBy) != 0) {
1547                                         HandleError ("Prohibited element type substitution.");
1548                                         return;
1549                                 }
1550                         }
1551
1552                         if (xsiComplexType != null)
1553                                 try {
1554                                         xsiComplexType.ValidateTypeDerivationOK (baseType, null, null);
1555                                 } catch (ValException ex) {
1556                                         HandleError (ex);
1557                                 }
1558                         else {
1559                                 SimpleType xsiSimpleType = xsiType as SimpleType;
1560                                 if (xsiSimpleType != null) {
1561                                         try {
1562                                                 xsiSimpleType.ValidateTypeDerivationOK (baseType, null, null, true);
1563                                         } catch (ValException ex) {
1564                                                 HandleError (ex);
1565                                         }
1566                                 }
1567                                 else if (xsiType is XsDatatype) {
1568                                         // do nothing
1569                                 }
1570                                 else
1571                                         HandleError ("Primitive data type cannot be derived type using xsi:type specification.");
1572                         }
1573                 }
1574                 #endregion
1575
1576                 private void HandleXsiNil (string value, XmlSchemaInfo info)
1577                 {
1578                         XsElement element = Context.Element;
1579                         if (!element.ActualIsNillable) {
1580                                 HandleError (String.Format ("Current element '{0}' is not nillable and thus does not allow occurence of 'nil' attribute.", Context.Element.QualifiedName));
1581                                 return;
1582                         }
1583                         value = value.Trim (XmlChar.WhitespaceChars);
1584                         // 3.2.
1585                         // Note that 3.2.1 xsi:nil constraints are to be 
1586                         // validated in AssessElementSchemaValidity() and 
1587                         // ValidateCharacters().
1588                         if (value == "true") {
1589                                 if (element.ValidatedFixedValue != null)
1590                                         HandleError ("Schema instance nil was specified, where the element declaration for " + element.QualifiedName + "has fixed value constraints.");
1591                                 xsiNilDepth = depth;
1592                                 if (info != null)
1593                                         info.IsNil = true;
1594                         }
1595                 }
1596
1597                 #region External schema resolution
1598
1599                 private XmlSchema ReadExternalSchema (string uri)
1600                 {
1601                         Uri absUri = new Uri (SourceUri, uri.Trim (XmlChar.WhitespaceChars));
1602                         XmlTextReader xtr = null;
1603                         try {
1604                                 xtr = new XmlTextReader (absUri.ToString (),
1605                                         (Stream) xmlResolver.GetEntity (
1606                                                 absUri, null, typeof (Stream)),
1607                                         nameTable);
1608                                 return XmlSchema.Read (
1609                                         xtr, ValidationEventHandler);
1610                         } finally {
1611                                 if (xtr != null)
1612                                         xtr.Close ();
1613                         }
1614                 }
1615
1616                 private void HandleSchemaLocation (string schemaLocation)
1617                 {
1618                         if (xmlResolver == null)
1619                                 return;
1620                         XmlSchema schema = null;
1621                         bool schemaAdded = false;
1622                         string [] tmp = null;
1623                         try {
1624                                 schemaLocation = XmlSchemaType.GetBuiltInSimpleType (XmlTypeCode.Token).Datatype.ParseValue (schemaLocation, null, null) as string;
1625                                 tmp = schemaLocation.Split (XmlChar.WhitespaceChars);
1626                         } catch (Exception ex) {
1627                                 HandleError ("Invalid schemaLocation attribute format.", ex, true);
1628                                 tmp = new string [0];
1629                         }
1630                         if (tmp.Length % 2 != 0)
1631                                 HandleError ("Invalid schemaLocation attribute format.");
1632                         for (int i = 0; i < tmp.Length; i += 2) {
1633                                 try {
1634                                         schema = ReadExternalSchema (tmp [i + 1]);
1635                                 } catch (Exception ex) { // It is inevitable and bad manner.
1636                                         HandleError ("Could not resolve schema location URI: " + schemaLocation, ex, true);
1637                                         continue;
1638                                 }
1639                                 if (schema.TargetNamespace == null)
1640                                         schema.TargetNamespace = tmp [i];
1641                                 else if (schema.TargetNamespace != tmp [i])
1642                                         HandleError ("Specified schema has different target namespace.");
1643
1644                                 if (schema != null) {
1645                                         if (!schemas.Contains (schema.TargetNamespace)) {
1646                                                 schemaAdded = true;
1647                                                 schemas.Add (schema);
1648                                         }
1649                                 }
1650                         }
1651                         if (schemaAdded)
1652                                 schemas.Compile ();
1653                 }
1654
1655                 private void HandleNoNSSchemaLocation (string noNsSchemaLocation)
1656                 {
1657                         if (xmlResolver == null)
1658                                 return;
1659                         XmlSchema schema = null;
1660                         bool schemaAdded = false;
1661
1662                         try {
1663                                 schema = ReadExternalSchema (noNsSchemaLocation);
1664                         } catch (Exception ex) { // It is inevitable and bad manner.
1665                                 HandleError ("Could not resolve schema location URI: " + noNsSchemaLocation, ex, true);
1666                         }
1667                         if (schema != null && schema.TargetNamespace != null)
1668                                 HandleError ("Specified schema has different target namespace.");
1669
1670                         if (schema != null) {
1671                                 if (!schemas.Contains (schema.TargetNamespace)) {
1672                                         schemaAdded = true;
1673                                         schemas.Add (schema);
1674                                 }
1675                         }
1676                         if (schemaAdded)
1677                                 schemas.Compile ();
1678                 }
1679
1680                 #endregion
1681         }
1682 }
1683
1684 #endif