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;
32 using System.Collections.Specialized;
35 using System.Xml.Schema;
38 namespace Mono.Xml.Schema
40 internal class XsdValidatingReader : XmlReader, IXmlLineInfo, IHasXmlSchemaInfo, IHasXmlParserContext, IXmlNamespaceResolver
42 static readonly XmlSchemaAttribute [] emptyAttributeArray =
43 new XmlSchemaAttribute [0];
47 IHasXmlSchemaInfo sourceReaderSchemaInfo;
48 IXmlLineInfo readerLineInfo;
49 ValidationType validationType;
50 XmlSchemaSet schemas = new XmlSchemaSet ();
51 bool namespaces = true;
53 bool checkIdentity = true;
54 Hashtable idList = new Hashtable ();
55 ArrayList missingIDReferences;
58 ArrayList keyTables = new ArrayList ();
59 ArrayList currentKeyFieldConsumers;
61 XsdValidationStateManager stateManager =
62 new XsdValidationStateManager ();
63 XsdValidationContext context = new XsdValidationContext ();
65 int skipValidationDepth = -1;
67 StringBuilder storedCharacters = new StringBuilder ();
68 bool shouldValidateCharacters;
70 XmlSchemaAttribute [] defaultAttributes = emptyAttributeArray;
71 int currentDefaultAttribute = -1;
72 ArrayList defaultAttributesCache = new ArrayList ();
73 bool defaultAttributeConsumed;
74 XmlQualifiedName attrQName;
76 ArrayList elementQNameStack = new ArrayList ();
80 // Validation engine cached object
81 ArrayList tmpKeyrefPool;
84 public XsdValidatingReader (XmlReader reader)
87 readerLineInfo = reader as IXmlLineInfo;
88 sourceReaderSchemaInfo = reader as IHasXmlSchemaInfo;
92 public ValidationEventHandler ValidationEventHandler;
95 private XmlQualifiedName CurrentQName {
97 if (attrQName == null)
98 attrQName = new XmlQualifiedName (LocalName, NamespaceURI);
103 internal ArrayList CurrentKeyFieldConsumers {
105 if (currentKeyFieldConsumers == null)
106 currentKeyFieldConsumers = new ArrayList ();
107 return currentKeyFieldConsumers;
111 private ArrayList MissingIDReferences {
113 if (missingIDReferences == null)
114 missingIDReferences = new ArrayList ();
115 return missingIDReferences;
119 // Public Non-overrides
121 public int XsiNilDepth {
122 get { return xsiNilDepth; }
125 public bool Namespaces {
126 get { return namespaces; }
127 set { namespaces = value; }
130 public XmlReader Reader {
131 get { return reader; }
134 // This is required to resolve xsi:schemaLocation
135 public XmlResolver XmlResolver {
141 // This should be changed before the first Read() call.
142 public XmlSchemaSet Schemas {
143 get { return schemas; }
145 if (ReadState != ReadState.Initial)
146 throw new InvalidOperationException ("Schemas must be set before the first call to Read().");
151 public object SchemaType {
153 if (ReadState != ReadState.Interactive)
157 case XmlNodeType.Element:
158 if (context.ActualType != null)
159 return context.ActualType;
161 return SourceReaderSchemaType;
162 case XmlNodeType.Attribute:
163 XmlSchemaComplexType ct = context.ActualType as XmlSchemaComplexType;
165 XmlSchemaAttribute attdef = ct.AttributeUses [CurrentQName] as XmlSchemaAttribute;
167 return attdef.AttributeType;
169 return SourceReaderSchemaType;
171 return SourceReaderSchemaType;
176 private object SourceReaderSchemaType {
177 get { return this.sourceReaderSchemaInfo != null ? sourceReaderSchemaInfo.SchemaType : null; }
180 public ValidationType ValidationType {
181 get { return validationType; }
183 if (ReadState != ReadState.Initial)
184 throw new InvalidOperationException ("ValidationType must be set before reading.");
185 validationType = value;
189 IDictionary IXmlNamespaceResolver.GetNamespacesInScope (XmlNamespaceScope scope)
191 IXmlNamespaceResolver resolver = reader as IXmlNamespaceResolver;
192 if (resolver == null)
193 throw new NotSupportedException ("The input XmlReader does not implement IXmlNamespaceResolver and thus this validating reader cannot collect in-scope namespaces.");
194 return resolver.GetNamespacesInScope (scope);
197 string IXmlNamespaceResolver.LookupPrefix (string ns)
199 return ((IXmlNamespaceResolver) this).LookupPrefix (ns, false);
202 string IXmlNamespaceResolver.LookupPrefix (string ns, bool atomizedNames)
204 IXmlNamespaceResolver resolver = reader as IXmlNamespaceResolver;
205 if (resolver == null)
206 throw new NotSupportedException ("The input XmlReader does not implement IXmlNamespaceResolver and thus this validating reader cannot execute namespace prefix lookup.");
207 return resolver.LookupPrefix (ns, atomizedNames);
210 // It is used only for independent XmlReader use, not for XmlValidatingReader.
212 public override object ReadTypedValue ()
214 public object ReadTypedValue ()
217 XmlSchemaDatatype dt = SchemaType as XmlSchemaDatatype;
218 XmlSchemaSimpleType st = SchemaType as XmlSchemaSimpleType;
225 case XmlNodeType.Element:
229 storedCharacters.Length = 0;
234 case XmlNodeType.SignificantWhitespace:
235 case XmlNodeType.Text:
236 case XmlNodeType.CDATA:
237 storedCharacters.Append (Value);
239 case XmlNodeType.Comment:
245 } while (loop && !EOF && ReadState == ReadState.Interactive);
246 return dt.ParseValue (storedCharacters.ToString (), NameTable, ParserContext.NamespaceManager);
247 case XmlNodeType.Attribute:
248 return dt.ParseValue (Value, NameTable, ParserContext.NamespaceManager);
253 // Public Overrided Properties
255 public override int AttributeCount {
257 return reader.AttributeCount + defaultAttributes.Length;
261 public override string BaseURI {
262 get { return reader.BaseURI; }
265 // If this class is used to implement XmlValidatingReader,
266 // it should be left to DTDValidatingReader. In other cases,
267 // it depends on the reader's ability.
268 public override bool CanResolveEntity {
269 get { return reader.CanResolveEntity; }
272 public override int Depth {
274 if (currentDefaultAttribute < 0)
276 if (this.defaultAttributeConsumed)
277 return reader.Depth + 2;
278 return reader.Depth + 1;
282 public override bool EOF {
283 get { return reader.EOF; }
286 public override bool HasValue {
288 if (currentDefaultAttribute < 0)
289 return reader.HasValue;
294 public override bool IsDefault {
296 if (currentDefaultAttribute < 0)
297 return reader.IsDefault;
302 public override bool IsEmptyElement {
304 if (currentDefaultAttribute < 0)
305 return reader.IsEmptyElement;
310 public override string this [int i] {
311 get { return GetAttribute (i); }
314 public override string this [string name] {
315 get { return GetAttribute (name); }
318 public override string this [string localName, string ns] {
319 get { return GetAttribute (localName, ns); }
322 int IXmlLineInfo.LineNumber {
323 get { return readerLineInfo != null ? readerLineInfo.LineNumber : 0; }
326 int IXmlLineInfo.LinePosition {
327 get { return readerLineInfo != null ? readerLineInfo.LinePosition : 0; }
330 public override string LocalName {
332 if (currentDefaultAttribute < 0)
333 return reader.LocalName;
334 if (defaultAttributeConsumed)
336 return defaultAttributes [currentDefaultAttribute].QualifiedName.Name;
340 public override string Name {
342 if (currentDefaultAttribute < 0)
344 if (defaultAttributeConsumed)
347 XmlQualifiedName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
348 string prefix = Prefix;
349 if (prefix == String.Empty)
352 return String.Concat (prefix, ":", qname.Name);
356 public override string NamespaceURI {
358 if (currentDefaultAttribute < 0)
359 return reader.NamespaceURI;
360 if (defaultAttributeConsumed)
362 return defaultAttributes [currentDefaultAttribute].QualifiedName.Namespace;
366 public override XmlNameTable NameTable {
367 get { return reader.NameTable; }
370 public override XmlNodeType NodeType {
372 if (currentDefaultAttribute < 0)
373 return reader.NodeType;
374 if (defaultAttributeConsumed)
375 return XmlNodeType.Text;
376 return XmlNodeType.Attribute;
380 public XmlParserContext ParserContext {
381 get { return XmlSchemaUtil.GetParserContext (reader); }
384 public override string Prefix {
386 if (currentDefaultAttribute < 0)
387 return reader.Prefix;
388 if (defaultAttributeConsumed)
390 XmlQualifiedName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
391 string prefix = this.ParserContext.NamespaceManager.LookupPrefix (qname.Namespace, false);
399 public override char QuoteChar {
400 get { return reader.QuoteChar; }
403 public override ReadState ReadState {
404 get { return reader.ReadState; }
407 public override string Value {
409 if (currentDefaultAttribute < 0)
411 string value = defaultAttributes [currentDefaultAttribute].ValidatedDefaultValue;
413 value = defaultAttributes [currentDefaultAttribute].ValidatedFixedValue;
418 public override string XmlLang {
420 string xmlLang = reader.XmlLang;
423 int idx = this.FindDefaultAttribute ("lang", XmlNamespaceManager.XmlnsXml);
426 xmlLang = defaultAttributes [idx].ValidatedDefaultValue;
428 xmlLang = defaultAttributes [idx].ValidatedFixedValue;
433 public override XmlSpace XmlSpace {
435 XmlSpace space = reader.XmlSpace;
436 if (space != XmlSpace.None)
438 int idx = this.FindDefaultAttribute ("space", XmlNamespaceManager.XmlnsXml);
440 return XmlSpace.None;
441 string spaceSpec = defaultAttributes [idx].ValidatedDefaultValue;
442 if (spaceSpec == null)
443 spaceSpec = defaultAttributes [idx].ValidatedFixedValue;
444 return (XmlSpace) Enum.Parse (typeof (XmlSpace), spaceSpec, false);
450 private XmlQualifiedName QualifyName (string name)
452 return XmlQualifiedName.Parse (name, this);
455 private void HandleError (string error)
457 HandleError (error, null);
460 private void HandleError (string error, Exception innerException)
462 HandleError (error, innerException, false);
465 private void HandleError (string error, Exception innerException, bool isWarning)
467 if (ValidationType == ValidationType.None) // extra quick check
470 XmlSchemaException schemaException = new XmlSchemaException (error,
471 this, this.BaseURI, null, innerException);
472 HandleError (schemaException, isWarning);
475 private void HandleError (XmlSchemaException schemaException)
477 HandleError (schemaException, false);
480 private void HandleError (XmlSchemaException schemaException, bool isWarning)
482 if (ValidationType == ValidationType.None)
485 ValidationEventArgs e = new ValidationEventArgs (schemaException,
486 schemaException.Message, isWarning ? XmlSeverityType.Warning : XmlSeverityType.Error);
488 if (ValidationEventHandler != null)
489 ValidationEventHandler (this, e);
491 else if (e.Severity == XmlSeverityType.Error)
495 private XmlSchemaElement FindElement (string name, string ns)
497 return (XmlSchemaElement) schemas.GlobalElements [new XmlQualifiedName (name, ns)];
500 private XmlSchemaType FindType (XmlQualifiedName qname)
502 return (XmlSchemaType) schemas.GlobalTypes [qname];
505 private void ValidateStartElementParticle ()
507 stateManager.CurrentElement = null;
508 context.EvaluateStartElement (reader.LocalName,
509 reader.NamespaceURI);
510 if (context.State == XsdValidationState.Invalid)
511 HandleError ("Invalid start element: " + reader.NamespaceURI + ":" + reader.LocalName);
513 context.SetElement (stateManager.CurrentElement);
516 private void ValidateEndElementParticle ()
518 if (context.State != null) {
519 if (!context.State.EvaluateEndElement ()) {
520 HandleError ("Invalid end element: " + reader.Name);
526 // Utility for missing validation completion related to child items.
527 private void ValidateCharacters ()
529 if (xsiNilDepth >= 0 && xsiNilDepth < reader.Depth)
530 HandleError ("Element item appeared, while current element context is nil.");
532 storedCharacters.Append (reader.Value);
535 // Utility for missing validation completion related to child items.
536 private void ValidateEndCharacters ()
538 if (context.ActualType == null)
541 string value = storedCharacters.ToString ();
543 if (storedCharacters.Length == 0) {
544 // 3.3.4 Element Locally Valid (Element) 5.1.2
545 if (context.Element != null) {
546 if (context.Element.ValidatedDefaultValue != null)
547 value = context.Element.ValidatedDefaultValue;
551 XmlSchemaDatatype dt = context.ActualType as XmlSchemaDatatype;
552 XmlSchemaSimpleType st = context.ActualType as XmlSchemaSimpleType;
557 XmlSchemaComplexType ct = context.ActualType as XmlSchemaComplexType;
559 switch (ct.ContentType) {
560 case XmlSchemaContentType.ElementOnly:
561 case XmlSchemaContentType.Empty:
562 if (storedCharacters.Length > 0)
563 HandleError ("Character content not allowed.");
569 // 3.3.4 Element Locally Valid (Element) :: 5.2.2.2. Fixed value constraints
570 if (context.Element != null && context.Element.ValidatedFixedValue != null)
571 if (value != context.Element.ValidatedFixedValue)
572 HandleError ("Fixed value constraint was not satisfied.");
573 AssessStringValid (st, dt, value);
576 // Identity field value
577 if (currentKeyFieldConsumers != null) {
578 while (this.currentKeyFieldConsumers.Count > 0) {
579 XsdKeyEntryField field = this.currentKeyFieldConsumers [0] as XsdKeyEntryField;
580 if (field.Identity != null)
581 HandleError ("Two or more identical field was found. Former value is '" + field.Identity + "' .");
582 object identity = null; // This means empty value
585 identity = dt.ParseValue (value, NameTable, ParserContext.NamespaceManager);
586 } catch (Exception ex) { // FIXME: (wishlist) This is bad manner ;-(
587 HandleError ("Identity value is invalid against its data type " + dt.TokenizedType, ex);
590 if (identity == null)
593 if (!field.SetIdentityField (identity, reader.Depth == xsiNilDepth, dt as XsdAnySimpleType, this))
594 HandleError ("Two or more identical key value was found: '" + value + "' .");
595 this.currentKeyFieldConsumers.RemoveAt (0);
599 shouldValidateCharacters = false;
602 // 3.14.4 String Valid
603 private void AssessStringValid (XmlSchemaSimpleType st,
604 XmlSchemaDatatype dt, string value)
606 XmlSchemaDatatype validatedDatatype = dt;
608 string normalized = validatedDatatype.Normalize (value);
610 XmlSchemaDatatype itemDatatype;
611 XmlSchemaSimpleType itemSimpleType;
612 switch (st.DerivedBy) {
613 case XmlSchemaDerivationMethod.List:
614 XmlSchemaSimpleTypeList listContent = st.Content as XmlSchemaSimpleTypeList;
615 values = normalized.Split (XmlChar.WhitespaceChars);
616 itemDatatype = listContent.ValidatedListItemType as XmlSchemaDatatype;
617 itemSimpleType = listContent.ValidatedListItemType as XmlSchemaSimpleType;
618 for (int vi = 0; vi < values.Length; vi++) {
619 string each = values [vi];
620 if (each == String.Empty)
622 // validate against ValidatedItemType
623 if (itemDatatype != null) {
625 itemDatatype.ParseValue (each, NameTable, ParserContext.NamespaceManager);
626 } catch (Exception ex) { // FIXME: (wishlist) better exception handling ;-(
627 HandleError ("List type value contains one or more invalid values.", ex);
632 AssessStringValid (itemSimpleType, itemSimpleType.Datatype, each);
635 case XmlSchemaDerivationMethod.Union:
636 XmlSchemaSimpleTypeUnion union = st.Content as XmlSchemaSimpleTypeUnion;
638 string each = normalized;
639 // validate against ValidatedItemType
641 foreach (object eachType in union.ValidatedTypes) {
642 itemDatatype = eachType as XmlSchemaDatatype;
643 itemSimpleType = eachType as XmlSchemaSimpleType;
644 if (itemDatatype != null) {
646 itemDatatype.ParseValue (each, NameTable, ParserContext.NamespaceManager);
647 } catch (Exception) { // FIXME: (wishlist) better exception handling ;-(
653 AssessStringValid (itemSimpleType, itemSimpleType.Datatype, each);
654 } catch (XmlSchemaException) {
662 HandleError ("Union type value contains one or more invalid values.");
667 case XmlSchemaDerivationMethod.Restriction:
668 XmlSchemaSimpleTypeRestriction str = st.Content as XmlSchemaSimpleTypeRestriction;
671 /* Don't forget to validate against inherited type's facets
672 * Could we simplify this by assuming that the basetype will also
675 // mmm, will check later.
676 XmlSchemaSimpleType baseType = st.BaseXmlSchemaType as XmlSchemaSimpleType;
677 if (baseType != null) {
678 AssessStringValid(baseType, dt, normalized);
680 if (!str.ValidateValueWithFacets (normalized, NameTable)) {
681 HandleError ("Specified value was invalid against the facets.");
685 validatedDatatype = st.Datatype;
689 if (validatedDatatype != null) {
691 validatedDatatype.ParseValue (value, NameTable, ParserContext.NamespaceManager);
692 } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
693 HandleError ("Invalidly typed data was specified.", ex);
698 private object GetXsiType (string name)
700 object xsiType = null;
701 XmlQualifiedName typeQName = QualifyName (name);
702 if (typeQName == XmlSchemaComplexType.AnyTypeName)
703 xsiType = XmlSchemaComplexType.AnyType;
704 else if (XmlSchemaUtil.IsBuiltInDatatypeName (typeQName))
705 xsiType = XmlSchemaDatatype.FromName (typeQName);
707 xsiType = FindType (typeQName);
711 // It is common to ElementLocallyValid::4 and SchemaValidityAssessment::1.2.1.2.4
712 private void AssessLocalTypeDerivationOK (object xsiType, object baseType, XmlSchemaDerivationMethod flag)
714 XmlSchemaType xsiSchemaType = xsiType as XmlSchemaType;
715 XmlSchemaComplexType baseComplexType = baseType as XmlSchemaComplexType;
716 XmlSchemaComplexType xsiComplexType = xsiSchemaType as XmlSchemaComplexType;
717 if (xsiType != baseType) {
718 // Extracted (not extraneous) check for 3.4.6 TypeDerivationOK.
719 if (baseComplexType != null)
720 flag |= baseComplexType.BlockResolved;
721 if (flag == XmlSchemaDerivationMethod.All) {
722 HandleError ("Prohibited element type substitution.");
724 } else if (xsiSchemaType != null && (flag & xsiSchemaType.DerivedBy) != 0) {
725 HandleError ("Prohibited element type substitution.");
730 if (xsiComplexType != null)
732 xsiComplexType.ValidateTypeDerivationOK (baseType, null, null);
733 } catch (XmlSchemaException ex) {
734 // HandleError ("Locally specified schema complex type derivation failed. " + ex.Message, ex);
738 XmlSchemaSimpleType xsiSimpleType = xsiType as XmlSchemaSimpleType;
739 if (xsiSimpleType != null) {
741 xsiSimpleType.ValidateTypeDerivationOK (baseType, null, null, true);
742 } catch (XmlSchemaException ex) {
743 // HandleError ("Locally specified schema simple type derivation failed. " + ex.Message, ex);
747 else if (xsiType is XmlSchemaDatatype) {
751 HandleError ("Primitive data type cannot be derived type using xsi:type specification.");
755 // Section 3.3.4 of the spec.
756 private void AssessStartElementSchemaValidity ()
758 // If the reader is inside xsi:nil (and failed on validation),
759 // then simply skip its content.
760 if (xsiNilDepth >= 0 && xsiNilDepth < reader.Depth)
761 HandleError ("Element item appeared, while current element context is nil.");
763 context.XsiType = null;
764 // If validation state exists, then first assess particle validity.
765 if (context.State != null) {
766 ValidateStartElementParticle ();
769 string xsiNilValue = reader.GetAttribute ("nil", XmlSchema.InstanceNamespace);
770 if (xsiNilValue != null)
771 xsiNilValue = xsiNilValue.Trim (XmlChar.WhitespaceChars);
772 bool isXsiNil = xsiNilValue == "true";
773 if (isXsiNil && this.xsiNilDepth < 0)
774 xsiNilDepth = reader.Depth;
776 // [Schema Validity Assessment (Element) 1.2]
777 // Evaluate "local type definition" from xsi:type.
778 // (See spec 3.3.4 Schema Validity Assessment (Element) 1.2.1.2.3.
779 // Note that Schema Validity Assessment(Element) 1.2 takes
780 // precedence than 1.1 of that.
782 string xsiTypeName = reader.GetAttribute ("type", XmlSchema.InstanceNamespace);
783 if (xsiTypeName != null) {
784 xsiTypeName = xsiTypeName.Trim (XmlChar.WhitespaceChars);
785 object xsiType = GetXsiType (xsiTypeName);
787 HandleError ("The instance type was not found: " + xsiTypeName + " .");
789 XmlSchemaType xsiSchemaType = xsiType as XmlSchemaType;
790 if (xsiSchemaType != null && this.context.Element != null) {
791 XmlSchemaType elemBaseType = context.Element.ElementType as XmlSchemaType;
792 if (elemBaseType != null && (xsiSchemaType.DerivedBy & elemBaseType.FinalResolved) != 0)
793 HandleError ("The instance type is prohibited by the type of the context element.");
794 if (elemBaseType != xsiType && (xsiSchemaType.DerivedBy & this.context.Element.BlockResolved) != 0)
795 HandleError ("The instance type is prohibited by the context element.");
797 XmlSchemaComplexType xsiComplexType = xsiType as XmlSchemaComplexType;
798 if (xsiComplexType != null && xsiComplexType.IsAbstract)
799 HandleError ("The instance type is abstract: " + xsiTypeName + " .");
801 // If current schema type exists, then this xsi:type must be
802 // valid extension of that type. See 1.2.1.2.4.
803 if (context.Element != null) {
804 AssessLocalTypeDerivationOK (xsiType, context.Element.ElementType, context.Element.BlockResolved);
806 AssessStartElementLocallyValidType (xsiType); // 1.2.2:
807 context.XsiType = xsiType;
812 // Create Validation Root, if not exist.
813 // [Schema Validity Assessment (Element) 1.1]
814 if (context.Element == null)
815 context.SetElement (FindElement (reader.LocalName, reader.NamespaceURI));
816 if (context.Element != null) {
817 if (xsiTypeName == null) {
818 AssessElementLocallyValidElement (context.Element, xsiNilValue); // 1.1.2
821 switch (stateManager.ProcessContents) {
822 case XmlSchemaContentProcessing.Skip:
824 case XmlSchemaContentProcessing.Lax:
827 if (xsiTypeName == null &&
828 (schemas.Contains (reader.NamespaceURI) ||
829 !schemas.MissedSubComponents (reader.NamespaceURI)))
830 HandleError ("Element declaration for " + reader.LocalName + " is missing.");
835 XsdValidationState next = null;
836 if (stateManager.ProcessContents
837 == XmlSchemaContentProcessing.Skip)
838 skipValidationDepth = reader.Depth;
840 // create child particle state.
841 XmlSchemaComplexType xsComplexType = SchemaType as XmlSchemaComplexType;
842 if (xsComplexType != null)
843 next = stateManager.Create (xsComplexType.ValidatableParticle);
844 else if (stateManager.ProcessContents == XmlSchemaContentProcessing.Lax)
845 next = stateManager.Create (XmlSchemaAny.AnyTypeContent);
847 next = stateManager.Create (XmlSchemaParticle.Empty);
850 AssessStartIdentityConstraints ();
852 context.PushScope ();
854 context.State = next;
857 // 3.3.4 Element Locally Valid (Element)
858 private void AssessElementLocallyValidElement (XmlSchemaElement element, string xsiNilValue)
860 XmlQualifiedName qname = new XmlQualifiedName (reader.LocalName, reader.NamespaceURI);
863 HandleError ("Element declaration is required for " + qname);
865 if (element.ActualIsAbstract)
866 HandleError ("Abstract element declaration was specified for " + qname);
868 if (!element.ActualIsNillable && xsiNilValue != null)
869 HandleError ("This element declaration is not nillable: " + qname);
871 // Note that 3.2.1 xsi:nil constraints are to be validated in
872 else if (xsiNilValue == "true") {
873 // AssessElementSchemaValidity() and ValidateCharacters()
875 if (element.ValidatedFixedValue != null)
876 HandleError ("Schema instance nil was specified, where the element declaration for " + qname + "has fixed value constraints.");
879 string xsiType = reader.GetAttribute ("type", XmlSchema.InstanceNamespace);
880 if (xsiType != null) {
881 context.XsiType = GetXsiType (xsiType);
882 AssessLocalTypeDerivationOK (context.XsiType, element.ElementType, element.BlockResolved);
885 context.XsiType = null;
887 // 5 Not all things cannot be assessed here.
888 // It is common to 5.1 and 5.2
889 if (element.ElementType != null)
890 AssessStartElementLocallyValidType (SchemaType);
892 // 6. should be out from here.
893 // See invokation of AssessStartIdentityConstraints().
895 // 7 is going to be validated in Read() (in case of xmlreader's EOF).
898 // 3.3.4 Element Locally Valid (Type)
899 private void AssessStartElementLocallyValidType (object schemaType)
901 if (schemaType == null) { // 1.
902 HandleError ("Schema type does not exist.");
905 XmlSchemaComplexType cType = schemaType as XmlSchemaComplexType;
906 XmlSchemaSimpleType sType = schemaType as XmlSchemaSimpleType;
909 while (reader.MoveToNextAttribute ()) {
910 if (reader.NamespaceURI == XmlNamespaceManager.XmlnsXmlns)
912 if (reader.NamespaceURI != XmlSchema.InstanceNamespace)
913 HandleError ("Current simple type cannot accept attributes other than schema instance namespace.");
914 switch (reader.LocalName) {
917 case "schemaLocation":
918 case "noNamespaceSchemaLocation":
921 HandleError ("Unknown schema instance namespace attribute: " + reader.LocalName);
925 reader.MoveToElement ();
926 // 3.1.2 and 3.1.3 cannot be assessed here.
927 } else if (cType != null) {
928 if (cType.IsAbstract) { // 2.
929 HandleError ("Target complex type is abstract.");
933 AssessElementLocallyValidComplexType (cType);
937 // 3.4.4 Element Locally Valid (Complex Type)
938 private void AssessElementLocallyValidComplexType (XmlSchemaComplexType cType)
941 if (cType.IsAbstract)
942 HandleError ("Target complex type is abstract.");
944 // 2 (xsi:nil and content prohibition)
945 // See AssessStartElementSchemaValidity() and ValidateCharacters()
947 // 3. attribute uses and
949 if (reader.MoveToFirstAttribute ()) {
951 switch (reader.NamespaceURI) {
952 case"http://www.w3.org/2000/xmlns/":
953 case XmlSchema.InstanceNamespace:
956 XmlQualifiedName qname = new XmlQualifiedName (reader.LocalName, reader.NamespaceURI);
957 XmlSchemaObject attMatch = FindAttributeDeclaration (cType, qname);
958 if (attMatch == null)
959 HandleError ("Attribute declaration was not found for " + qname);
960 XmlSchemaAttribute attdecl = attMatch as XmlSchemaAttribute;
961 if (attdecl != null) {
962 AssessAttributeLocallyValidUse (attdecl);
963 AssessAttributeLocallyValid (attdecl);
964 } // otherwise anyAttribute or null.
965 } while (reader.MoveToNextAttribute ());
966 reader.MoveToElement ();
969 // Collect default attributes.
971 foreach (DictionaryEntry entry in cType.AttributeUses) {
972 XmlSchemaAttribute attr = (XmlSchemaAttribute) entry.Value;
973 if (reader [attr.QualifiedName.Name, attr.QualifiedName.Namespace] == null) {
974 if (attr.ValidatedUse == XmlSchemaUse.Required &&
975 attr.ValidatedFixedValue == null)
976 HandleError ("Required attribute " + attr.QualifiedName + " was not found.");
977 else if (attr.ValidatedDefaultValue != null || attr.ValidatedFixedValue != null)
978 defaultAttributesCache.Add (attr);
981 if (defaultAttributesCache.Count == 0)
982 defaultAttributes = emptyAttributeArray;
984 defaultAttributes = (XmlSchemaAttribute [])
985 defaultAttributesCache.ToArray (
986 typeof (XmlSchemaAttribute));
987 defaultAttributesCache.Clear ();
988 // 5. wild IDs was already checked above.
991 // Spec 3.10.4 Item Valid (Wildcard)
992 private static bool AttributeWildcardItemValid (XmlSchemaAnyAttribute anyAttr, XmlQualifiedName qname, string ns)
994 if (anyAttr.HasValueAny)
996 if (anyAttr.HasValueOther && (anyAttr.TargetNamespace == "" || ns != anyAttr.TargetNamespace))
998 if (anyAttr.HasValueTargetNamespace && ns == anyAttr.TargetNamespace)
1000 if (anyAttr.HasValueLocal && ns == "")
1002 for (int i = 0; i < anyAttr.ResolvedNamespaces.Count; i++)
1003 if (anyAttr.ResolvedNamespaces [i] == ns)
1008 private XmlSchemaObject FindAttributeDeclaration (
1009 XmlSchemaComplexType cType,
1010 XmlQualifiedName qname)
1012 XmlSchemaObject result = cType.AttributeUses [qname];
1015 if (cType.AttributeWildcard == null)
1018 if (!AttributeWildcardItemValid (cType.AttributeWildcard, qname, reader.NamespaceURI))
1021 if (cType.AttributeWildcard.ResolvedProcessContents == XmlSchemaContentProcessing.Skip)
1022 return cType.AttributeWildcard;
1023 XmlSchemaAttribute attr = schemas.GlobalAttributes [qname] as XmlSchemaAttribute;
1026 if (cType.AttributeWildcard.ResolvedProcessContents == XmlSchemaContentProcessing.Lax)
1027 return cType.AttributeWildcard;
1032 // 3.2.4 Attribute Locally Valid and 3.4.4
1033 private void AssessAttributeLocallyValid (XmlSchemaAttribute attr)
1036 if (attr.AttributeType == null)
1037 HandleError ("Attribute type is missing for " + attr.QualifiedName);
1038 XmlSchemaDatatype dt = attr.AttributeType as XmlSchemaDatatype;
1040 dt = ((XmlSchemaSimpleType) attr.AttributeType).Datatype;
1041 // It is a bit heavy process, so let's omit as long as possible ;-)
1042 if (dt != XmlSchemaSimpleType.AnySimpleType || attr.ValidatedFixedValue != null) {
1043 string normalized = dt.Normalize (reader.Value);
1044 object parsedValue = null;
1046 parsedValue = dt.ParseValue (normalized, reader.NameTable, this.ParserContext.NamespaceManager);
1047 } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
1048 HandleError ("Attribute value is invalid against its data type " + dt.TokenizedType, ex);
1050 if (attr.ValidatedFixedValue != null && attr.ValidatedFixedValue != normalized) {
1051 HandleError ("The value of the attribute " + attr.QualifiedName + " does not match with its fixed value.");
1052 parsedValue = dt.ParseValue (attr.ValidatedFixedValue, reader.NameTable, this.ParserContext.NamespaceManager);
1054 if (this.checkIdentity)
1055 AssessEachAttributeIdentityConstraint (dt, parsedValue);
1060 private void AssessEachAttributeIdentityConstraint (
1061 XmlSchemaDatatype dt, object parsedValue)
1063 // Validate identity constraints.
1064 string str = parsedValue as string;
1065 switch (dt.TokenizedType) {
1066 case XmlTokenizedType.ID:
1067 if (thisElementId != null)
1068 HandleError ("ID type attribute was already assigned in the containing element.");
1069 thisElementId = str;
1070 if (idList.Contains (str))
1071 HandleError ("Duplicate ID value was found.");
1073 idList.Add (str, str);
1074 if (MissingIDReferences.Contains (str))
1075 MissingIDReferences.Remove (str);
1077 case XmlTokenizedType.IDREF:
1078 if (!idList.Contains (str))
1079 MissingIDReferences.Add (str);
1081 case XmlTokenizedType.IDREFS:
1082 string [] idrefs = (string []) parsedValue;
1083 for (int i = 0; i < idrefs.Length; i++) {
1084 string id = idrefs [i];
1085 if (!idList.Contains (id))
1086 MissingIDReferences.Add (id);
1092 private void AssessAttributeLocallyValidUse (XmlSchemaAttribute attr)
1094 // This is extra check than spec 3.5.4
1095 if (attr.ValidatedUse == XmlSchemaUse.Prohibited)
1096 HandleError ("Attribute " + attr.QualifiedName + " is prohibited in this context.");
1099 private void AssessEndElementSchemaValidity ()
1101 ValidateEndElementParticle (); // validate against childrens' state.
1103 if (shouldValidateCharacters) {
1104 ValidateEndCharacters ();
1105 shouldValidateCharacters = false;
1108 // 3.3.4 Assess ElementLocallyValidElement 5: value constraints.
1109 // 3.3.4 Assess ElementLocallyValidType 3.1.3. = StringValid(3.14.4)
1110 // => ValidateEndCharacters().
1112 // Reset Identity constraints.
1113 for (int i = 0; i < keyTables.Count; i++) {
1114 XsdKeyTable keyTable = this.keyTables [i] as XsdKeyTable;
1115 if (keyTable.StartDepth == reader.Depth) {
1116 EndIdentityValidation (keyTable);
1118 for (int k = 0; k < keyTable.Entries.Count; k++) {
1119 XsdKeyEntry entry = keyTable.Entries [k] as XsdKeyEntry;
1120 // Remove finished (maybe key not found) entries.
1121 if (entry.StartDepth == reader.Depth) {
1123 keyTable.FinishedEntries.Add (entry);
1124 else if (entry.KeySequence.SourceSchemaIdentity is XmlSchemaKey)
1125 HandleError ("Key sequence is missing.");
1126 keyTable.Entries.RemoveAt (k);
1129 // Pop validated key depth to find two or more fields.
1131 for (int j = 0; j < entry.KeyFields.Count; j++) {
1132 XsdKeyEntryField kf = entry.KeyFields [j];
1133 if (!kf.FieldFound && kf.FieldFoundDepth == reader.Depth) {
1134 kf.FieldFoundDepth = 0;
1135 kf.FieldFoundPath = null;
1142 for (int i = 0; i < keyTables.Count; i++) {
1143 XsdKeyTable keyseq = this.keyTables [i] as XsdKeyTable;
1144 if (keyseq.StartDepth == reader.Depth) {
1145 keyTables.RemoveAt (i);
1150 // Reset xsi:nil, if required.
1151 if (xsiNilDepth == reader.Depth)
1155 // 3.11.4 Identity Constraint Satisfied
1156 private void AssessStartIdentityConstraints ()
1158 if (tmpKeyrefPool != null)
1159 tmpKeyrefPool.Clear ();
1160 if (context.Element != null && context.Element.Constraints.Count > 0) {
1161 // (a) Create new key sequences, if required.
1162 for (int i = 0; i < context.Element.Constraints.Count; i++) {
1163 XmlSchemaIdentityConstraint ident = (XmlSchemaIdentityConstraint) context.Element.Constraints [i];
1164 XsdKeyTable seq = CreateNewKeyTable (ident);
1165 if (ident is XmlSchemaKeyref) {
1166 if (tmpKeyrefPool == null)
1167 tmpKeyrefPool = new ArrayList ();
1168 tmpKeyrefPool.Add (seq);
1173 // (b) Evaluate current key sequences.
1174 for (int i = 0; i < keyTables.Count; i++) {
1175 XsdKeyTable seq = (XsdKeyTable) keyTables [i];
1176 if (seq.SelectorMatches (this.elementQNameStack, reader) != null) {
1177 // creates and registers new entry.
1178 XsdKeyEntry entry = new XsdKeyEntry (seq, reader);
1179 seq.Entries.Add (entry);
1183 // (c) Evaluate field paths.
1184 for (int i = 0; i < keyTables.Count; i++) {
1185 XsdKeyTable seq = (XsdKeyTable) keyTables [i];
1186 // If possible, create new field entry candidates.
1187 for (int j = 0; j < seq.Entries.Count; j++) {
1188 XsdKeyEntry entry = seq.Entries [j] as XsdKeyEntry;
1190 entry.FieldMatches (this.elementQNameStack, this);
1191 } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
1192 HandleError ("Identity field value is invalid against its data type.", ex);
1198 private XsdKeyTable CreateNewKeyTable (XmlSchemaIdentityConstraint ident)
1200 XsdKeyTable seq = new XsdKeyTable (ident, this);
1201 seq.StartDepth = reader.Depth;
1202 this.keyTables.Add (seq);
1206 private void EndIdentityValidation (XsdKeyTable seq)
1208 ArrayList errors = new ArrayList ();
1209 for (int i = 0; i < seq.Entries.Count; i++) {
1210 XsdKeyEntry entry = (XsdKeyEntry) seq.Entries [i];
1213 if (seq.SourceSchemaIdentity is XmlSchemaKey)
1214 errors.Add ("line " + entry.SelectorLineNumber + "position " + entry.SelectorLinePosition);
1216 if (errors.Count > 0)
1217 HandleError ("Invalid identity constraints were found. Key was not found. "
1218 + String.Join (", ", errors.ToArray (typeof (string)) as string []));
1221 // Find reference target
1222 XmlSchemaKeyref xsdKeyref = seq.SourceSchemaIdentity as XmlSchemaKeyref;
1223 if (xsdKeyref != null) {
1224 for (int i = this.keyTables.Count - 1; i >= 0; i--) {
1225 XsdKeyTable target = this.keyTables [i] as XsdKeyTable;
1226 if (target.SourceSchemaIdentity == xsdKeyref.Target) {
1227 seq.ReferencedKey = target;
1228 for (int j = 0; j < seq.FinishedEntries.Count; j++) {
1229 XsdKeyEntry entry = (XsdKeyEntry) seq.FinishedEntries [j];
1230 for (int k = 0; k < target.FinishedEntries.Count; k++) {
1231 XsdKeyEntry targetEntry = (XsdKeyEntry) target.FinishedEntries [k];
1232 if (entry.CompareIdentity (targetEntry)) {
1233 entry.KeyRefFound = true;
1240 if (seq.ReferencedKey == null)
1241 HandleError ("Target key was not found.");
1242 for (int i = 0; i < seq.FinishedEntries.Count; i++) {
1243 XsdKeyEntry entry = (XsdKeyEntry) seq.FinishedEntries [i];
1244 if (!entry.KeyRefFound)
1245 errors.Add (" line " + entry.SelectorLineNumber + ", position " + entry.SelectorLinePosition);
1247 if (errors.Count > 0)
1248 HandleError ("Invalid identity constraints were found. Referenced key was not found: "
1249 + String.Join (" / ", errors.ToArray (typeof (string)) as string []));
1253 // Overrided Methods
1255 public override void Close ()
1260 public override string GetAttribute (int i)
1262 switch (reader.NodeType) {
1263 case XmlNodeType.XmlDeclaration:
1264 case XmlNodeType.DocumentType:
1265 return reader.GetAttribute (i);
1268 if (reader.AttributeCount > i)
1269 reader.GetAttribute (i);
1270 int defIdx = i - reader.AttributeCount;
1271 if (i < AttributeCount)
1272 return defaultAttributes [defIdx].DefaultValue;
1274 throw new ArgumentOutOfRangeException ("i", i, "Specified attribute index is out of range.");
1277 public override string GetAttribute (string name)
1279 switch (reader.NodeType) {
1280 case XmlNodeType.XmlDeclaration:
1281 case XmlNodeType.DocumentType:
1282 return reader.GetAttribute (name);
1285 string value = reader.GetAttribute (name);
1289 XmlQualifiedName qname = SplitQName (name);
1290 return GetDefaultAttribute (qname.Name, qname.Namespace);
1293 private XmlQualifiedName SplitQName (string name)
1295 if (!XmlChar.IsName (name))
1296 throw new ArgumentException ("Invalid name was specified.", "name");
1298 Exception ex = null;
1299 XmlQualifiedName qname = XmlSchemaUtil.ToQName (reader, name, out ex);
1301 return XmlQualifiedName.Empty;
1306 public override string GetAttribute (string localName, string ns)
1308 switch (reader.NodeType) {
1309 case XmlNodeType.XmlDeclaration:
1310 case XmlNodeType.DocumentType:
1311 return reader.GetAttribute (localName, ns);
1314 string value = reader.GetAttribute (localName, ns);
1318 return GetDefaultAttribute (localName, ns);
1321 private string GetDefaultAttribute (string localName, string ns)
1323 int idx = this.FindDefaultAttribute (localName, ns);
1326 string value = defaultAttributes [idx].ValidatedDefaultValue;
1328 value = defaultAttributes [idx].ValidatedFixedValue;
1332 private int FindDefaultAttribute (string localName, string ns)
1334 for (int i = 0; i < this.defaultAttributes.Length; i++) {
1335 XmlSchemaAttribute attr = defaultAttributes [i];
1336 if (attr.QualifiedName.Name == localName &&
1337 (ns == null || attr.QualifiedName.Namespace == ns))
1343 bool IXmlLineInfo.HasLineInfo ()
1345 return readerLineInfo != null && readerLineInfo.HasLineInfo ();
1348 public override string LookupNamespace (string prefix)
1350 return reader.LookupNamespace (prefix);
1353 string IXmlNamespaceResolver.LookupNamespace (string prefix, bool atomizedNames)
1355 IXmlNamespaceResolver res = reader as IXmlNamespaceResolver;
1357 return res.LookupNamespace (prefix, atomizedNames);
1359 return reader.LookupNamespace (prefix);
1362 public override void MoveToAttribute (int i)
1364 switch (reader.NodeType) {
1365 case XmlNodeType.XmlDeclaration:
1366 case XmlNodeType.DocumentType:
1367 reader.MoveToAttribute (i);
1372 if (i < reader.AttributeCount) {
1373 reader.MoveToAttribute (i);
1374 this.currentDefaultAttribute = -1;
1375 this.defaultAttributeConsumed = false;
1378 if (i < AttributeCount) {
1379 this.currentDefaultAttribute = i - reader.AttributeCount;
1380 this.defaultAttributeConsumed = false;
1383 throw new ArgumentOutOfRangeException ("i", i, "Attribute index is out of range.");
1386 public override bool MoveToAttribute (string name)
1388 switch (reader.NodeType) {
1389 case XmlNodeType.XmlDeclaration:
1390 case XmlNodeType.DocumentType:
1391 return reader.MoveToAttribute (name);
1395 bool b = reader.MoveToAttribute (name);
1397 this.currentDefaultAttribute = -1;
1398 this.defaultAttributeConsumed = false;
1402 return MoveToDefaultAttribute (name, null);
1405 public override bool MoveToAttribute (string localName, string ns)
1407 switch (reader.NodeType) {
1408 case XmlNodeType.XmlDeclaration:
1409 case XmlNodeType.DocumentType:
1410 return reader.MoveToAttribute (localName, ns);
1414 bool b = reader.MoveToAttribute (localName, ns);
1416 this.currentDefaultAttribute = -1;
1417 this.defaultAttributeConsumed = false;
1421 return MoveToDefaultAttribute (localName, ns);
1424 private bool MoveToDefaultAttribute (string localName, string ns)
1426 int idx = this.FindDefaultAttribute (localName, ns);
1429 currentDefaultAttribute = idx;
1430 defaultAttributeConsumed = false;
1434 public override bool MoveToElement ()
1436 currentDefaultAttribute = -1;
1437 defaultAttributeConsumed = false;
1439 return reader.MoveToElement ();
1442 public override bool MoveToFirstAttribute ()
1444 switch (reader.NodeType) {
1445 case XmlNodeType.XmlDeclaration:
1446 case XmlNodeType.DocumentType:
1447 return reader.MoveToFirstAttribute ();
1451 if (reader.AttributeCount > 0) {
1452 bool b = reader.MoveToFirstAttribute ();
1454 currentDefaultAttribute = -1;
1455 defaultAttributeConsumed = false;
1460 if (this.defaultAttributes.Length > 0) {
1461 currentDefaultAttribute = 0;
1462 defaultAttributeConsumed = false;
1469 public override bool MoveToNextAttribute ()
1471 switch (reader.NodeType) {
1472 case XmlNodeType.XmlDeclaration:
1473 case XmlNodeType.DocumentType:
1474 return reader.MoveToNextAttribute ();
1478 if (currentDefaultAttribute >= 0) {
1479 if (defaultAttributes.Length == currentDefaultAttribute + 1)
1481 currentDefaultAttribute++;
1482 defaultAttributeConsumed = false;
1486 bool b = reader.MoveToNextAttribute ();
1488 currentDefaultAttribute = -1;
1489 defaultAttributeConsumed = false;
1493 if (defaultAttributes.Length > 0) {
1494 currentDefaultAttribute = 0;
1495 defaultAttributeConsumed = false;
1502 private void ExamineAdditionalSchema ()
1504 XmlSchema schema = null;
1505 string schemaLocation = reader.GetAttribute ("schemaLocation", XmlSchema.InstanceNamespace);
1506 bool schemaAdded = false;
1507 if (schemaLocation != null) {
1508 string [] tmp = null;
1510 schemaLocation = XmlSchemaDatatype.FromName ("token", XmlSchema.Namespace).Normalize (schemaLocation);
1511 tmp = schemaLocation.Split (XmlChar.WhitespaceChars);
1512 } catch (Exception ex) {
1513 HandleError ("Invalid schemaLocation attribute format.", ex, true);
1514 tmp = new string [0];
1516 if (tmp.Length % 2 != 0)
1517 HandleError ("Invalid schemaLocation attribute format.");
1518 for (int i = 0; i < tmp.Length; i += 2) {
1520 XmlTextReader xtr = null;
1522 absUri = new Uri ((this.BaseURI != "" ? new Uri (BaseURI) : null), tmp [i + 1]);
1523 xtr = new XmlTextReader (absUri.ToString (), NameTable);
1524 schema = XmlSchema.Read (xtr, null);
1525 } catch (Exception) { // FIXME: (wishlist) It is bad manner ;-(
1526 HandleError ("Could not resolve schema location URI: " + absUri, null, true);
1532 if (schema.TargetNamespace == null)
1533 schema.TargetNamespace = tmp [i];
1534 else if (schema.TargetNamespace != tmp [i])
1535 HandleError ("Specified schema has different target namespace.");
1538 if (schema != null) {
1539 if (!schemas.Contains (schema.TargetNamespace)) {
1541 schemas.Add (schema);
1545 string noNsSchemaLocation = reader.GetAttribute ("noNamespaceSchemaLocation", XmlSchema.InstanceNamespace);
1546 if (noNsSchemaLocation != null) {
1548 XmlTextReader xtr = null;
1550 absUri = new Uri ((this.BaseURI != "" ? new Uri (BaseURI) : null), noNsSchemaLocation);
1551 xtr = new XmlTextReader (absUri.ToString (), NameTable);
1552 schema = XmlSchema.Read (xtr, null);
1553 } catch (Exception) { // FIXME: (wishlist) It is bad manner ;-(
1554 HandleError ("Could not resolve schema location URI: " + absUri, null, true);
1559 if (schema != null && schema.TargetNamespace != null)
1560 HandleError ("Specified schema has different target namespace.");
1562 if (schema != null) {
1563 if (!schemas.Contains (schema.TargetNamespace)) {
1565 schemas.Add (schema);
1568 // FIXME: should call Reprocess()?
1573 private bool HasMissingIDReferences ()
1575 return missingIDReferences != null
1576 && missingIDReferences.Count > 0;
1579 public override bool Read ()
1581 currentDefaultAttribute = -1;
1582 defaultAttributeConsumed = false;
1584 if (this.checkIdentity)
1585 thisElementId = null;
1586 defaultAttributes = new XmlSchemaAttribute [0];
1587 if (!schemas.IsCompiled)
1590 bool result = reader.Read ();
1591 // 3.3.4 ElementLocallyValidElement 7 = Root Valid.
1592 if (!result && this.checkIdentity &&
1593 HasMissingIDReferences ())
1594 HandleError ("There are missing ID references: " +
1596 this.missingIDReferences.ToArray (typeof (string)) as string []));
1598 switch (reader.NodeType) {
1599 case XmlNodeType.Element:
1600 // FIXME: schemaLocation could be specified
1602 if (reader.Depth == 0)
1603 ExamineAdditionalSchema ();
1605 this.elementQNameStack.Add (new XmlQualifiedName (reader.LocalName, reader.NamespaceURI));
1607 // If there is no schema information, then no validation is performed.
1608 if (schemas.Count == 0)
1611 if (skipValidationDepth < 0 || reader.Depth <= skipValidationDepth) {
1612 if (shouldValidateCharacters) {
1613 ValidateEndCharacters ();
1614 shouldValidateCharacters = false;
1616 AssessStartElementSchemaValidity ();
1617 storedCharacters.Length = 0;
1620 if (reader.IsEmptyElement)
1621 goto case XmlNodeType.EndElement;
1623 shouldValidateCharacters = true;
1625 case XmlNodeType.EndElement:
1626 if (reader.Depth == skipValidationDepth)
1627 skipValidationDepth = -1;
1628 else if (skipValidationDepth < 0 || reader.Depth <= skipValidationDepth)
1629 AssessEndElementSchemaValidity ();
1631 storedCharacters.Length = 0;
1632 elementQNameStack.RemoveAt (elementQNameStack.Count - 1);
1635 case XmlNodeType.CDATA:
1636 case XmlNodeType.SignificantWhitespace:
1637 case XmlNodeType.Text:
1638 XmlSchemaComplexType ct = context.ActualType as XmlSchemaComplexType;
1639 if (ct != null && storedCharacters.Length > 0) {
1640 switch (ct.ContentType) {
1641 case XmlSchemaContentType.ElementOnly:
1642 case XmlSchemaContentType.Empty:
1643 HandleError ("Not allowed character content was found.");
1648 ValidateCharacters ();
1655 public override bool ReadAttributeValue ()
1657 if (currentDefaultAttribute < 0)
1658 return reader.ReadAttributeValue ();
1660 if (this.defaultAttributeConsumed)
1663 defaultAttributeConsumed = true;
1668 public override string ReadInnerXml ()
1670 // MS.NET 1.0 has a serious bug here. It skips validation.
1671 return reader.ReadInnerXml ();
1674 public override string ReadOuterXml ()
1676 // MS.NET 1.0 has a serious bug here. It skips validation.
1677 return reader.ReadOuterXml ();
1681 // XmlReader.ReadString() should call derived this.Read().
1682 public override string ReadString ()
1685 return reader.ReadString ();
1687 return base.ReadString ();
1691 // This class itself does not have this feature.
1692 public override void ResolveEntity ()
1694 reader.ResolveEntity ();
1697 internal class XsdValidationContext
1699 Stack contextStack = new Stack ();
1701 public XsdValidationContext ()
1705 // Some of them might be missing (See the spec section 5.3, and also 3.3.4).
1706 public XmlSchemaElement Element;
1707 public XsdValidationState State;
1708 public object XsiType; // xsi:type
1710 // Note that it represents current element's type.
1711 public object ActualType {
1713 if (XsiType != null)
1716 return Element != null ? Element.ElementType : null;
1720 public void PushScope ()
1722 contextStack.Push (MemberwiseClone ());
1725 public void PopScope ()
1727 XsdValidationContext restored = (XsdValidationContext) contextStack.Pop ();
1728 this.Element = restored.Element;
1729 this.State = restored.State;
1730 this.XsiType = restored.XsiType;
1733 public void EvaluateStartElement (
1734 string localName, string ns)
1736 State = State.EvaluateStartElement (localName, ns);
1739 public void SetElement (XmlSchemaElement element)
1744 public void SetState (XsdValidationState state)