2 // Mono.Xml.Schema.XsdValidatingReader.cs
5 // Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
7 // (C)2003 Atsushi Enomoto
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System.Collections;
33 using System.Collections.Generic;
35 using System.Collections.Specialized;
39 using System.Xml.Schema;
43 using ValException = System.Xml.Schema.XmlSchemaValidationException;
45 using ValException = System.Xml.Schema.XmlSchemaException;
48 using QName = System.Xml.XmlQualifiedName;
49 using ContentProc = System.Xml.Schema.XmlSchemaContentProcessing;
50 using XsElement = System.Xml.Schema.XmlSchemaElement;
51 using XsAttribute = System.Xml.Schema.XmlSchemaAttribute;
52 using ComplexType = System.Xml.Schema.XmlSchemaComplexType;
53 using SimpleType = System.Xml.Schema.XmlSchemaSimpleType;
54 using SimpleTypeRest = System.Xml.Schema.XmlSchemaSimpleTypeRestriction;
55 using SimpleTypeList = System.Xml.Schema.XmlSchemaSimpleTypeList;
56 using SimpleTypeUnion = System.Xml.Schema.XmlSchemaSimpleTypeUnion;
57 using XsDatatype = System.Xml.Schema.XmlSchemaDatatype;
59 namespace Mono.Xml.Schema
61 internal class XsdValidatingReader : XmlReader, IXmlLineInfo, IHasXmlSchemaInfo, IHasXmlParserContext, IXmlNamespaceResolver
63 static readonly XsAttribute [] emptyAttributeArray =
68 IHasXmlSchemaInfo sourceReaderSchemaInfo;
69 IXmlLineInfo readerLineInfo;
70 ValidationType validationType;
71 XmlSchemaSet schemas = new XmlSchemaSet ();
72 bool namespaces = true;
73 bool validationStarted;
75 #region ID Constraints
76 bool checkIdentity = true;
77 XsdIDManager idManager = new XsdIDManager ();
80 #region Key Constraints
81 bool checkKeyConstraints = true;
82 ArrayList keyTables = new ArrayList ();
83 ArrayList currentKeyFieldConsumers;
84 ArrayList tmpKeyrefPool;
86 ArrayList elementQNameStack = new ArrayList ();
88 XsdParticleStateManager state = new XsdParticleStateManager ();
90 int skipValidationDepth = -1;
92 StringBuilder storedCharacters = new StringBuilder ();
93 bool shouldValidateCharacters;
95 XsAttribute [] defaultAttributes = emptyAttributeArray;
96 int currentDefaultAttribute = -1;
97 ArrayList defaultAttributesCache = new ArrayList ();
98 bool defaultAttributeConsumed;
99 object currentAttrType;
102 public XsdValidatingReader (XmlReader reader)
104 this.reader = reader;
105 readerLineInfo = reader as IXmlLineInfo;
106 sourceReaderSchemaInfo = reader as IHasXmlSchemaInfo;
107 schemas.ValidationEventHandler += ValidationEventHandler;
111 public ValidationEventHandler ValidationEventHandler;
113 // Private Properties
115 private XsdValidationContext Context {
116 get { return state.Context; }
119 #region Key Constraints
120 internal ArrayList CurrentKeyFieldConsumers {
122 if (currentKeyFieldConsumers == null)
123 currentKeyFieldConsumers = new ArrayList ();
124 return currentKeyFieldConsumers;
129 // Public Non-overrides
131 public int XsiNilDepth {
132 get { return xsiNilDepth; }
135 public bool Namespaces {
136 get { return namespaces; }
137 set { namespaces = value; }
140 // This is required to resolve xsi:schemaLocation
141 public XmlResolver XmlResolver {
147 // This should be changed before the first Read() call.
148 public XmlSchemaSet Schemas {
149 get { return schemas; }
151 if (validationStarted)
152 throw new InvalidOperationException ("Schemas must be set before the first call to Read().");
157 public object SchemaType {
159 if (ReadState != ReadState.Interactive)
163 case XmlNodeType.Element:
164 if (Context.ActualType != null)
165 return Context.ActualType;
167 return SourceReaderSchemaType;
168 case XmlNodeType.Attribute:
169 if (currentAttrType == null) {
170 ComplexType ct = Context.ActualType as ComplexType;
172 XsAttribute attdef = ct.AttributeUses [new QName (LocalName, NamespaceURI)] as XsAttribute;
174 currentAttrType = attdef.AttributeType;
175 return currentAttrType;
177 currentAttrType = SourceReaderSchemaType;
179 return currentAttrType;
181 return SourceReaderSchemaType;
186 private object SourceReaderSchemaType {
187 get { return this.sourceReaderSchemaInfo != null ? sourceReaderSchemaInfo.SchemaType : null; }
190 public ValidationType ValidationType {
191 get { return validationType; }
193 if (validationStarted)
194 throw new InvalidOperationException ("ValidationType must be set before reading.");
195 validationType = value;
200 IDictionary<string, string>
204 IXmlNamespaceResolver.GetNamespacesInScope (XmlNamespaceScope scope)
206 IXmlNamespaceResolver resolver = reader as IXmlNamespaceResolver;
207 if (resolver == null)
208 throw new NotSupportedException ("The input XmlReader does not implement IXmlNamespaceResolver and thus this validating reader cannot collect in-scope namespaces.");
209 return resolver.GetNamespacesInScope (scope);
212 string IXmlNamespaceResolver.LookupPrefix (string ns)
214 IXmlNamespaceResolver resolver = reader as IXmlNamespaceResolver;
215 if (resolver == null)
216 throw new NotSupportedException ("The input XmlReader does not implement IXmlNamespaceResolver and thus this validating reader cannot execute namespace prefix lookup.");
217 return resolver.LookupPrefix (ns);
220 // It is used only for independent XmlReader use, not for XmlValidatingReader.
221 public object ReadTypedValue ()
223 object o = XmlSchemaUtil.ReadTypedValue (this,
224 SchemaType, NamespaceManager,
226 storedCharacters.Length = 0;
230 // Public Overriden Properties
232 public override int AttributeCount {
234 return reader.AttributeCount + defaultAttributes.Length;
238 public override string BaseURI {
239 get { return reader.BaseURI; }
242 // If this class is used to implement XmlValidatingReader,
243 // it should be left to DTDValidatingReader. In other cases,
244 // it depends on the reader's ability.
245 public override bool CanResolveEntity {
246 get { return reader.CanResolveEntity; }
249 public override int Depth {
251 if (currentDefaultAttribute < 0)
253 if (this.defaultAttributeConsumed)
254 return reader.Depth + 2;
255 return reader.Depth + 1;
259 public override bool EOF {
260 get { return reader.EOF; }
263 public override bool HasValue {
265 if (currentDefaultAttribute < 0)
266 return reader.HasValue;
271 public override bool IsDefault {
273 if (currentDefaultAttribute < 0)
274 return reader.IsDefault;
279 public override bool IsEmptyElement {
281 if (currentDefaultAttribute < 0)
282 return reader.IsEmptyElement;
287 public override string this [int i] {
288 get { return GetAttribute (i); }
291 public override string this [string name] {
292 get { return GetAttribute (name); }
295 public override string this [string localName, string ns] {
296 get { return GetAttribute (localName, ns); }
299 public int LineNumber {
300 get { return readerLineInfo != null ? readerLineInfo.LineNumber : 0; }
303 public int LinePosition {
304 get { return readerLineInfo != null ? readerLineInfo.LinePosition : 0; }
307 public override string LocalName {
309 if (currentDefaultAttribute < 0)
310 return reader.LocalName;
311 if (defaultAttributeConsumed)
313 return defaultAttributes [currentDefaultAttribute].QualifiedName.Name;
317 public override string Name {
319 if (currentDefaultAttribute < 0)
321 if (defaultAttributeConsumed)
324 QName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
325 string prefix = Prefix;
326 if (prefix == String.Empty)
329 return String.Concat (prefix, ":", qname.Name);
333 public override string NamespaceURI {
335 if (currentDefaultAttribute < 0)
336 return reader.NamespaceURI;
337 if (defaultAttributeConsumed)
339 return defaultAttributes [currentDefaultAttribute].QualifiedName.Namespace;
343 public override XmlNameTable NameTable {
344 get { return reader.NameTable; }
347 public override XmlNodeType NodeType {
349 if (currentDefaultAttribute < 0)
350 return reader.NodeType;
351 if (defaultAttributeConsumed)
352 return XmlNodeType.Text;
353 return XmlNodeType.Attribute;
357 public XmlParserContext ParserContext {
358 get { return XmlSchemaUtil.GetParserContext (reader); }
361 internal XmlNamespaceManager NamespaceManager {
362 get { return ParserContext != null ? ParserContext.NamespaceManager : null; }
365 public override string Prefix {
367 if (currentDefaultAttribute < 0)
368 return reader.Prefix;
369 if (defaultAttributeConsumed)
371 QName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
372 string prefix = NamespaceManager != null ? NamespaceManager.LookupPrefix (qname.Namespace, false) : null;
380 public override char QuoteChar {
381 get { return reader.QuoteChar; }
384 public override ReadState ReadState {
385 get { return reader.ReadState; }
388 public override string Value {
390 if (currentDefaultAttribute < 0)
392 string value = defaultAttributes [currentDefaultAttribute].ValidatedDefaultValue;
394 value = defaultAttributes [currentDefaultAttribute].ValidatedFixedValue;
399 public override string XmlLang {
401 string xmlLang = reader.XmlLang;
404 int idx = this.FindDefaultAttribute ("lang", XmlNamespaceManager.XmlnsXml);
407 xmlLang = defaultAttributes [idx].ValidatedDefaultValue;
409 xmlLang = defaultAttributes [idx].ValidatedFixedValue;
414 public override XmlSpace XmlSpace {
416 XmlSpace space = reader.XmlSpace;
417 if (space != XmlSpace.None)
419 int idx = this.FindDefaultAttribute ("space", XmlNamespaceManager.XmlnsXml);
421 return XmlSpace.None;
422 string spaceSpec = defaultAttributes [idx].ValidatedDefaultValue;
423 if (spaceSpec == null)
424 spaceSpec = defaultAttributes [idx].ValidatedFixedValue;
425 return (XmlSpace) Enum.Parse (typeof (XmlSpace), spaceSpec, false);
431 private void HandleError (string error)
433 HandleError (error, null);
436 private void HandleError (string error, Exception innerException)
438 HandleError (error, innerException, false);
441 private void HandleError (string error, Exception innerException, bool isWarning)
443 if (ValidationType == ValidationType.None) // extra quick check
446 ValException schemaException = new ValException (error,
447 this, this.BaseURI, null, innerException);
448 HandleError (schemaException, isWarning);
451 private void HandleError (ValException schemaException)
453 HandleError (schemaException, false);
456 private void HandleError (ValException schemaException, bool isWarning)
458 if (ValidationType == ValidationType.None)
461 ValidationEventArgs e = new ValidationEventArgs (schemaException,
462 schemaException.Message, isWarning ? XmlSeverityType.Warning : XmlSeverityType.Error);
464 if (ValidationEventHandler != null)
465 ValidationEventHandler (this, e);
467 else if (e.Severity == XmlSeverityType.Error)
471 private XsElement FindElement (string name, string ns)
473 return (XsElement) schemas.GlobalElements [new QName (name, ns)];
476 private XmlSchemaType FindType (QName qname)
478 return (XmlSchemaType) schemas.GlobalTypes [qname];
481 private void ValidateStartElementParticle ()
483 if (Context.State == null)
485 Context.XsiType = null;
486 state.CurrentElement = null;
487 Context.EvaluateStartElement (reader.LocalName,
488 reader.NamespaceURI);
489 if (Context.IsInvalid)
490 HandleError ("Invalid start element: " + reader.NamespaceURI + ":" + reader.LocalName);
492 Context.SetElement (state.CurrentElement);
495 private void ValidateEndElementParticle ()
497 if (Context.State != null) {
498 if (!Context.EvaluateEndElement ()) {
499 HandleError ("Invalid end element: " + reader.Name);
505 // Utility for missing validation completion related to child items.
506 private void ValidateCharacters ()
508 if (xsiNilDepth >= 0 && xsiNilDepth < reader.Depth)
509 HandleError ("Element item appeared, while current element context is nil.");
511 if (shouldValidateCharacters)
512 storedCharacters.Append (reader.Value);
515 // Utility for missing validation completion related to child items.
516 private void ValidateEndSimpleContent ()
518 if (shouldValidateCharacters)
519 ValidateEndSimpleContentCore ();
520 shouldValidateCharacters = false;
521 storedCharacters.Length = 0;
524 private void ValidateEndSimpleContentCore ()
526 if (Context.ActualType == null)
529 string value = storedCharacters.ToString ();
531 if (value.Length == 0) {
532 // 3.3.4 Element Locally Valid (Element) 5.1.2
533 if (Context.Element != null) {
534 if (Context.Element.ValidatedDefaultValue != null)
535 value = Context.Element.ValidatedDefaultValue;
539 XsDatatype dt = Context.ActualType as XsDatatype;
540 SimpleType st = Context.ActualType as SimpleType;
545 ComplexType ct = Context.ActualType as ComplexType;
547 switch (ct.ContentType) {
548 case XmlSchemaContentType.ElementOnly:
549 case XmlSchemaContentType.Empty:
550 if (value.Length > 0)
551 HandleError ("Character content not allowed.");
557 // 3.3.4 Element Locally Valid (Element) :: 5.2.2.2. Fixed value constraints
558 if (Context.Element != null && Context.Element.ValidatedFixedValue != null)
559 if (value != Context.Element.ValidatedFixedValue)
560 HandleError ("Fixed value constraint was not satisfied.");
561 AssessStringValid (st, dt, value);
564 #region Key Constraints
565 if (checkKeyConstraints)
566 ValidateSimpleContentIdentity (dt, value);
569 shouldValidateCharacters = false;
572 // 3.14.4 String Valid
573 private void AssessStringValid (SimpleType st,
574 XsDatatype dt, string value)
576 XsDatatype validatedDatatype = dt;
578 string normalized = validatedDatatype.Normalize (value);
580 XsDatatype itemDatatype;
581 SimpleType itemSimpleType;
582 switch (st.DerivedBy) {
583 case XmlSchemaDerivationMethod.List:
584 SimpleTypeList listContent = st.Content as SimpleTypeList;
585 values = normalized.Split (XmlChar.WhitespaceChars);
586 itemDatatype = listContent.ValidatedListItemType as XsDatatype;
587 itemSimpleType = listContent.ValidatedListItemType as SimpleType;
588 for (int vi = 0; vi < values.Length; vi++) {
589 string each = values [vi];
590 if (each == String.Empty)
592 // validate against ValidatedItemType
593 if (itemDatatype != null) {
595 itemDatatype.ParseValue (each, NameTable, NamespaceManager);
596 } catch (Exception ex) { // FIXME: (wishlist) better exception handling ;-(
597 HandleError ("List type value contains one or more invalid values.", ex);
602 AssessStringValid (itemSimpleType, itemSimpleType.Datatype, each);
605 case XmlSchemaDerivationMethod.Union:
606 SimpleTypeUnion union = st.Content as SimpleTypeUnion;
608 string each = normalized;
609 // validate against ValidatedItemType
611 foreach (object eachType in union.ValidatedTypes) {
612 itemDatatype = eachType as XsDatatype;
613 itemSimpleType = eachType as SimpleType;
614 if (itemDatatype != null) {
616 itemDatatype.ParseValue (each, NameTable, NamespaceManager);
617 } catch (Exception) { // FIXME: (wishlist) better exception handling ;-(
623 AssessStringValid (itemSimpleType, itemSimpleType.Datatype, each);
624 } catch (ValException) {
632 HandleError ("Union type value contains one or more invalid values.");
637 case XmlSchemaDerivationMethod.Restriction:
638 SimpleTypeRest str = st.Content as SimpleTypeRest;
641 /* Don't forget to validate against inherited type's facets
642 * Could we simplify this by assuming that the basetype will also
645 // mmm, will check later.
646 SimpleType baseType = st.BaseXmlSchemaType as SimpleType;
647 if (baseType != null) {
648 AssessStringValid(baseType, dt, normalized);
650 if (!str.ValidateValueWithFacets (normalized, NameTable)) {
651 HandleError ("Specified value was invalid against the facets.");
655 validatedDatatype = st.Datatype;
659 if (validatedDatatype != null) {
661 validatedDatatype.ParseValue (value, NameTable, NamespaceManager);
662 } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
663 HandleError ("Invalidly typed data was specified.", ex);
668 private object GetXsiType (string name)
670 object xsiType = null;
671 QName typeQName = QName.Parse (name, this);
672 if (typeQName == ComplexType.AnyTypeName)
673 xsiType = ComplexType.AnyType;
674 else if (XmlSchemaUtil.IsBuiltInDatatypeName (typeQName))
675 xsiType = XsDatatype.FromName (typeQName);
677 xsiType = FindType (typeQName);
681 // It is common to ElementLocallyValid::4 and SchemaValidityAssessment::1.2.1.2.4
682 private void AssessLocalTypeDerivationOK (object xsiType, object baseType, XmlSchemaDerivationMethod flag)
684 XmlSchemaType xsiSchemaType = xsiType as XmlSchemaType;
685 ComplexType baseComplexType = baseType as ComplexType;
686 ComplexType xsiComplexType = xsiSchemaType as ComplexType;
687 if (xsiType != baseType) {
688 // Extracted (not extraneous) check for 3.4.6 TypeDerivationOK.
689 if (baseComplexType != null)
690 flag |= baseComplexType.BlockResolved;
691 if (flag == XmlSchemaDerivationMethod.All) {
692 HandleError ("Prohibited element type substitution.");
694 } else if (xsiSchemaType != null && (flag & xsiSchemaType.DerivedBy) != 0) {
695 HandleError ("Prohibited element type substitution.");
700 if (xsiComplexType != null)
702 xsiComplexType.ValidateTypeDerivationOK (baseType, null, null);
703 } catch (ValException ex) {
704 // HandleError ("Locally specified schema complex type derivation failed. " + ex.Message, ex);
708 SimpleType xsiSimpleType = xsiType as SimpleType;
709 if (xsiSimpleType != null) {
711 xsiSimpleType.ValidateTypeDerivationOK (baseType, null, null, true);
712 } catch (ValException ex) {
713 // HandleError ("Locally specified schema simple type derivation failed. " + ex.Message, ex);
717 else if (xsiType is XsDatatype) {
721 HandleError ("Primitive data type cannot be derived type using xsi:type specification.");
725 // Section 3.3.4 of the spec.
726 private void AssessStartElementSchemaValidity ()
728 // If the reader is inside xsi:nil (and failed
729 // on validation), then simply skip its content.
730 if (xsiNilDepth >= 0 && xsiNilDepth < reader.Depth)
731 HandleError ("Element item appeared, while current element context is nil.");
733 ValidateStartElementParticle ();
735 string xsiNilValue = reader.GetAttribute ("nil", XmlSchema.InstanceNamespace);
736 if (xsiNilValue != null)
737 xsiNilValue = xsiNilValue.Trim (XmlChar.WhitespaceChars);
738 bool isXsiNil = xsiNilValue == "true";
739 if (isXsiNil && this.xsiNilDepth < 0)
740 xsiNilDepth = reader.Depth;
742 // [Schema Validity Assessment (Element) 1.2]
743 // Evaluate "local type definition" from xsi:type.
744 // (See spec 3.3.4 Schema Validity Assessment (Element) 1.2.1.2.3.
745 // Note that Schema Validity Assessment(Element) 1.2 takes
746 // precedence than 1.1 of that.
748 string xsiTypeName = reader.GetAttribute ("type", XmlSchema.InstanceNamespace);
749 if (xsiTypeName != null) {
750 xsiTypeName = xsiTypeName.Trim (XmlChar.WhitespaceChars);
751 object xsiType = GetXsiType (xsiTypeName);
753 HandleError ("The instance type was not found: " + xsiTypeName + " .");
755 XmlSchemaType xsiSchemaType = xsiType as XmlSchemaType;
756 if (xsiSchemaType != null && this.Context.Element != null) {
757 XmlSchemaType elemBaseType = Context.Element.ElementType as XmlSchemaType;
758 if (elemBaseType != null && (xsiSchemaType.DerivedBy & elemBaseType.FinalResolved) != 0)
759 HandleError ("The instance type is prohibited by the type of the context element.");
760 if (elemBaseType != xsiType && (xsiSchemaType.DerivedBy & this.Context.Element.BlockResolved) != 0)
761 HandleError ("The instance type is prohibited by the context element.");
763 ComplexType xsiComplexType = xsiType as ComplexType;
764 if (xsiComplexType != null && xsiComplexType.IsAbstract)
765 HandleError ("The instance type is abstract: " + xsiTypeName + " .");
767 // If current schema type exists, then this xsi:type must be
768 // valid extension of that type. See 1.2.1.2.4.
769 if (Context.Element != null) {
770 AssessLocalTypeDerivationOK (xsiType, Context.Element.ElementType, Context.Element.BlockResolved);
772 AssessStartElementLocallyValidType (xsiType); // 1.2.2:
773 Context.XsiType = xsiType;
778 // Create Validation Root, if not exist.
779 // [Schema Validity Assessment (Element) 1.1]
780 if (Context.Element == null) {
781 state.CurrentElement = FindElement (reader.LocalName, reader.NamespaceURI);
782 Context.SetElement (state.CurrentElement);
784 if (Context.Element != null) {
785 if (Context.XsiType == null) {
786 AssessElementLocallyValidElement (xsiNilValue); // 1.1.2
789 switch (state.ProcessContents) {
790 case ContentProc.Skip:
792 case ContentProc.Lax:
795 if (xsiTypeName == null &&
796 (schemas.Contains (reader.NamespaceURI) ||
797 !schemas.MissedSubComponents (reader.NamespaceURI)))
798 HandleError ("Element declaration for " + new QName (reader.LocalName, reader.NamespaceURI) + " is missing.");
803 state.PushContext ();
805 XsdValidationState next = null;
806 if (state.ProcessContents == ContentProc.Skip)
807 skipValidationDepth = reader.Depth;
809 // create child particle state.
810 ComplexType xsComplexType = SchemaType as ComplexType;
811 if (xsComplexType != null)
812 next = state.Create (xsComplexType.ValidatableParticle);
813 else if (state.ProcessContents == ContentProc.Lax)
814 next = state.Create (XmlSchemaAny.AnyTypeContent);
816 next = state.Create (XmlSchemaParticle.Empty);
818 Context.State = next;
820 #region Key Constraints
821 if (checkKeyConstraints) {
822 ValidateKeySelectors ();
823 ValidateKeyFields ();
829 // 3.3.4 Element Locally Valid (Element)
830 private void AssessElementLocallyValidElement (string xsiNilValue)
832 XsElement element = Context.Element;
833 QName qname = new QName (reader.LocalName, reader.NamespaceURI);
836 HandleError ("Element declaration is required for " + qname);
838 if (element.ActualIsAbstract)
839 HandleError ("Abstract element declaration was specified for " + qname);
841 if (!element.ActualIsNillable && xsiNilValue != null)
842 HandleError ("This element declaration is not nillable: " + qname);
844 // Note that 3.2.1 xsi:nil constraints are to be
845 // validated in AssessElementSchemaValidity() and
846 // ValidateCharacters().
847 else if (xsiNilValue == "true") {
848 if (element.ValidatedFixedValue != null)
849 HandleError ("Schema instance nil was specified, where the element declaration for " + qname + "has fixed value constraints.");
851 // 4. xsi:type (it takes precedence than element type)
852 string xsiType = reader.GetAttribute ("type", XmlSchema.InstanceNamespace);
853 if (xsiType != null) {
854 Context.XsiType = GetXsiType (xsiType);
855 AssessLocalTypeDerivationOK (Context.XsiType, element.ElementType, element.BlockResolved);
858 Context.XsiType = null;
860 // 5 Not all things cannot be assessed here.
861 // It is common to 5.1 and 5.2
862 if (element.ElementType != null)
863 AssessStartElementLocallyValidType (SchemaType);
865 // 6. should be out from here.
866 // See invokation of AssessStartIdentityConstraints().
868 // 7 is going to be validated in Read() (in case of xmlreader's EOF).
871 // 3.3.4 Element Locally Valid (Type)
872 private void AssessStartElementLocallyValidType (object schemaType)
874 if (schemaType == null) { // 1.
875 HandleError ("Schema type does not exist.");
878 ComplexType cType = schemaType as ComplexType;
879 SimpleType sType = schemaType as SimpleType;
882 while (reader.MoveToNextAttribute ()) {
883 if (reader.NamespaceURI == XmlNamespaceManager.XmlnsXmlns)
885 if (reader.NamespaceURI != XmlSchema.InstanceNamespace)
886 HandleError ("Current simple type cannot accept attributes other than schema instance namespace.");
887 switch (reader.LocalName) {
890 case "schemaLocation":
891 case "noNamespaceSchemaLocation":
894 HandleError ("Unknown schema instance namespace attribute: " + reader.LocalName);
898 reader.MoveToElement ();
899 // 3.1.2 and 3.1.3 cannot be assessed here.
900 } else if (cType != null) {
901 if (cType.IsAbstract) { // 2.
902 HandleError ("Target complex type is abstract.");
906 AssessElementLocallyValidComplexType (cType);
910 // 3.4.4 Element Locally Valid (Complex Type)
911 private void AssessElementLocallyValidComplexType (ComplexType cType)
914 if (cType.IsAbstract)
915 HandleError ("Target complex type is abstract.");
917 // 2 (xsi:nil and content prohibition)
918 // See AssessStartElementSchemaValidity() and ValidateCharacters()
920 // 3. attribute uses and
922 if (reader.MoveToFirstAttribute ()) {
924 switch (reader.NamespaceURI) {
925 case"http://www.w3.org/2000/xmlns/":
926 case XmlSchema.InstanceNamespace:
929 QName qname = new QName (reader.LocalName, reader.NamespaceURI);
930 // including 3.10.4 Item Valid (Wildcard)
931 XmlSchemaObject attMatch = XmlSchemaUtil.FindAttributeDeclaration (reader.NamespaceURI, schemas, cType, qname);
932 if (attMatch == null)
933 HandleError ("Attribute declaration was not found for " + qname);
934 XsAttribute attdecl = attMatch as XsAttribute;
935 if (attdecl != null) {
936 AssessAttributeLocallyValidUse (attdecl);
937 AssessAttributeLocallyValid (attdecl);
938 } // otherwise anyAttribute or null.
939 } while (reader.MoveToNextAttribute ());
940 reader.MoveToElement ();
943 // Collect default attributes.
945 foreach (DictionaryEntry entry in cType.AttributeUses) {
946 XsAttribute attr = (XsAttribute) entry.Value;
947 if (reader [attr.QualifiedName.Name, attr.QualifiedName.Namespace] == null) {
948 if (attr.ValidatedUse == XmlSchemaUse.Required &&
949 attr.ValidatedFixedValue == null)
950 HandleError ("Required attribute " + attr.QualifiedName + " was not found.");
951 else if (attr.ValidatedDefaultValue != null || attr.ValidatedFixedValue != null)
952 defaultAttributesCache.Add (attr);
955 if (defaultAttributesCache.Count == 0)
956 defaultAttributes = emptyAttributeArray;
958 defaultAttributes = (XsAttribute [])
959 defaultAttributesCache.ToArray (
960 typeof (XsAttribute));
961 defaultAttributesCache.Clear ();
962 // 5. wild IDs was already checked above.
965 // 3.2.4 Attribute Locally Valid and 3.4.4
966 private void AssessAttributeLocallyValid (XsAttribute attr)
969 if (attr.AttributeType == null)
970 HandleError ("Attribute type is missing for " + attr.QualifiedName);
971 XsDatatype dt = attr.AttributeType as XsDatatype;
973 dt = ((SimpleType) attr.AttributeType).Datatype;
974 // It is a bit heavy process, so let's omit as long as possible ;-)
975 if (dt != SimpleType.AnySimpleType || attr.ValidatedFixedValue != null) {
976 string normalized = dt.Normalize (reader.Value);
977 object parsedValue = null;
979 parsedValue = dt.ParseValue (normalized, reader.NameTable, NamespaceManager);
980 } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
981 HandleError ("Attribute value is invalid against its data type " + dt.TokenizedType, ex);
983 if (attr.ValidatedFixedValue != null && attr.ValidatedFixedValue != normalized) {
984 HandleError ("The value of the attribute " + attr.QualifiedName + " does not match with its fixed value.");
985 parsedValue = dt.ParseValue (attr.ValidatedFixedValue, reader.NameTable, NamespaceManager);
987 #region ID Constraints
988 if (this.checkIdentity) {
989 string error = idManager.AssessEachAttributeIdentityConstraint (dt, parsedValue, ((QName) elementQNameStack [elementQNameStack.Count - 1]).Name);
997 private void AssessAttributeLocallyValidUse (XsAttribute attr)
999 // This is extra check than spec 3.5.4
1000 if (attr.ValidatedUse == XmlSchemaUse.Prohibited)
1001 HandleError ("Attribute " + attr.QualifiedName + " is prohibited in this context.");
1004 private void AssessEndElementSchemaValidity ()
1006 ValidateEndElementParticle (); // validate against childrens' state.
1008 ValidateEndSimpleContent ();
1010 // 3.3.4 Assess ElementLocallyValidElement 5: value constraints.
1011 // 3.3.4 Assess ElementLocallyValidType 3.1.3. = StringValid(3.14.4)
1012 // => ValidateEndSimpleContent().
1014 #region Key Constraints
1015 if (checkKeyConstraints)
1016 ValidateEndElementKeyConstraints ();
1019 // Reset xsi:nil, if required.
1020 if (xsiNilDepth == reader.Depth)
1024 #region Key Constraints
1025 private void ValidateEndElementKeyConstraints ()
1027 // Reset Identity constraints.
1028 for (int i = 0; i < keyTables.Count; i++) {
1029 XsdKeyTable seq = this.keyTables [i] as XsdKeyTable;
1030 if (seq.StartDepth == reader.Depth) {
1031 EndIdentityValidation (seq);
1033 for (int k = 0; k < seq.Entries.Count; k++) {
1034 XsdKeyEntry entry = seq.Entries [k] as XsdKeyEntry;
1035 // Remove finished (maybe key not found) entries.
1036 if (entry.StartDepth == reader.Depth) {
1038 seq.FinishedEntries.Add (entry);
1039 else if (seq.SourceSchemaIdentity is XmlSchemaKey)
1040 HandleError ("Key sequence is missing.");
1041 seq.Entries.RemoveAt (k);
1044 // Pop validated key depth to find two or more fields.
1046 for (int j = 0; j < entry.KeyFields.Count; j++) {
1047 XsdKeyEntryField kf = entry.KeyFields [j];
1048 if (!kf.FieldFound && kf.FieldFoundDepth == reader.Depth) {
1049 kf.FieldFoundDepth = 0;
1050 kf.FieldFoundPath = null;
1057 for (int i = 0; i < keyTables.Count; i++) {
1058 XsdKeyTable seq = this.keyTables [i] as XsdKeyTable;
1059 if (seq.StartDepth == reader.Depth) {
1060 keyTables.RemoveAt (i);
1066 // 3.11.4 Identity Constraint Satisfied
1067 private void ValidateKeySelectors ()
1069 if (tmpKeyrefPool != null)
1070 tmpKeyrefPool.Clear ();
1071 if (Context.Element != null && Context.Element.Constraints.Count > 0) {
1072 // (a) Create new key sequences, if required.
1073 for (int i = 0; i < Context.Element.Constraints.Count; i++) {
1074 XmlSchemaIdentityConstraint ident = (XmlSchemaIdentityConstraint) Context.Element.Constraints [i];
1075 XsdKeyTable seq = CreateNewKeyTable (ident);
1076 if (ident is XmlSchemaKeyref) {
1077 if (tmpKeyrefPool == null)
1078 tmpKeyrefPool = new ArrayList ();
1079 tmpKeyrefPool.Add (seq);
1084 // (b) Evaluate current key sequences.
1085 for (int i = 0; i < keyTables.Count; i++) {
1086 XsdKeyTable seq = (XsdKeyTable) keyTables [i];
1087 if (seq.SelectorMatches (this.elementQNameStack, reader.Depth) != null) {
1088 // creates and registers new entry.
1089 XsdKeyEntry entry = new XsdKeyEntry (seq, reader.Depth, readerLineInfo);
1090 seq.Entries.Add (entry);
1095 private void ValidateKeyFields ()
1097 // (c) Evaluate field paths.
1098 for (int i = 0; i < keyTables.Count; i++) {
1099 XsdKeyTable seq = (XsdKeyTable) keyTables [i];
1100 // If possible, create new field entry candidates.
1101 for (int j = 0; j < seq.Entries.Count; j++) {
1103 ProcessKeyEntry (seq.Entries [j]);
1104 } catch (ValException ex) {
1111 private void ProcessKeyEntry (XsdKeyEntry entry)
1113 bool isNil = XsiNilDepth == Depth;
1114 entry.ProcessMatch (false, elementQNameStack, this, NameTable, BaseURI, SchemaType, NamespaceManager, readerLineInfo, Depth, null, null, null, isNil, CurrentKeyFieldConsumers);
1115 if (MoveToFirstAttribute ()) {
1118 switch (NamespaceURI) {
1119 case XmlNamespaceManager.XmlnsXmlns:
1120 case XmlSchema.InstanceNamespace:
1123 XmlSchemaDatatype dt = SchemaType as XmlSchemaDatatype;
1124 XmlSchemaSimpleType st = SchemaType as XmlSchemaSimpleType;
1125 if (dt == null && st != null)
1127 object identity = null;
1129 identity = dt.ParseValue (Value, NameTable, NamespaceManager);
1130 if (identity == null)
1132 entry.ProcessMatch (true, elementQNameStack, this, NameTable, BaseURI, SchemaType, NamespaceManager, readerLineInfo, Depth, LocalName, NamespaceURI, identity, false, CurrentKeyFieldConsumers);
1133 } while (MoveToNextAttribute ());
1140 private XsdKeyTable CreateNewKeyTable (XmlSchemaIdentityConstraint ident)
1142 XsdKeyTable seq = new XsdKeyTable (ident);
1143 seq.StartDepth = reader.Depth;
1144 this.keyTables.Add (seq);
1148 private void ValidateSimpleContentIdentity (
1149 XmlSchemaDatatype dt, string value)
1151 // Identity field value
1152 if (currentKeyFieldConsumers != null) {
1153 while (this.currentKeyFieldConsumers.Count > 0) {
1154 XsdKeyEntryField field = this.currentKeyFieldConsumers [0] as XsdKeyEntryField;
1155 if (field.Identity != null)
1156 HandleError ("Two or more identical field was found. Former value is '" + field.Identity + "' .");
1157 object identity = null; // This means empty value
1160 identity = dt.ParseValue (value, NameTable, NamespaceManager);
1161 } catch (Exception ex) { // FIXME: (wishlist) This is bad manner ;-(
1162 HandleError ("Identity value is invalid against its data type " + dt.TokenizedType, ex);
1165 if (identity == null)
1168 if (!field.SetIdentityField (identity, reader.Depth == xsiNilDepth, dt as XsdAnySimpleType, this.Depth, readerLineInfo))
1169 HandleError ("Two or more identical key value was found: '" + value + "' .");
1170 this.currentKeyFieldConsumers.RemoveAt (0);
1175 private void EndIdentityValidation (XsdKeyTable seq)
1177 ArrayList errors = null;
1178 for (int i = 0; i < seq.Entries.Count; i++) {
1179 XsdKeyEntry entry = (XsdKeyEntry) seq.Entries [i];
1182 if (seq.SourceSchemaIdentity is XmlSchemaKey) {
1184 errors = new ArrayList ();
1185 errors.Add ("line " + entry.SelectorLineNumber + "position " + entry.SelectorLinePosition);
1189 HandleError ("Invalid identity constraints were found. Key was not found. "
1190 + String.Join (", ", errors.ToArray (typeof (string)) as string []));
1192 // If it is keyref, then find reference target
1193 XmlSchemaKeyref xsdKeyref = seq.SourceSchemaIdentity as XmlSchemaKeyref;
1194 if (xsdKeyref != null)
1195 EndKeyrefValidation (seq, xsdKeyref.Target);
1198 private void EndKeyrefValidation (XsdKeyTable seq, XmlSchemaIdentityConstraint targetIdent)
1200 for (int i = this.keyTables.Count - 1; i >= 0; i--) {
1201 XsdKeyTable target = this.keyTables [i] as XsdKeyTable;
1202 if (target.SourceSchemaIdentity != targetIdent)
1204 seq.ReferencedKey = target;
1205 for (int j = 0; j < seq.FinishedEntries.Count; j++) {
1206 XsdKeyEntry entry = (XsdKeyEntry) seq.FinishedEntries [j];
1207 for (int k = 0; k < target.FinishedEntries.Count; k++) {
1208 XsdKeyEntry targetEntry = (XsdKeyEntry) target.FinishedEntries [k];
1209 if (entry.CompareIdentity (targetEntry)) {
1210 entry.KeyRefFound = true;
1216 if (seq.ReferencedKey == null)
1217 HandleError ("Target key was not found.");
1218 ArrayList errors = null;
1219 for (int i = 0; i < seq.FinishedEntries.Count; i++) {
1220 XsdKeyEntry entry = (XsdKeyEntry) seq.FinishedEntries [i];
1221 if (!entry.KeyRefFound) {
1223 errors = new ArrayList ();
1224 errors.Add (" line " + entry.SelectorLineNumber + ", position " + entry.SelectorLinePosition);
1228 HandleError ("Invalid identity constraints were found. Referenced key was not found: "
1229 + String.Join (" / ", errors.ToArray (typeof (string)) as string []));
1233 // Overrided Methods
1235 public override void Close ()
1240 public override string GetAttribute (int i)
1242 switch (reader.NodeType) {
1243 case XmlNodeType.XmlDeclaration:
1244 case XmlNodeType.DocumentType:
1245 return reader.GetAttribute (i);
1248 if (reader.AttributeCount > i)
1249 reader.GetAttribute (i);
1250 int defIdx = i - reader.AttributeCount;
1251 if (i < AttributeCount)
1252 return defaultAttributes [defIdx].DefaultValue;
1254 throw new ArgumentOutOfRangeException ("i", i, "Specified attribute index is out of range.");
1257 public override string GetAttribute (string name)
1259 switch (reader.NodeType) {
1260 case XmlNodeType.XmlDeclaration:
1261 case XmlNodeType.DocumentType:
1262 return reader.GetAttribute (name);
1265 string value = reader.GetAttribute (name);
1269 QName qname = SplitQName (name);
1270 return GetDefaultAttribute (qname.Name, qname.Namespace);
1273 private QName SplitQName (string name)
1275 if (!XmlChar.IsName (name))
1276 throw new ArgumentException ("Invalid name was specified.", "name");
1278 Exception ex = null;
1279 QName qname = XmlSchemaUtil.ToQName (reader, name, out ex);
1286 public override string GetAttribute (string localName, string ns)
1288 switch (reader.NodeType) {
1289 case XmlNodeType.XmlDeclaration:
1290 case XmlNodeType.DocumentType:
1291 return reader.GetAttribute (localName, ns);
1294 string value = reader.GetAttribute (localName, ns);
1298 return GetDefaultAttribute (localName, ns);
1301 private string GetDefaultAttribute (string localName, string ns)
1303 int idx = this.FindDefaultAttribute (localName, ns);
1306 string value = defaultAttributes [idx].ValidatedDefaultValue;
1308 value = defaultAttributes [idx].ValidatedFixedValue;
1312 private int FindDefaultAttribute (string localName, string ns)
1314 for (int i = 0; i < this.defaultAttributes.Length; i++) {
1315 XsAttribute attr = defaultAttributes [i];
1316 if (attr.QualifiedName.Name == localName &&
1317 (ns == null || attr.QualifiedName.Namespace == ns))
1323 public bool HasLineInfo ()
1325 return readerLineInfo != null && readerLineInfo.HasLineInfo ();
1328 public override string LookupNamespace (string prefix)
1330 return reader.LookupNamespace (prefix);
1333 public override void MoveToAttribute (int i)
1335 switch (reader.NodeType) {
1336 case XmlNodeType.XmlDeclaration:
1337 case XmlNodeType.DocumentType:
1338 reader.MoveToAttribute (i);
1342 currentAttrType = null;
1343 if (i < reader.AttributeCount) {
1344 reader.MoveToAttribute (i);
1345 this.currentDefaultAttribute = -1;
1346 this.defaultAttributeConsumed = false;
1349 if (i < AttributeCount) {
1350 this.currentDefaultAttribute = i - reader.AttributeCount;
1351 this.defaultAttributeConsumed = false;
1354 throw new ArgumentOutOfRangeException ("i", i, "Attribute index is out of range.");
1357 public override bool MoveToAttribute (string name)
1359 switch (reader.NodeType) {
1360 case XmlNodeType.XmlDeclaration:
1361 case XmlNodeType.DocumentType:
1362 return reader.MoveToAttribute (name);
1365 currentAttrType = null;
1366 bool b = reader.MoveToAttribute (name);
1368 this.currentDefaultAttribute = -1;
1369 this.defaultAttributeConsumed = false;
1373 return MoveToDefaultAttribute (name, null);
1376 public override bool MoveToAttribute (string localName, string ns)
1378 switch (reader.NodeType) {
1379 case XmlNodeType.XmlDeclaration:
1380 case XmlNodeType.DocumentType:
1381 return reader.MoveToAttribute (localName, ns);
1384 currentAttrType = null;
1385 bool b = reader.MoveToAttribute (localName, ns);
1387 this.currentDefaultAttribute = -1;
1388 this.defaultAttributeConsumed = false;
1392 return MoveToDefaultAttribute (localName, ns);
1395 private bool MoveToDefaultAttribute (string localName, string ns)
1397 int idx = this.FindDefaultAttribute (localName, ns);
1400 currentDefaultAttribute = idx;
1401 defaultAttributeConsumed = false;
1405 public override bool MoveToElement ()
1407 currentDefaultAttribute = -1;
1408 defaultAttributeConsumed = false;
1409 currentAttrType = null;
1410 return reader.MoveToElement ();
1413 public override bool MoveToFirstAttribute ()
1415 switch (reader.NodeType) {
1416 case XmlNodeType.XmlDeclaration:
1417 case XmlNodeType.DocumentType:
1418 return reader.MoveToFirstAttribute ();
1421 currentAttrType = null;
1422 if (reader.AttributeCount > 0) {
1423 bool b = reader.MoveToFirstAttribute ();
1425 currentDefaultAttribute = -1;
1426 defaultAttributeConsumed = false;
1431 if (this.defaultAttributes.Length > 0) {
1432 currentDefaultAttribute = 0;
1433 defaultAttributeConsumed = false;
1440 public override bool MoveToNextAttribute ()
1442 switch (reader.NodeType) {
1443 case XmlNodeType.XmlDeclaration:
1444 case XmlNodeType.DocumentType:
1445 return reader.MoveToNextAttribute ();
1448 currentAttrType = null;
1449 if (currentDefaultAttribute >= 0) {
1450 if (defaultAttributes.Length == currentDefaultAttribute + 1)
1452 currentDefaultAttribute++;
1453 defaultAttributeConsumed = false;
1457 bool b = reader.MoveToNextAttribute ();
1459 currentDefaultAttribute = -1;
1460 defaultAttributeConsumed = false;
1464 if (defaultAttributes.Length > 0) {
1465 currentDefaultAttribute = 0;
1466 defaultAttributeConsumed = false;
1473 private XmlSchema ReadExternalSchema (string uri)
1475 Uri absUri = resolver.ResolveUri ((BaseURI != "" ? new Uri (BaseURI) : null), uri);
1476 string absUriString = absUri != null ? absUri.ToString () : String.Empty;
1477 XmlTextReader xtr = null;
1479 xtr = new XmlTextReader (absUriString,
1480 (Stream) resolver.GetEntity (
1481 absUri, null, typeof (Stream)),
1483 return XmlSchema.Read (
1484 xtr, ValidationEventHandler);
1491 private void ExamineAdditionalSchema ()
1493 if (resolver == null)
1495 XmlSchema schema = null;
1496 string schemaLocation = reader.GetAttribute ("schemaLocation", XmlSchema.InstanceNamespace);
1497 bool schemaAdded = false;
1498 if (schemaLocation != null) {
1499 string [] tmp = null;
1501 schemaLocation = XsDatatype.FromName ("token", XmlSchema.Namespace).Normalize (schemaLocation);
1502 tmp = schemaLocation.Split (XmlChar.WhitespaceChars);
1503 } catch (Exception ex) {
1504 if (schemas.Count == 0)
1505 HandleError ("Invalid schemaLocation attribute format.", ex, true);
1506 tmp = new string [0];
1508 if (tmp.Length % 2 != 0)
1509 if (schemas.Count == 0)
1510 HandleError ("Invalid schemaLocation attribute format.");
1511 for (int i = 0; i < tmp.Length; i += 2) {
1513 schema = ReadExternalSchema (tmp [i + 1]);
1514 } catch (Exception) { // FIXME: (wishlist) It is bad manner ;-(
1515 if (!schemas.Contains (tmp [i]))
1516 HandleError (String.Format ("Could not resolve schema location URI: {0}",
1517 i + 1 < tmp.Length ? tmp [i + 1] : String.Empty), null, true);
1520 if (schema.TargetNamespace == null)
1521 schema.TargetNamespace = tmp [i];
1522 else if (schema.TargetNamespace != tmp [i])
1523 HandleError ("Specified schema has different target namespace.");
1526 if (schema != null) {
1527 if (!schemas.Contains (schema.TargetNamespace)) {
1529 schemas.Add (schema);
1533 string noNsSchemaLocation = reader.GetAttribute ("noNamespaceSchemaLocation", XmlSchema.InstanceNamespace);
1534 if (noNsSchemaLocation != null) {
1536 schema = ReadExternalSchema (noNsSchemaLocation);
1537 } catch (Exception) { // FIXME: (wishlist) It is bad manner ;-(
1538 if (schemas.Count != 0)
1539 HandleError ("Could not resolve schema location URI: " + noNsSchemaLocation, null, true);
1541 if (schema != null && schema.TargetNamespace != null)
1542 HandleError ("Specified schema has different target namespace.");
1544 if (schema != null) {
1545 if (!schemas.Contains (schema.TargetNamespace)) {
1547 schemas.Add (schema);
1550 // FIXME: should call Reprocess()?
1555 public override bool Read ()
1557 validationStarted = true;
1558 currentDefaultAttribute = -1;
1559 defaultAttributeConsumed = false;
1560 currentAttrType = null;
1561 #region ID Constraints
1562 if (this.checkIdentity)
1563 idManager.OnStartElement ();
1565 defaultAttributes = emptyAttributeArray;
1567 bool result = reader.Read ();
1568 #region ID Constraints
1569 // 3.3.4 ElementLocallyValidElement 7 = Root Valid.
1570 if (!result && this.checkIdentity &&
1571 idManager.HasMissingIDReferences ())
1572 HandleError ("There are missing ID references: " + idManager.GetMissingIDString ());
1575 // FIXME: schemaLocation could be specified
1577 if (reader.Depth == 0 &&
1578 reader.NodeType == XmlNodeType.Element)
1579 ExamineAdditionalSchema ();
1580 if (schemas.Count == 0)
1582 if (!schemas.IsCompiled)
1585 switch (reader.NodeType) {
1586 case XmlNodeType.Element:
1587 #region Key Constraints
1588 if (checkKeyConstraints)
1589 this.elementQNameStack.Add (new QName (reader.LocalName, reader.NamespaceURI));
1592 // If there is no schema information, then no validation is performed.
1593 if (skipValidationDepth < 0 || reader.Depth <= skipValidationDepth) {
1594 ValidateEndSimpleContent ();
1595 AssessStartElementSchemaValidity ();
1598 if (reader.IsEmptyElement)
1599 goto case XmlNodeType.EndElement;
1601 shouldValidateCharacters = true;
1603 case XmlNodeType.EndElement:
1604 if (reader.Depth == skipValidationDepth)
1605 skipValidationDepth = -1;
1606 else if (skipValidationDepth < 0 || reader.Depth <= skipValidationDepth)
1607 AssessEndElementSchemaValidity ();
1609 if (checkKeyConstraints)
1610 elementQNameStack.RemoveAt (elementQNameStack.Count - 1);
1613 case XmlNodeType.CDATA:
1614 case XmlNodeType.SignificantWhitespace:
1615 case XmlNodeType.Text:
1616 // FIXME: does this check make sense?
1617 ComplexType ct = Context.ActualType as ComplexType;
1618 if (ct != null && storedCharacters.Length > 0) {
1619 switch (ct.ContentType) {
1620 case XmlSchemaContentType.ElementOnly:
1621 case XmlSchemaContentType.Empty:
1622 HandleError ("Not allowed character content was found.");
1627 ValidateCharacters ();
1634 public override bool ReadAttributeValue ()
1636 if (currentDefaultAttribute < 0)
1637 return reader.ReadAttributeValue ();
1639 if (this.defaultAttributeConsumed)
1642 defaultAttributeConsumed = true;
1647 public override string ReadInnerXml ()
1649 // MS.NET 1.0 has a serious bug here. It skips validation.
1650 return reader.ReadInnerXml ();
1653 public override string ReadOuterXml ()
1655 // MS.NET 1.0 has a serious bug here. It skips validation.
1656 return reader.ReadOuterXml ();
1660 // XmlReader.ReadString() should call derived this.Read().
1661 public override string ReadString ()
1664 return reader.ReadString ();
1666 return base.ReadString ();
1670 // This class itself does not have this feature.
1671 public override void ResolveEntity ()
1673 reader.ResolveEntity ();
1677 internal class XsdValidationContext
1679 public XsdValidationContext ()
1683 // Some of them might be missing (See the spec section 5.3, and also 3.3.4).
1684 public XsElement Element;
1685 public object XsiType; // xsi:type
1686 internal XsdValidationState State;
1688 // Note that it represents current element's type.
1689 public object ActualType {
1691 if (XsiType != null)
1694 return Element != null ? Element.ElementType : null;
1699 public XmlSchemaType ActualSchemaType {
1701 object at = ActualType;
1704 XmlSchemaType st = at as XmlSchemaType;
1706 st = XmlSchemaType.GetBuiltInSimpleType (
1707 ((XmlSchemaDatatype) at).TypeCode);
1713 public bool IsInvalid {
1714 get { return State == XsdValidationState.Invalid; }
1717 public object Clone ()
1719 return MemberwiseClone ();
1722 public void EvaluateStartElement (
1723 string localName, string ns)
1725 State = State.EvaluateStartElement (localName, ns);
1728 public bool EvaluateEndElement ()
1730 return State.EvaluateEndElement ();
1733 public void SetElement (XsElement element)
1739 internal class XsdIDManager
1741 public XsdIDManager ()
1745 Hashtable idList = new Hashtable ();
1746 ArrayList missingIDReferences;
1747 string thisElementId;
1749 private ArrayList MissingIDReferences {
1751 if (missingIDReferences == null)
1752 missingIDReferences = new ArrayList ();
1753 return missingIDReferences;
1757 public void OnStartElement ()
1759 thisElementId = null;
1763 public string AssessEachAttributeIdentityConstraint (
1764 XsDatatype dt, object parsedValue, string elementName)
1766 // Validate identity constraints.
1767 string str = parsedValue as string;
1768 switch (dt.TokenizedType) {
1769 case XmlTokenizedType.ID:
1770 if (thisElementId != null)
1771 return "ID type attribute was already assigned in the containing element.";
1773 thisElementId = str;
1774 if (idList.ContainsKey (str))
1775 return "Duplicate ID value was found.";
1777 idList.Add (str, elementName);
1778 if (MissingIDReferences.Contains (str))
1779 MissingIDReferences.Remove (str);
1781 case XmlTokenizedType.IDREF:
1782 if (!idList.Contains (str))
1783 MissingIDReferences.Add (str);
1785 case XmlTokenizedType.IDREFS:
1786 string [] idrefs = (string []) parsedValue;
1787 for (int i = 0; i < idrefs.Length; i++) {
1788 string id = idrefs [i];
1789 if (!idList.Contains (id))
1790 MissingIDReferences.Add (id);
1797 public bool HasMissingIDReferences ()
1799 return missingIDReferences != null
1800 && missingIDReferences.Count > 0;
1803 public string GetMissingIDString ()
1805 return String.Join (" ",
1806 MissingIDReferences.ToArray (typeof (string))