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;
60 ArrayList tmpKeyrefPool;
62 XsdValidationStateManager stateManager =
63 new XsdValidationStateManager ();
64 XsdValidationContext context = new XsdValidationContext ();
66 int skipValidationDepth = -1;
68 StringBuilder storedCharacters = new StringBuilder ();
69 bool shouldValidateCharacters;
71 XmlSchemaAttribute [] defaultAttributes = emptyAttributeArray;
72 int currentDefaultAttribute = -1;
73 ArrayList defaultAttributesCache = new ArrayList ();
74 bool defaultAttributeConsumed;
75 XmlQualifiedName attrQName;
77 ArrayList elementQNameStack = new ArrayList ();
80 public XsdValidatingReader (XmlReader reader)
83 readerLineInfo = reader as IXmlLineInfo;
84 sourceReaderSchemaInfo = reader as IHasXmlSchemaInfo;
88 public ValidationEventHandler ValidationEventHandler;
91 private XmlQualifiedName CurrentQName {
93 if (attrQName == null)
94 attrQName = new XmlQualifiedName (LocalName, NamespaceURI);
99 internal ArrayList CurrentKeyFieldConsumers {
101 if (currentKeyFieldConsumers == null)
102 currentKeyFieldConsumers = new ArrayList ();
103 return currentKeyFieldConsumers;
107 private ArrayList MissingIDReferences {
109 if (missingIDReferences == null)
110 missingIDReferences = new ArrayList ();
111 return missingIDReferences;
115 // Public Non-overrides
117 public int XsiNilDepth {
118 get { return xsiNilDepth; }
121 public bool Namespaces {
122 get { return namespaces; }
123 set { namespaces = value; }
126 public XmlReader Reader {
127 get { return reader; }
130 // This is required to resolve xsi:schemaLocation
131 public XmlResolver XmlResolver {
137 // This should be changed before the first Read() call.
138 public XmlSchemaSet Schemas {
139 get { return schemas; }
141 if (ReadState != ReadState.Initial)
142 throw new InvalidOperationException ("Schemas must be set before the first call to Read().");
147 public object SchemaType {
149 if (ReadState != ReadState.Interactive)
153 case XmlNodeType.Element:
154 if (context.ActualType != null)
155 return context.ActualType;
157 return SourceReaderSchemaType;
158 case XmlNodeType.Attribute:
159 XmlSchemaComplexType ct = context.ActualType as XmlSchemaComplexType;
161 XmlSchemaAttribute attdef = ct.AttributeUses [CurrentQName] as XmlSchemaAttribute;
163 return attdef.AttributeType;
165 return SourceReaderSchemaType;
167 return SourceReaderSchemaType;
172 private object SourceReaderSchemaType {
173 get { return this.sourceReaderSchemaInfo != null ? sourceReaderSchemaInfo.SchemaType : null; }
176 public ValidationType ValidationType {
177 get { return validationType; }
179 if (ReadState != ReadState.Initial)
180 throw new InvalidOperationException ("ValidationType must be set before reading.");
181 validationType = value;
185 IDictionary IXmlNamespaceResolver.GetNamespacesInScope (XmlNamespaceScope scope)
187 IXmlNamespaceResolver resolver = reader as IXmlNamespaceResolver;
188 if (resolver == null)
189 throw new NotSupportedException ("The input XmlReader does not implement IXmlNamespaceResolver and thus this validating reader cannot collect in-scope namespaces.");
190 return resolver.GetNamespacesInScope (scope);
193 string IXmlNamespaceResolver.LookupPrefix (string ns)
195 return ((IXmlNamespaceResolver) this).LookupPrefix (ns, false);
198 string IXmlNamespaceResolver.LookupPrefix (string ns, bool atomizedNames)
200 IXmlNamespaceResolver resolver = reader as IXmlNamespaceResolver;
201 if (resolver == null)
202 throw new NotSupportedException ("The input XmlReader does not implement IXmlNamespaceResolver and thus this validating reader cannot execute namespace prefix lookup.");
203 return resolver.LookupPrefix (ns, atomizedNames);
206 // It is used only for independent XmlReader use, not for XmlValidatingReader.
208 public override object ReadTypedValue ()
210 public object ReadTypedValue ()
213 XmlSchemaDatatype dt = SchemaType as XmlSchemaDatatype;
214 XmlSchemaSimpleType st = SchemaType as XmlSchemaSimpleType;
221 case XmlNodeType.Element:
225 storedCharacters.Length = 0;
230 case XmlNodeType.SignificantWhitespace:
231 case XmlNodeType.Text:
232 case XmlNodeType.CDATA:
233 storedCharacters.Append (Value);
235 case XmlNodeType.Comment:
241 } while (loop && !EOF && ReadState == ReadState.Interactive);
242 return dt.ParseValue (storedCharacters.ToString (), NameTable, ParserContext.NamespaceManager);
243 case XmlNodeType.Attribute:
244 return dt.ParseValue (Value, NameTable, ParserContext.NamespaceManager);
249 // Public Overrided Properties
251 public override int AttributeCount {
253 return reader.AttributeCount + defaultAttributes.Length;
257 public override string BaseURI {
258 get { return reader.BaseURI; }
261 // If this class is used to implement XmlValidatingReader,
262 // it should be left to DTDValidatingReader. In other cases,
263 // it depends on the reader's ability.
264 public override bool CanResolveEntity {
265 get { return reader.CanResolveEntity; }
268 public override int Depth {
270 if (currentDefaultAttribute < 0)
272 if (this.defaultAttributeConsumed)
273 return reader.Depth + 2;
274 return reader.Depth + 1;
278 public override bool EOF {
279 get { return reader.EOF; }
282 public override bool HasValue {
284 if (currentDefaultAttribute < 0)
285 return reader.HasValue;
290 public override bool IsDefault {
292 if (currentDefaultAttribute < 0)
293 return reader.IsDefault;
298 public override bool IsEmptyElement {
300 if (currentDefaultAttribute < 0)
301 return reader.IsEmptyElement;
306 public override string this [int i] {
307 get { return GetAttribute (i); }
310 public override string this [string name] {
311 get { return GetAttribute (name); }
314 public override string this [string localName, string ns] {
315 get { return GetAttribute (localName, ns); }
318 int IXmlLineInfo.LineNumber {
319 get { return readerLineInfo != null ? readerLineInfo.LineNumber : 0; }
322 int IXmlLineInfo.LinePosition {
323 get { return readerLineInfo != null ? readerLineInfo.LinePosition : 0; }
326 public override string LocalName {
328 if (currentDefaultAttribute < 0)
329 return reader.LocalName;
330 if (defaultAttributeConsumed)
332 return defaultAttributes [currentDefaultAttribute].QualifiedName.Name;
336 public override string Name {
338 if (currentDefaultAttribute < 0)
340 if (defaultAttributeConsumed)
343 XmlQualifiedName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
344 string prefix = Prefix;
345 if (prefix == String.Empty)
348 return String.Concat (prefix, ":", qname.Name);
352 public override string NamespaceURI {
354 if (currentDefaultAttribute < 0)
355 return reader.NamespaceURI;
356 if (defaultAttributeConsumed)
358 return defaultAttributes [currentDefaultAttribute].QualifiedName.Namespace;
362 public override XmlNameTable NameTable {
363 get { return reader.NameTable; }
366 public override XmlNodeType NodeType {
368 if (currentDefaultAttribute < 0)
369 return reader.NodeType;
370 if (defaultAttributeConsumed)
371 return XmlNodeType.Text;
372 return XmlNodeType.Attribute;
376 public XmlParserContext ParserContext {
377 get { return XmlSchemaUtil.GetParserContext (reader); }
380 public override string Prefix {
382 if (currentDefaultAttribute < 0)
383 return reader.Prefix;
384 if (defaultAttributeConsumed)
386 XmlQualifiedName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
387 string prefix = this.ParserContext.NamespaceManager.LookupPrefix (qname.Namespace, false);
395 public override char QuoteChar {
396 get { return reader.QuoteChar; }
399 public override ReadState ReadState {
400 get { return reader.ReadState; }
403 public override string Value {
405 if (currentDefaultAttribute < 0)
407 string value = defaultAttributes [currentDefaultAttribute].ValidatedDefaultValue;
409 value = defaultAttributes [currentDefaultAttribute].ValidatedFixedValue;
414 public override string XmlLang {
416 string xmlLang = reader.XmlLang;
419 int idx = this.FindDefaultAttribute ("lang", XmlNamespaceManager.XmlnsXml);
422 xmlLang = defaultAttributes [idx].ValidatedDefaultValue;
424 xmlLang = defaultAttributes [idx].ValidatedFixedValue;
429 public override XmlSpace XmlSpace {
431 XmlSpace space = reader.XmlSpace;
432 if (space != XmlSpace.None)
434 int idx = this.FindDefaultAttribute ("space", XmlNamespaceManager.XmlnsXml);
436 return XmlSpace.None;
437 string spaceSpec = defaultAttributes [idx].ValidatedDefaultValue;
438 if (spaceSpec == null)
439 spaceSpec = defaultAttributes [idx].ValidatedFixedValue;
440 return (XmlSpace) Enum.Parse (typeof (XmlSpace), spaceSpec, false);
446 private XmlQualifiedName QualifyName (string name)
448 return XmlQualifiedName.Parse (name, this);
451 private void HandleError (string error)
453 HandleError (error, null);
456 private void HandleError (string error, Exception innerException)
458 HandleError (error, innerException, false);
461 private void HandleError (string error, Exception innerException, bool isWarning)
463 if (ValidationType == ValidationType.None) // extra quick check
466 XmlSchemaException schemaException = new XmlSchemaException (error,
467 this, this.BaseURI, null, innerException);
468 HandleError (schemaException, isWarning);
471 private void HandleError (XmlSchemaException schemaException)
473 HandleError (schemaException, false);
476 private void HandleError (XmlSchemaException schemaException, bool isWarning)
478 if (ValidationType == ValidationType.None)
481 ValidationEventArgs e = new ValidationEventArgs (schemaException,
482 schemaException.Message, isWarning ? XmlSeverityType.Warning : XmlSeverityType.Error);
484 if (ValidationEventHandler != null)
485 ValidationEventHandler (this, e);
487 else if (e.Severity == XmlSeverityType.Error)
491 private XmlSchemaElement FindElement (string name, string ns)
493 return (XmlSchemaElement) schemas.GlobalElements [new XmlQualifiedName (name, ns)];
496 private XmlSchemaType FindType (XmlQualifiedName qname)
498 return (XmlSchemaType) schemas.GlobalTypes [qname];
501 private void ValidateStartElementParticle ()
503 stateManager.CurrentElement = null;
504 context.EvaluateStartElement (reader.LocalName,
505 reader.NamespaceURI);
506 if (context.State == XsdValidationState.Invalid)
507 HandleError ("Invalid start element: " + reader.NamespaceURI + ":" + reader.LocalName);
509 context.SetElement (stateManager.CurrentElement);
512 private void ValidateEndElementParticle ()
514 if (context.State != null) {
515 if (!context.State.EvaluateEndElement ()) {
516 HandleError ("Invalid end element: " + reader.Name);
522 // Utility for missing validation completion related to child items.
523 private void ValidateCharacters ()
525 if (xsiNilDepth >= 0 && xsiNilDepth < reader.Depth)
526 HandleError ("Element item appeared, while current element context is nil.");
528 storedCharacters.Append (reader.Value);
531 // Utility for missing validation completion related to child items.
532 private void ValidateEndCharacters ()
534 if (context.ActualType == null)
537 string value = storedCharacters.ToString ();
539 if (storedCharacters.Length == 0) {
540 // 3.3.4 Element Locally Valid (Element) 5.1.2
541 if (context.Element != null) {
542 if (context.Element.ValidatedDefaultValue != null)
543 value = context.Element.ValidatedDefaultValue;
547 XmlSchemaDatatype dt = context.ActualType as XmlSchemaDatatype;
548 XmlSchemaSimpleType st = context.ActualType as XmlSchemaSimpleType;
553 XmlSchemaComplexType ct = context.ActualType as XmlSchemaComplexType;
555 switch (ct.ContentType) {
556 case XmlSchemaContentType.ElementOnly:
557 case XmlSchemaContentType.Empty:
558 if (storedCharacters.Length > 0)
559 HandleError ("Character content not allowed.");
565 // 3.3.4 Element Locally Valid (Element) :: 5.2.2.2. Fixed value constraints
566 if (context.Element != null && context.Element.ValidatedFixedValue != null)
567 if (value != context.Element.ValidatedFixedValue)
568 HandleError ("Fixed value constraint was not satisfied.");
569 AssessStringValid (st, dt, value);
572 // Identity field value
573 if (currentKeyFieldConsumers != null) {
574 while (this.currentKeyFieldConsumers.Count > 0) {
575 XsdKeyEntryField field = this.currentKeyFieldConsumers [0] as XsdKeyEntryField;
576 if (field.Identity != null)
577 HandleError ("Two or more identical field was found. Former value is '" + field.Identity + "' .");
578 object identity = null; // This means empty value
581 identity = dt.ParseValue (value, NameTable, ParserContext.NamespaceManager);
582 } catch (Exception ex) { // FIXME: (wishlist) This is bad manner ;-(
583 HandleError ("Identity value is invalid against its data type " + dt.TokenizedType, ex);
586 if (identity == null)
589 if (!field.SetIdentityField (identity, reader.Depth == xsiNilDepth, dt as XsdAnySimpleType, this))
590 HandleError ("Two or more identical key value was found: '" + value + "' .");
591 this.currentKeyFieldConsumers.RemoveAt (0);
595 shouldValidateCharacters = false;
598 // 3.14.4 String Valid
599 private void AssessStringValid (XmlSchemaSimpleType st,
600 XmlSchemaDatatype dt, string value)
602 XmlSchemaDatatype validatedDatatype = dt;
604 string normalized = validatedDatatype.Normalize (value);
606 XmlSchemaDatatype itemDatatype;
607 XmlSchemaSimpleType itemSimpleType;
608 switch (st.DerivedBy) {
609 case XmlSchemaDerivationMethod.List:
610 XmlSchemaSimpleTypeList listContent = st.Content as XmlSchemaSimpleTypeList;
611 values = normalized.Split (XmlChar.WhitespaceChars);
612 itemDatatype = listContent.ValidatedListItemType as XmlSchemaDatatype;
613 itemSimpleType = listContent.ValidatedListItemType as XmlSchemaSimpleType;
614 for (int vi = 0; vi < values.Length; vi++) {
615 string each = values [vi];
616 if (each == String.Empty)
618 // validate against ValidatedItemType
619 if (itemDatatype != null) {
621 itemDatatype.ParseValue (each, NameTable, ParserContext.NamespaceManager);
622 } catch (Exception ex) { // FIXME: (wishlist) better exception handling ;-(
623 HandleError ("List type value contains one or more invalid values.", ex);
628 AssessStringValid (itemSimpleType, itemSimpleType.Datatype, each);
631 case XmlSchemaDerivationMethod.Union:
632 XmlSchemaSimpleTypeUnion union = st.Content as XmlSchemaSimpleTypeUnion;
634 string each = normalized;
635 // validate against ValidatedItemType
637 foreach (object eachType in union.ValidatedTypes) {
638 itemDatatype = eachType as XmlSchemaDatatype;
639 itemSimpleType = eachType as XmlSchemaSimpleType;
640 if (itemDatatype != null) {
642 itemDatatype.ParseValue (each, NameTable, ParserContext.NamespaceManager);
643 } catch (Exception) { // FIXME: (wishlist) better exception handling ;-(
649 AssessStringValid (itemSimpleType, itemSimpleType.Datatype, each);
650 } catch (XmlSchemaException) {
658 HandleError ("Union type value contains one or more invalid values.");
663 case XmlSchemaDerivationMethod.Restriction:
664 XmlSchemaSimpleTypeRestriction str = st.Content as XmlSchemaSimpleTypeRestriction;
667 /* Don't forget to validate against inherited type's facets
668 * Could we simplify this by assuming that the basetype will also
671 // mmm, will check later.
672 XmlSchemaSimpleType baseType = st.BaseXmlSchemaType as XmlSchemaSimpleType;
673 if (baseType != null) {
674 AssessStringValid(baseType, dt, normalized);
676 if (!str.ValidateValueWithFacets (normalized, NameTable)) {
677 HandleError ("Specified value was invalid against the facets.");
681 validatedDatatype = st.Datatype;
685 if (validatedDatatype != null) {
687 validatedDatatype.ParseValue (value, NameTable, ParserContext.NamespaceManager);
688 } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
689 HandleError ("Invalidly typed data was specified.", ex);
694 private object GetXsiType (string name)
696 object xsiType = null;
697 XmlQualifiedName typeQName = QualifyName (name);
698 if (typeQName == XmlSchemaComplexType.AnyTypeName)
699 xsiType = XmlSchemaComplexType.AnyType;
700 else if (XmlSchemaUtil.IsBuiltInDatatypeName (typeQName))
701 xsiType = XmlSchemaDatatype.FromName (typeQName);
703 xsiType = FindType (typeQName);
707 // It is common to ElementLocallyValid::4 and SchemaValidityAssessment::1.2.1.2.4
708 private void AssessLocalTypeDerivationOK (object xsiType, object baseType, XmlSchemaDerivationMethod flag)
710 XmlSchemaType xsiSchemaType = xsiType as XmlSchemaType;
711 XmlSchemaComplexType baseComplexType = baseType as XmlSchemaComplexType;
712 XmlSchemaComplexType xsiComplexType = xsiSchemaType as XmlSchemaComplexType;
713 if (xsiType != baseType) {
714 // Extracted (not extraneous) check for 3.4.6 TypeDerivationOK.
715 if (baseComplexType != null)
716 flag |= baseComplexType.BlockResolved;
717 if (flag == XmlSchemaDerivationMethod.All) {
718 HandleError ("Prohibited element type substitution.");
720 } else if (xsiSchemaType != null && (flag & xsiSchemaType.DerivedBy) != 0) {
721 HandleError ("Prohibited element type substitution.");
726 if (xsiComplexType != null)
728 xsiComplexType.ValidateTypeDerivationOK (baseType, null, null);
729 } catch (XmlSchemaException ex) {
730 // HandleError ("Locally specified schema complex type derivation failed. " + ex.Message, ex);
734 XmlSchemaSimpleType xsiSimpleType = xsiType as XmlSchemaSimpleType;
735 if (xsiSimpleType != null) {
737 xsiSimpleType.ValidateTypeDerivationOK (baseType, null, null, true);
738 } catch (XmlSchemaException ex) {
739 // HandleError ("Locally specified schema simple type derivation failed. " + ex.Message, ex);
743 else if (xsiType is XmlSchemaDatatype) {
747 HandleError ("Primitive data type cannot be derived type using xsi:type specification.");
751 // Section 3.3.4 of the spec.
752 private void AssessStartElementSchemaValidity ()
754 // If the reader is inside xsi:nil (and failed on validation),
755 // then simply skip its content.
756 if (xsiNilDepth >= 0 && xsiNilDepth < reader.Depth)
757 HandleError ("Element item appeared, while current element context is nil.");
759 context.XsiType = null;
760 // If validation state exists, then first assess particle validity.
761 if (context.State != null) {
762 ValidateStartElementParticle ();
765 string xsiNilValue = reader.GetAttribute ("nil", XmlSchema.InstanceNamespace);
766 if (xsiNilValue != null)
767 xsiNilValue = xsiNilValue.Trim (XmlChar.WhitespaceChars);
768 bool isXsiNil = xsiNilValue == "true";
769 if (isXsiNil && this.xsiNilDepth < 0)
770 xsiNilDepth = reader.Depth;
772 // [Schema Validity Assessment (Element) 1.2]
773 // Evaluate "local type definition" from xsi:type.
774 // (See spec 3.3.4 Schema Validity Assessment (Element) 1.2.1.2.3.
775 // Note that Schema Validity Assessment(Element) 1.2 takes
776 // precedence than 1.1 of that.
778 string xsiTypeName = reader.GetAttribute ("type", XmlSchema.InstanceNamespace);
779 if (xsiTypeName != null) {
780 xsiTypeName = xsiTypeName.Trim (XmlChar.WhitespaceChars);
781 object xsiType = GetXsiType (xsiTypeName);
783 HandleError ("The instance type was not found: " + xsiTypeName + " .");
785 XmlSchemaType xsiSchemaType = xsiType as XmlSchemaType;
786 if (xsiSchemaType != null && this.context.Element != null) {
787 XmlSchemaType elemBaseType = context.Element.ElementType as XmlSchemaType;
788 if (elemBaseType != null && (xsiSchemaType.DerivedBy & elemBaseType.FinalResolved) != 0)
789 HandleError ("The instance type is prohibited by the type of the context element.");
790 if (elemBaseType != xsiType && (xsiSchemaType.DerivedBy & this.context.Element.BlockResolved) != 0)
791 HandleError ("The instance type is prohibited by the context element.");
793 XmlSchemaComplexType xsiComplexType = xsiType as XmlSchemaComplexType;
794 if (xsiComplexType != null && xsiComplexType.IsAbstract)
795 HandleError ("The instance type is abstract: " + xsiTypeName + " .");
797 // If current schema type exists, then this xsi:type must be
798 // valid extension of that type. See 1.2.1.2.4.
799 if (context.Element != null) {
800 AssessLocalTypeDerivationOK (xsiType, context.Element.ElementType, context.Element.BlockResolved);
802 AssessStartElementLocallyValidType (xsiType); // 1.2.2:
803 context.XsiType = xsiType;
808 // Create Validation Root, if not exist.
809 // [Schema Validity Assessment (Element) 1.1]
810 if (context.Element == null)
811 context.SetElement (FindElement (reader.LocalName, reader.NamespaceURI));
812 if (context.Element != null) {
813 if (xsiTypeName == null) {
814 AssessElementLocallyValidElement (context.Element, xsiNilValue); // 1.1.2
817 switch (stateManager.ProcessContents) {
818 case XmlSchemaContentProcessing.Skip:
820 case XmlSchemaContentProcessing.Lax:
823 if (xsiTypeName == null &&
824 (schemas.Contains (reader.NamespaceURI) ||
825 !schemas.MissedSubComponents (reader.NamespaceURI)))
826 HandleError ("Element declaration for " + reader.LocalName + " is missing.");
831 XsdValidationState next = null;
832 if (stateManager.ProcessContents
833 == XmlSchemaContentProcessing.Skip)
834 skipValidationDepth = reader.Depth;
836 // create child particle state.
837 XmlSchemaComplexType xsComplexType = SchemaType as XmlSchemaComplexType;
838 if (xsComplexType != null)
839 next = stateManager.Create (xsComplexType.ValidatableParticle);
840 else if (stateManager.ProcessContents == XmlSchemaContentProcessing.Lax)
841 next = stateManager.Create (XmlSchemaAny.AnyTypeContent);
843 next = stateManager.Create (XmlSchemaParticle.Empty);
846 AssessStartIdentityConstraints ();
848 context.PushScope ();
850 context.State = next;
853 // 3.3.4 Element Locally Valid (Element)
854 private void AssessElementLocallyValidElement (XmlSchemaElement element, string xsiNilValue)
856 XmlQualifiedName qname = new XmlQualifiedName (reader.LocalName, reader.NamespaceURI);
859 HandleError ("Element declaration is required for " + qname);
861 if (element.ActualIsAbstract)
862 HandleError ("Abstract element declaration was specified for " + qname);
864 if (!element.ActualIsNillable && xsiNilValue != null)
865 HandleError ("This element declaration is not nillable: " + qname);
867 // Note that 3.2.1 xsi:nil constraints are to be validated in
868 else if (xsiNilValue == "true") {
869 // AssessElementSchemaValidity() and ValidateCharacters()
871 if (element.ValidatedFixedValue != null)
872 HandleError ("Schema instance nil was specified, where the element declaration for " + qname + "has fixed value constraints.");
875 string xsiType = reader.GetAttribute ("type", XmlSchema.InstanceNamespace);
876 if (xsiType != null) {
877 context.XsiType = GetXsiType (xsiType);
878 AssessLocalTypeDerivationOK (context.XsiType, element.ElementType, element.BlockResolved);
881 context.XsiType = null;
883 // 5 Not all things cannot be assessed here.
884 // It is common to 5.1 and 5.2
885 if (element.ElementType != null)
886 AssessStartElementLocallyValidType (SchemaType);
888 // 6. should be out from here.
889 // See invokation of AssessStartIdentityConstraints().
891 // 7 is going to be validated in Read() (in case of xmlreader's EOF).
894 // 3.3.4 Element Locally Valid (Type)
895 private void AssessStartElementLocallyValidType (object schemaType)
897 if (schemaType == null) { // 1.
898 HandleError ("Schema type does not exist.");
901 XmlSchemaComplexType cType = schemaType as XmlSchemaComplexType;
902 XmlSchemaSimpleType sType = schemaType as XmlSchemaSimpleType;
905 while (reader.MoveToNextAttribute ()) {
906 if (reader.NamespaceURI == XmlNamespaceManager.XmlnsXmlns)
908 if (reader.NamespaceURI != XmlSchema.InstanceNamespace)
909 HandleError ("Current simple type cannot accept attributes other than schema instance namespace.");
910 switch (reader.LocalName) {
913 case "schemaLocation":
914 case "noNamespaceSchemaLocation":
917 HandleError ("Unknown schema instance namespace attribute: " + reader.LocalName);
921 reader.MoveToElement ();
922 // 3.1.2 and 3.1.3 cannot be assessed here.
923 } else if (cType != null) {
924 if (cType.IsAbstract) { // 2.
925 HandleError ("Target complex type is abstract.");
929 AssessElementLocallyValidComplexType (cType);
933 // 3.4.4 Element Locally Valid (Complex Type)
934 private void AssessElementLocallyValidComplexType (XmlSchemaComplexType cType)
937 if (cType.IsAbstract)
938 HandleError ("Target complex type is abstract.");
940 // 2 (xsi:nil and content prohibition)
941 // See AssessStartElementSchemaValidity() and ValidateCharacters()
943 // 3. attribute uses and
945 if (reader.MoveToFirstAttribute ()) {
947 switch (reader.NamespaceURI) {
948 case"http://www.w3.org/2000/xmlns/":
949 case XmlSchema.InstanceNamespace:
952 XmlQualifiedName qname = new XmlQualifiedName (reader.LocalName, reader.NamespaceURI);
953 XmlSchemaObject attMatch = FindAttributeDeclaration (cType, qname);
954 if (attMatch == null)
955 HandleError ("Attribute declaration was not found for " + qname);
956 XmlSchemaAttribute attdecl = attMatch as XmlSchemaAttribute;
957 if (attdecl != null) {
958 AssessAttributeLocallyValidUse (attdecl);
959 AssessAttributeLocallyValid (attdecl);
960 } // otherwise anyAttribute or null.
961 } while (reader.MoveToNextAttribute ());
962 reader.MoveToElement ();
965 // Collect default attributes.
967 foreach (DictionaryEntry entry in cType.AttributeUses) {
968 XmlSchemaAttribute attr = (XmlSchemaAttribute) entry.Value;
969 if (reader [attr.QualifiedName.Name, attr.QualifiedName.Namespace] == null) {
970 if (attr.ValidatedUse == XmlSchemaUse.Required &&
971 attr.ValidatedFixedValue == null)
972 HandleError ("Required attribute " + attr.QualifiedName + " was not found.");
973 else if (attr.ValidatedDefaultValue != null || attr.ValidatedFixedValue != null)
974 defaultAttributesCache.Add (attr);
977 if (defaultAttributesCache.Count == 0)
978 defaultAttributes = emptyAttributeArray;
980 defaultAttributes = (XmlSchemaAttribute [])
981 defaultAttributesCache.ToArray (
982 typeof (XmlSchemaAttribute));
983 defaultAttributesCache.Clear ();
984 // 5. wild IDs was already checked above.
987 // Spec 3.10.4 Item Valid (Wildcard)
988 private static bool AttributeWildcardItemValid (XmlSchemaAnyAttribute anyAttr, XmlQualifiedName qname, string ns)
990 if (anyAttr.HasValueAny)
992 if (anyAttr.HasValueOther && (anyAttr.TargetNamespace == "" || ns != anyAttr.TargetNamespace))
994 if (anyAttr.HasValueTargetNamespace && ns == anyAttr.TargetNamespace)
996 if (anyAttr.HasValueLocal && ns == "")
998 for (int i = 0; i < anyAttr.ResolvedNamespaces.Count; i++)
999 if (anyAttr.ResolvedNamespaces [i] == ns)
1004 private XmlSchemaObject FindAttributeDeclaration (
1005 XmlSchemaComplexType cType,
1006 XmlQualifiedName qname)
1008 XmlSchemaObject result = cType.AttributeUses [qname];
1011 if (cType.AttributeWildcard == null)
1014 if (!AttributeWildcardItemValid (cType.AttributeWildcard, qname, reader.NamespaceURI))
1017 if (cType.AttributeWildcard.ResolvedProcessContents == XmlSchemaContentProcessing.Skip)
1018 return cType.AttributeWildcard;
1019 XmlSchemaAttribute attr = schemas.GlobalAttributes [qname] as XmlSchemaAttribute;
1022 if (cType.AttributeWildcard.ResolvedProcessContents == XmlSchemaContentProcessing.Lax)
1023 return cType.AttributeWildcard;
1028 // 3.2.4 Attribute Locally Valid and 3.4.4
1029 private void AssessAttributeLocallyValid (XmlSchemaAttribute attr)
1032 if (attr.AttributeType == null)
1033 HandleError ("Attribute type is missing for " + attr.QualifiedName);
1034 XmlSchemaDatatype dt = attr.AttributeType as XmlSchemaDatatype;
1036 dt = ((XmlSchemaSimpleType) attr.AttributeType).Datatype;
1037 // It is a bit heavy process, so let's omit as long as possible ;-)
1038 if (dt != XmlSchemaSimpleType.AnySimpleType || attr.ValidatedFixedValue != null) {
1039 string normalized = dt.Normalize (reader.Value);
1040 object parsedValue = null;
1042 parsedValue = dt.ParseValue (normalized, reader.NameTable, this.ParserContext.NamespaceManager);
1043 } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
1044 HandleError ("Attribute value is invalid against its data type " + dt.TokenizedType, ex);
1046 if (attr.ValidatedFixedValue != null && attr.ValidatedFixedValue != normalized) {
1047 HandleError ("The value of the attribute " + attr.QualifiedName + " does not match with its fixed value.");
1048 parsedValue = dt.ParseValue (attr.ValidatedFixedValue, reader.NameTable, this.ParserContext.NamespaceManager);
1050 if (this.checkIdentity)
1051 AssessEachAttributeIdentityConstraint (dt, parsedValue);
1056 private void AssessEachAttributeIdentityConstraint (
1057 XmlSchemaDatatype dt, object parsedValue)
1059 // Validate identity constraints.
1060 string str = parsedValue as string;
1061 switch (dt.TokenizedType) {
1062 case XmlTokenizedType.ID:
1063 if (thisElementId != null)
1064 HandleError ("ID type attribute was already assigned in the containing element.");
1065 thisElementId = str;
1066 if (idList.Contains (str))
1067 HandleError ("Duplicate ID value was found.");
1069 idList.Add (str, str);
1070 if (MissingIDReferences.Contains (str))
1071 MissingIDReferences.Remove (str);
1073 case XmlTokenizedType.IDREF:
1074 if (!idList.Contains (str))
1075 MissingIDReferences.Add (str);
1077 case XmlTokenizedType.IDREFS:
1078 string [] idrefs = (string []) parsedValue;
1079 for (int i = 0; i < idrefs.Length; i++) {
1080 string id = idrefs [i];
1081 if (!idList.Contains (id))
1082 MissingIDReferences.Add (id);
1088 private void AssessAttributeLocallyValidUse (XmlSchemaAttribute attr)
1090 // This is extra check than spec 3.5.4
1091 if (attr.ValidatedUse == XmlSchemaUse.Prohibited)
1092 HandleError ("Attribute " + attr.QualifiedName + " is prohibited in this context.");
1095 private void AssessEndElementSchemaValidity ()
1097 ValidateEndElementParticle (); // validate against childrens' state.
1099 if (shouldValidateCharacters) {
1100 ValidateEndCharacters ();
1101 shouldValidateCharacters = false;
1104 // 3.3.4 Assess ElementLocallyValidElement 5: value constraints.
1105 // 3.3.4 Assess ElementLocallyValidType 3.1.3. = StringValid(3.14.4)
1106 // => ValidateEndCharacters().
1108 // Reset Identity constraints.
1109 for (int i = 0; i < keyTables.Count; i++) {
1110 XsdKeyTable keyTable = this.keyTables [i] as XsdKeyTable;
1111 if (keyTable.StartDepth == reader.Depth) {
1112 EndIdentityValidation (keyTable);
1114 for (int k = 0; k < keyTable.Entries.Count; k++) {
1115 XsdKeyEntry entry = keyTable.Entries [k] as XsdKeyEntry;
1116 // Remove finished (maybe key not found) entries.
1117 if (entry.StartDepth == reader.Depth) {
1119 keyTable.FinishedEntries.Add (entry);
1120 else if (entry.KeySequence.SourceSchemaIdentity is XmlSchemaKey)
1121 HandleError ("Key sequence is missing.");
1122 keyTable.Entries.RemoveAt (k);
1125 // Pop validated key depth to find two or more fields.
1127 for (int j = 0; j < entry.KeyFields.Count; j++) {
1128 XsdKeyEntryField kf = entry.KeyFields [j];
1129 if (!kf.FieldFound && kf.FieldFoundDepth == reader.Depth) {
1130 kf.FieldFoundDepth = 0;
1131 kf.FieldFoundPath = null;
1138 for (int i = 0; i < keyTables.Count; i++) {
1139 XsdKeyTable keyseq = this.keyTables [i] as XsdKeyTable;
1140 if (keyseq.StartDepth == reader.Depth) {
1141 keyTables.RemoveAt (i);
1146 // Reset xsi:nil, if required.
1147 if (xsiNilDepth == reader.Depth)
1151 // 3.11.4 Identity Constraint Satisfied
1152 private void AssessStartIdentityConstraints ()
1154 if (tmpKeyrefPool != null)
1155 tmpKeyrefPool.Clear ();
1156 if (context.Element != null && context.Element.Constraints.Count > 0) {
1157 // (a) Create new key sequences, if required.
1158 for (int i = 0; i < context.Element.Constraints.Count; i++) {
1159 XmlSchemaIdentityConstraint ident = (XmlSchemaIdentityConstraint) context.Element.Constraints [i];
1160 XsdKeyTable seq = CreateNewKeyTable (ident);
1161 if (ident is XmlSchemaKeyref) {
1162 if (tmpKeyrefPool == null)
1163 tmpKeyrefPool = new ArrayList ();
1164 tmpKeyrefPool.Add (seq);
1169 // (b) Evaluate current key sequences.
1170 for (int i = 0; i < keyTables.Count; i++) {
1171 XsdKeyTable seq = (XsdKeyTable) keyTables [i];
1172 if (seq.SelectorMatches (this.elementQNameStack, reader) != null) {
1173 // creates and registers new entry.
1174 XsdKeyEntry entry = new XsdKeyEntry (seq, reader);
1175 seq.Entries.Add (entry);
1179 // (c) Evaluate field paths.
1180 for (int i = 0; i < keyTables.Count; i++) {
1181 XsdKeyTable seq = (XsdKeyTable) keyTables [i];
1182 // If possible, create new field entry candidates.
1183 for (int j = 0; j < seq.Entries.Count; j++) {
1184 XsdKeyEntry entry = seq.Entries [j] as XsdKeyEntry;
1186 entry.FieldMatches (this.elementQNameStack, this);
1187 } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
1188 HandleError ("Identity field value is invalid against its data type.", ex);
1194 private XsdKeyTable CreateNewKeyTable (XmlSchemaIdentityConstraint ident)
1196 XsdKeyTable seq = new XsdKeyTable (ident, this);
1197 seq.StartDepth = reader.Depth;
1198 this.keyTables.Add (seq);
1202 private void EndIdentityValidation (XsdKeyTable seq)
1204 ArrayList errors = new ArrayList ();
1205 for (int i = 0; i < seq.Entries.Count; i++) {
1206 XsdKeyEntry entry = (XsdKeyEntry) seq.Entries [i];
1209 if (seq.SourceSchemaIdentity is XmlSchemaKey)
1210 errors.Add ("line " + entry.SelectorLineNumber + "position " + entry.SelectorLinePosition);
1212 if (errors.Count > 0)
1213 HandleError ("Invalid identity constraints were found. Key was not found. "
1214 + String.Join (", ", errors.ToArray (typeof (string)) as string []));
1217 // Find reference target
1218 XmlSchemaKeyref xsdKeyref = seq.SourceSchemaIdentity as XmlSchemaKeyref;
1219 if (xsdKeyref != null) {
1220 for (int i = this.keyTables.Count - 1; i >= 0; i--) {
1221 XsdKeyTable target = this.keyTables [i] as XsdKeyTable;
1222 if (target.SourceSchemaIdentity == xsdKeyref.Target) {
1223 seq.ReferencedKey = target;
1224 for (int j = 0; j < seq.FinishedEntries.Count; j++) {
1225 XsdKeyEntry entry = (XsdKeyEntry) seq.FinishedEntries [j];
1226 for (int k = 0; k < target.FinishedEntries.Count; k++) {
1227 XsdKeyEntry targetEntry = (XsdKeyEntry) target.FinishedEntries [k];
1228 if (entry.CompareIdentity (targetEntry)) {
1229 entry.KeyRefFound = true;
1236 if (seq.ReferencedKey == null)
1237 HandleError ("Target key was not found.");
1238 for (int i = 0; i < seq.FinishedEntries.Count; i++) {
1239 XsdKeyEntry entry = (XsdKeyEntry) seq.FinishedEntries [i];
1240 if (!entry.KeyRefFound)
1241 errors.Add (" line " + entry.SelectorLineNumber + ", position " + entry.SelectorLinePosition);
1243 if (errors.Count > 0)
1244 HandleError ("Invalid identity constraints were found. Referenced key was not found: "
1245 + String.Join (" / ", errors.ToArray (typeof (string)) as string []));
1249 // Overrided Methods
1251 public override void Close ()
1256 public override string GetAttribute (int i)
1258 switch (reader.NodeType) {
1259 case XmlNodeType.XmlDeclaration:
1260 case XmlNodeType.DocumentType:
1261 return reader.GetAttribute (i);
1264 if (reader.AttributeCount > i)
1265 reader.GetAttribute (i);
1266 int defIdx = i - reader.AttributeCount;
1267 if (i < AttributeCount)
1268 return defaultAttributes [defIdx].DefaultValue;
1270 throw new ArgumentOutOfRangeException ("i", i, "Specified attribute index is out of range.");
1273 public override string GetAttribute (string name)
1275 switch (reader.NodeType) {
1276 case XmlNodeType.XmlDeclaration:
1277 case XmlNodeType.DocumentType:
1278 return reader.GetAttribute (name);
1281 string value = reader.GetAttribute (name);
1285 XmlQualifiedName qname = SplitQName (name);
1286 return GetDefaultAttribute (qname.Name, qname.Namespace);
1289 private XmlQualifiedName SplitQName (string name)
1291 if (!XmlChar.IsName (name))
1292 throw new ArgumentException ("Invalid name was specified.", "name");
1294 Exception ex = null;
1295 XmlQualifiedName qname = XmlSchemaUtil.ToQName (reader, name, out ex);
1297 return XmlQualifiedName.Empty;
1302 public override string GetAttribute (string localName, string ns)
1304 switch (reader.NodeType) {
1305 case XmlNodeType.XmlDeclaration:
1306 case XmlNodeType.DocumentType:
1307 return reader.GetAttribute (localName, ns);
1310 string value = reader.GetAttribute (localName, ns);
1314 return GetDefaultAttribute (localName, ns);
1317 private string GetDefaultAttribute (string localName, string ns)
1319 int idx = this.FindDefaultAttribute (localName, ns);
1322 string value = defaultAttributes [idx].ValidatedDefaultValue;
1324 value = defaultAttributes [idx].ValidatedFixedValue;
1328 private int FindDefaultAttribute (string localName, string ns)
1330 for (int i = 0; i < this.defaultAttributes.Length; i++) {
1331 XmlSchemaAttribute attr = defaultAttributes [i];
1332 if (attr.QualifiedName.Name == localName &&
1333 (ns == null || attr.QualifiedName.Namespace == ns))
1339 bool IXmlLineInfo.HasLineInfo ()
1341 return readerLineInfo != null && readerLineInfo.HasLineInfo ();
1344 public override string LookupNamespace (string prefix)
1346 return reader.LookupNamespace (prefix);
1349 string IXmlNamespaceResolver.LookupNamespace (string prefix, bool atomizedNames)
1351 IXmlNamespaceResolver res = reader as IXmlNamespaceResolver;
1353 return res.LookupNamespace (prefix, atomizedNames);
1355 return reader.LookupNamespace (prefix);
1358 public override void MoveToAttribute (int i)
1360 switch (reader.NodeType) {
1361 case XmlNodeType.XmlDeclaration:
1362 case XmlNodeType.DocumentType:
1363 reader.MoveToAttribute (i);
1368 if (i < reader.AttributeCount) {
1369 reader.MoveToAttribute (i);
1370 this.currentDefaultAttribute = -1;
1371 this.defaultAttributeConsumed = false;
1374 if (i < AttributeCount) {
1375 this.currentDefaultAttribute = i - reader.AttributeCount;
1376 this.defaultAttributeConsumed = false;
1379 throw new ArgumentOutOfRangeException ("i", i, "Attribute index is out of range.");
1382 public override bool MoveToAttribute (string name)
1384 switch (reader.NodeType) {
1385 case XmlNodeType.XmlDeclaration:
1386 case XmlNodeType.DocumentType:
1387 return reader.MoveToAttribute (name);
1391 bool b = reader.MoveToAttribute (name);
1393 this.currentDefaultAttribute = -1;
1394 this.defaultAttributeConsumed = false;
1398 return MoveToDefaultAttribute (name, null);
1401 public override bool MoveToAttribute (string localName, string ns)
1403 switch (reader.NodeType) {
1404 case XmlNodeType.XmlDeclaration:
1405 case XmlNodeType.DocumentType:
1406 return reader.MoveToAttribute (localName, ns);
1410 bool b = reader.MoveToAttribute (localName, ns);
1412 this.currentDefaultAttribute = -1;
1413 this.defaultAttributeConsumed = false;
1417 return MoveToDefaultAttribute (localName, ns);
1420 private bool MoveToDefaultAttribute (string localName, string ns)
1422 int idx = this.FindDefaultAttribute (localName, ns);
1425 currentDefaultAttribute = idx;
1426 defaultAttributeConsumed = false;
1430 public override bool MoveToElement ()
1432 currentDefaultAttribute = -1;
1433 defaultAttributeConsumed = false;
1435 return reader.MoveToElement ();
1438 public override bool MoveToFirstAttribute ()
1440 switch (reader.NodeType) {
1441 case XmlNodeType.XmlDeclaration:
1442 case XmlNodeType.DocumentType:
1443 return reader.MoveToFirstAttribute ();
1447 if (reader.AttributeCount > 0) {
1448 bool b = reader.MoveToFirstAttribute ();
1450 currentDefaultAttribute = -1;
1451 defaultAttributeConsumed = false;
1456 if (this.defaultAttributes.Length > 0) {
1457 currentDefaultAttribute = 0;
1458 defaultAttributeConsumed = false;
1465 public override bool MoveToNextAttribute ()
1467 switch (reader.NodeType) {
1468 case XmlNodeType.XmlDeclaration:
1469 case XmlNodeType.DocumentType:
1470 return reader.MoveToNextAttribute ();
1474 if (currentDefaultAttribute >= 0) {
1475 if (defaultAttributes.Length == currentDefaultAttribute + 1)
1477 currentDefaultAttribute++;
1478 defaultAttributeConsumed = false;
1482 bool b = reader.MoveToNextAttribute ();
1484 currentDefaultAttribute = -1;
1485 defaultAttributeConsumed = false;
1489 if (defaultAttributes.Length > 0) {
1490 currentDefaultAttribute = 0;
1491 defaultAttributeConsumed = false;
1498 private void ExamineAdditionalSchema ()
1500 XmlSchema schema = null;
1501 string schemaLocation = reader.GetAttribute ("schemaLocation", XmlSchema.InstanceNamespace);
1502 bool schemaAdded = false;
1503 if (schemaLocation != null) {
1504 string [] tmp = null;
1506 schemaLocation = XmlSchemaDatatype.FromName ("token", XmlSchema.Namespace).Normalize (schemaLocation);
1507 tmp = schemaLocation.Split (XmlChar.WhitespaceChars);
1508 } catch (Exception ex) {
1509 HandleError ("Invalid schemaLocation attribute format.", ex, true);
1510 tmp = new string [0];
1512 if (tmp.Length % 2 != 0)
1513 HandleError ("Invalid schemaLocation attribute format.");
1514 for (int i = 0; i < tmp.Length; i += 2) {
1516 XmlTextReader xtr = null;
1518 absUri = new Uri ((this.BaseURI != "" ? new Uri (BaseURI) : null), tmp [i + 1]);
1519 xtr = new XmlTextReader (absUri.ToString (), NameTable);
1520 schema = XmlSchema.Read (xtr, null);
1521 } catch (Exception) { // FIXME: (wishlist) It is bad manner ;-(
1522 HandleError ("Could not resolve schema location URI: " + absUri, null, true);
1528 if (schema.TargetNamespace == null)
1529 schema.TargetNamespace = tmp [i];
1530 else if (schema.TargetNamespace != tmp [i])
1531 HandleError ("Specified schema has different target namespace.");
1534 if (schema != null) {
1535 if (!schemas.Contains (schema.TargetNamespace)) {
1537 schemas.Add (schema);
1541 string noNsSchemaLocation = reader.GetAttribute ("noNamespaceSchemaLocation", XmlSchema.InstanceNamespace);
1542 if (noNsSchemaLocation != null) {
1544 XmlTextReader xtr = null;
1546 absUri = new Uri ((this.BaseURI != "" ? new Uri (BaseURI) : null), noNsSchemaLocation);
1547 xtr = new XmlTextReader (absUri.ToString (), NameTable);
1548 schema = XmlSchema.Read (xtr, null);
1549 } catch (Exception) { // FIXME: (wishlist) It is bad manner ;-(
1550 HandleError ("Could not resolve schema location URI: " + absUri, null, true);
1555 if (schema != null && schema.TargetNamespace != null)
1556 HandleError ("Specified schema has different target namespace.");
1558 if (schema != null) {
1559 if (!schemas.Contains (schema.TargetNamespace)) {
1561 schemas.Add (schema);
1564 // FIXME: should call Reprocess()?
1569 private bool HasMissingIDReferences ()
1571 return missingIDReferences != null
1572 && missingIDReferences.Count > 0;
1575 public override bool Read ()
1577 currentDefaultAttribute = -1;
1578 defaultAttributeConsumed = false;
1580 if (this.checkIdentity)
1581 thisElementId = null;
1582 defaultAttributes = new XmlSchemaAttribute [0];
1583 if (!schemas.IsCompiled)
1586 bool result = reader.Read ();
1587 // 3.3.4 ElementLocallyValidElement 7 = Root Valid.
1588 if (!result && this.checkIdentity &&
1589 HasMissingIDReferences ())
1590 HandleError ("There are missing ID references: " +
1592 this.missingIDReferences.ToArray (typeof (string)) as string []));
1594 switch (reader.NodeType) {
1595 case XmlNodeType.Element:
1596 // FIXME: schemaLocation could be specified
1598 if (reader.Depth == 0)
1599 ExamineAdditionalSchema ();
1601 this.elementQNameStack.Add (new XmlQualifiedName (reader.LocalName, reader.NamespaceURI));
1603 // If there is no schema information, then no validation is performed.
1604 if (schemas.Count == 0)
1607 if (skipValidationDepth < 0 || reader.Depth <= skipValidationDepth) {
1608 if (shouldValidateCharacters) {
1609 ValidateEndCharacters ();
1610 shouldValidateCharacters = false;
1612 AssessStartElementSchemaValidity ();
1613 storedCharacters.Length = 0;
1616 if (reader.IsEmptyElement)
1617 goto case XmlNodeType.EndElement;
1619 shouldValidateCharacters = true;
1621 case XmlNodeType.EndElement:
1622 if (reader.Depth == skipValidationDepth)
1623 skipValidationDepth = -1;
1624 else if (skipValidationDepth < 0 || reader.Depth <= skipValidationDepth)
1625 AssessEndElementSchemaValidity ();
1627 storedCharacters.Length = 0;
1628 elementQNameStack.RemoveAt (elementQNameStack.Count - 1);
1631 case XmlNodeType.CDATA:
1632 case XmlNodeType.SignificantWhitespace:
1633 case XmlNodeType.Text:
1634 XmlSchemaComplexType ct = context.ActualType as XmlSchemaComplexType;
1635 if (ct != null && storedCharacters.Length > 0) {
1636 switch (ct.ContentType) {
1637 case XmlSchemaContentType.ElementOnly:
1638 case XmlSchemaContentType.Empty:
1639 HandleError ("Not allowed character content was found.");
1644 ValidateCharacters ();
1651 public override bool ReadAttributeValue ()
1653 if (currentDefaultAttribute < 0)
1654 return reader.ReadAttributeValue ();
1656 if (this.defaultAttributeConsumed)
1659 defaultAttributeConsumed = true;
1664 public override string ReadInnerXml ()
1666 // MS.NET 1.0 has a serious bug here. It skips validation.
1667 return reader.ReadInnerXml ();
1670 public override string ReadOuterXml ()
1672 // MS.NET 1.0 has a serious bug here. It skips validation.
1673 return reader.ReadOuterXml ();
1677 // XmlReader.ReadString() should call derived this.Read().
1678 public override string ReadString ()
1681 return reader.ReadString ();
1683 return base.ReadString ();
1687 // This class itself does not have this feature.
1688 public override void ResolveEntity ()
1690 reader.ResolveEntity ();
1693 internal class XsdValidationContext
1695 Stack contextStack = new Stack ();
1697 public XsdValidationContext ()
1701 // Some of them might be missing (See the spec section 5.3, and also 3.3.4).
1702 public XmlSchemaElement Element;
1703 public XsdValidationState State;
1704 public object XsiType; // xsi:type
1706 // Note that it represents current element's type.
1707 public object ActualType {
1709 if (XsiType != null)
1712 return Element != null ? Element.ElementType : null;
1716 public void PushScope ()
1718 contextStack.Push (MemberwiseClone ());
1721 public void PopScope ()
1723 // FIXME: this count check should not be required, so check the behavior.
1724 if (contextStack.Count > 0) {
1725 XsdValidationContext restored = (XsdValidationContext) contextStack.Pop ();
1726 this.Element = restored.Element;
1727 this.State = restored.State;
1728 this.XsiType = restored.XsiType;
1732 public void EvaluateStartElement (
1733 string localName, string ns)
1735 State = State.EvaluateStartElement (localName, ns);
1738 public void SetElement (XmlSchemaElement element)
1743 public void SetState (XsdValidationState state)