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;
36 using System.Xml.Schema;
39 using ContentProc = System.Xml.Schema.XmlSchemaContentProcessing;
40 using XsElement = System.Xml.Schema.XmlSchemaElement;
41 using XsAttribute = System.Xml.Schema.XmlSchemaAttribute;
42 using ComplexType = System.Xml.Schema.XmlSchemaComplexType;
43 using SimpleType = System.Xml.Schema.XmlSchemaSimpleType;
44 using SimpleTypeRest = System.Xml.Schema.XmlSchemaSimpleTypeRestriction;
45 using SimpleTypeList = System.Xml.Schema.XmlSchemaSimpleTypeList;
46 using SimpleTypeUnion = System.Xml.Schema.XmlSchemaSimpleTypeUnion;
47 using XsDatatype = System.Xml.Schema.XmlSchemaDatatype;
49 namespace Mono.Xml.Schema
51 internal class XsdValidatingReader : XmlReader, IXmlLineInfo, IHasXmlSchemaInfo, IHasXmlParserContext, IXmlNamespaceResolver
53 static readonly XsAttribute [] emptyAttributeArray =
58 IHasXmlSchemaInfo sourceReaderSchemaInfo;
59 IXmlLineInfo readerLineInfo;
60 ValidationType validationType;
61 XmlSchemaSet schemas = new XmlSchemaSet ();
62 bool namespaces = true;
64 #region ID Constraints
65 bool checkIdentity = true;
66 Hashtable idList = new Hashtable ();
67 ArrayList missingIDReferences;
71 #region Key Constraints
72 bool checkKeyConstraints = true;
73 ArrayList keyTables = new ArrayList ();
74 ArrayList currentKeyFieldConsumers;
75 ArrayList tmpKeyrefPool;
76 ArrayList elementQNameStack = new ArrayList ();
79 XsdParticleStateManager state = new XsdParticleStateManager ();
81 int skipValidationDepth = -1;
83 StringBuilder storedCharacters = new StringBuilder ();
84 bool shouldValidateCharacters;
86 XsAttribute [] defaultAttributes = emptyAttributeArray;
87 int currentDefaultAttribute = -1;
88 ArrayList defaultAttributesCache = new ArrayList ();
89 bool defaultAttributeConsumed;
90 object currentAttrType;
93 public XsdValidatingReader (XmlReader reader)
96 readerLineInfo = reader as IXmlLineInfo;
97 sourceReaderSchemaInfo = reader as IHasXmlSchemaInfo;
98 schemas.ValidationEventHandler += ValidationEventHandler;
102 public ValidationEventHandler ValidationEventHandler;
104 // Private Properties
106 private XsdValidationContext Context {
107 get { return state.Context; }
110 #region Key Constraints
111 internal ArrayList CurrentKeyFieldConsumers {
113 if (currentKeyFieldConsumers == null)
114 currentKeyFieldConsumers = new ArrayList ();
115 return currentKeyFieldConsumers;
120 private ArrayList MissingIDReferences {
122 if (missingIDReferences == null)
123 missingIDReferences = new ArrayList ();
124 return missingIDReferences;
128 // Public Non-overrides
130 public int XsiNilDepth {
131 get { return xsiNilDepth; }
134 public bool Namespaces {
135 get { return namespaces; }
136 set { namespaces = value; }
139 // This is required to resolve xsi:schemaLocation
140 public XmlResolver XmlResolver {
146 // This should be changed before the first Read() call.
147 public XmlSchemaSet Schemas {
148 get { return schemas; }
150 if (ReadState != ReadState.Initial)
151 throw new InvalidOperationException ("Schemas must be set before the first call to Read().");
156 public object SchemaType {
158 if (ReadState != ReadState.Interactive)
162 case XmlNodeType.Element:
163 if (Context.ActualType != null)
164 return Context.ActualType;
166 return SourceReaderSchemaType;
167 case XmlNodeType.Attribute:
168 if (currentAttrType == null) {
169 ComplexType ct = Context.ActualType as ComplexType;
171 XsAttribute attdef = ct.AttributeUses [new XmlQualifiedName (LocalName, NamespaceURI)] as XsAttribute;
173 currentAttrType = attdef.AttributeType;
174 return currentAttrType;
176 currentAttrType = SourceReaderSchemaType;
178 return currentAttrType;
180 return SourceReaderSchemaType;
185 private object SourceReaderSchemaType {
186 get { return this.sourceReaderSchemaInfo != null ? sourceReaderSchemaInfo.SchemaType : null; }
189 public ValidationType ValidationType {
190 get { return validationType; }
192 if (ReadState != ReadState.Initial)
193 throw new InvalidOperationException ("ValidationType must be set before reading.");
194 validationType = value;
198 IDictionary IXmlNamespaceResolver.GetNamespacesInScope (XmlNamespaceScope scope)
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 collect in-scope namespaces.");
203 return resolver.GetNamespacesInScope (scope);
206 string IXmlNamespaceResolver.LookupPrefix (string ns)
208 return ((IXmlNamespaceResolver) this).LookupPrefix (ns, false);
211 string IXmlNamespaceResolver.LookupPrefix (string ns, bool atomizedNames)
213 IXmlNamespaceResolver resolver = reader as IXmlNamespaceResolver;
214 if (resolver == null)
215 throw new NotSupportedException ("The input XmlReader does not implement IXmlNamespaceResolver and thus this validating reader cannot execute namespace prefix lookup.");
216 return resolver.LookupPrefix (ns, atomizedNames);
219 // It is used only for independent XmlReader use, not for XmlValidatingReader.
221 public override object ReadTypedValue ()
223 public object ReadTypedValue ()
226 object o = XmlSchemaUtil.ReadTypedValue (this,
227 SchemaType, ParserContext.NamespaceManager,
229 storedCharacters.Length = 0;
233 private object ReadTypedValueCore ()
235 XsDatatype dt = SchemaType as XsDatatype;
236 SimpleType st = SchemaType as SimpleType;
243 case XmlNodeType.Element:
247 storedCharacters.Length = 0;
252 case XmlNodeType.SignificantWhitespace:
253 case XmlNodeType.Text:
254 case XmlNodeType.CDATA:
255 storedCharacters.Append (Value);
257 case XmlNodeType.Comment:
263 } while (loop && !EOF && ReadState == ReadState.Interactive);
264 return dt.ParseValue (storedCharacters.ToString (), NameTable, ParserContext.NamespaceManager);
265 case XmlNodeType.Attribute:
266 return dt.ParseValue (Value, NameTable, ParserContext.NamespaceManager);
271 // Public Overriden Properties
273 public override int AttributeCount {
275 return reader.AttributeCount + defaultAttributes.Length;
279 public override string BaseURI {
280 get { return reader.BaseURI; }
283 // If this class is used to implement XmlValidatingReader,
284 // it should be left to DTDValidatingReader. In other cases,
285 // it depends on the reader's ability.
286 public override bool CanResolveEntity {
287 get { return reader.CanResolveEntity; }
290 public override int Depth {
292 if (currentDefaultAttribute < 0)
294 if (this.defaultAttributeConsumed)
295 return reader.Depth + 2;
296 return reader.Depth + 1;
300 public override bool EOF {
301 get { return reader.EOF; }
304 public override bool HasValue {
306 if (currentDefaultAttribute < 0)
307 return reader.HasValue;
312 public override bool IsDefault {
314 if (currentDefaultAttribute < 0)
315 return reader.IsDefault;
320 public override bool IsEmptyElement {
322 if (currentDefaultAttribute < 0)
323 return reader.IsEmptyElement;
328 public override string this [int i] {
329 get { return GetAttribute (i); }
332 public override string this [string name] {
333 get { return GetAttribute (name); }
336 public override string this [string localName, string ns] {
337 get { return GetAttribute (localName, ns); }
340 int IXmlLineInfo.LineNumber {
341 get { return readerLineInfo != null ? readerLineInfo.LineNumber : 0; }
344 int IXmlLineInfo.LinePosition {
345 get { return readerLineInfo != null ? readerLineInfo.LinePosition : 0; }
348 public override string LocalName {
350 if (currentDefaultAttribute < 0)
351 return reader.LocalName;
352 if (defaultAttributeConsumed)
354 return defaultAttributes [currentDefaultAttribute].QualifiedName.Name;
358 public override string Name {
360 if (currentDefaultAttribute < 0)
362 if (defaultAttributeConsumed)
365 XmlQualifiedName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
366 string prefix = Prefix;
367 if (prefix == String.Empty)
370 return String.Concat (prefix, ":", qname.Name);
374 public override string NamespaceURI {
376 if (currentDefaultAttribute < 0)
377 return reader.NamespaceURI;
378 if (defaultAttributeConsumed)
380 return defaultAttributes [currentDefaultAttribute].QualifiedName.Namespace;
384 public override XmlNameTable NameTable {
385 get { return reader.NameTable; }
388 public override XmlNodeType NodeType {
390 if (currentDefaultAttribute < 0)
391 return reader.NodeType;
392 if (defaultAttributeConsumed)
393 return XmlNodeType.Text;
394 return XmlNodeType.Attribute;
398 public XmlParserContext ParserContext {
399 get { return XmlSchemaUtil.GetParserContext (reader); }
402 public override string Prefix {
404 if (currentDefaultAttribute < 0)
405 return reader.Prefix;
406 if (defaultAttributeConsumed)
408 XmlQualifiedName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
409 string prefix = this.ParserContext.NamespaceManager.LookupPrefix (qname.Namespace, false);
417 public override char QuoteChar {
418 get { return reader.QuoteChar; }
421 public override ReadState ReadState {
422 get { return reader.ReadState; }
425 public override string Value {
427 if (currentDefaultAttribute < 0)
429 string value = defaultAttributes [currentDefaultAttribute].ValidatedDefaultValue;
431 value = defaultAttributes [currentDefaultAttribute].ValidatedFixedValue;
436 public override string XmlLang {
438 string xmlLang = reader.XmlLang;
441 int idx = this.FindDefaultAttribute ("lang", XmlNamespaceManager.XmlnsXml);
444 xmlLang = defaultAttributes [idx].ValidatedDefaultValue;
446 xmlLang = defaultAttributes [idx].ValidatedFixedValue;
451 public override XmlSpace XmlSpace {
453 XmlSpace space = reader.XmlSpace;
454 if (space != XmlSpace.None)
456 int idx = this.FindDefaultAttribute ("space", XmlNamespaceManager.XmlnsXml);
458 return XmlSpace.None;
459 string spaceSpec = defaultAttributes [idx].ValidatedDefaultValue;
460 if (spaceSpec == null)
461 spaceSpec = defaultAttributes [idx].ValidatedFixedValue;
462 return (XmlSpace) Enum.Parse (typeof (XmlSpace), spaceSpec, false);
468 private void HandleError (string error)
470 HandleError (error, null);
473 private void HandleError (string error, Exception innerException)
475 HandleError (error, innerException, false);
478 private void HandleError (string error, Exception innerException, bool isWarning)
480 if (ValidationType == ValidationType.None) // extra quick check
483 XmlSchemaException schemaException = new XmlSchemaException (error,
484 this, this.BaseURI, null, innerException);
485 HandleError (schemaException, isWarning);
488 private void HandleError (XmlSchemaException schemaException)
490 HandleError (schemaException, false);
493 private void HandleError (XmlSchemaException schemaException, bool isWarning)
495 if (ValidationType == ValidationType.None)
498 ValidationEventArgs e = new ValidationEventArgs (schemaException,
499 schemaException.Message, isWarning ? XmlSeverityType.Warning : XmlSeverityType.Error);
501 if (ValidationEventHandler != null)
502 ValidationEventHandler (this, e);
504 else if (e.Severity == XmlSeverityType.Error)
508 private XsElement FindElement (string name, string ns)
510 return (XsElement) schemas.GlobalElements [new XmlQualifiedName (name, ns)];
513 private XmlSchemaType FindType (XmlQualifiedName qname)
515 return (XmlSchemaType) schemas.GlobalTypes [qname];
518 private void ValidateStartElementParticle ()
520 if (Context.State == null)
522 Context.XsiType = null;
523 state.CurrentElement = null;
524 Context.EvaluateStartElement (reader.LocalName,
525 reader.NamespaceURI);
526 if (Context.IsInvalid)
527 HandleError ("Invalid start element: " + reader.NamespaceURI + ":" + reader.LocalName);
529 Context.SetElement (state.CurrentElement);
532 private void ValidateEndElementParticle ()
534 if (Context.State != null) {
535 if (!Context.EvaluateEndElement ()) {
536 HandleError ("Invalid end element: " + reader.Name);
542 // Utility for missing validation completion related to child items.
543 private void ValidateCharacters ()
545 if (xsiNilDepth >= 0 && xsiNilDepth < reader.Depth)
546 HandleError ("Element item appeared, while current element context is nil.");
548 if (shouldValidateCharacters)
549 storedCharacters.Append (reader.Value);
552 // Utility for missing validation completion related to child items.
553 private void ValidateEndCharacters ()
555 if (shouldValidateCharacters)
556 ValidateEndCharactersCore ();
557 shouldValidateCharacters = false;
558 storedCharacters.Length = 0;
561 private void ValidateEndCharactersCore ()
563 if (Context.ActualType == null)
566 string value = storedCharacters.ToString ();
568 if (value.Length == 0) {
569 // 3.3.4 Element Locally Valid (Element) 5.1.2
570 if (Context.Element != null) {
571 if (Context.Element.ValidatedDefaultValue != null)
572 value = Context.Element.ValidatedDefaultValue;
576 XsDatatype dt = Context.ActualType as XsDatatype;
577 SimpleType st = Context.ActualType as SimpleType;
582 ComplexType ct = Context.ActualType as ComplexType;
584 switch (ct.ContentType) {
585 case XmlSchemaContentType.ElementOnly:
586 case XmlSchemaContentType.Empty:
587 if (value.Length > 0)
588 HandleError ("Character content not allowed.");
594 // 3.3.4 Element Locally Valid (Element) :: 5.2.2.2. Fixed value constraints
595 if (Context.Element != null && Context.Element.ValidatedFixedValue != null)
596 if (value != Context.Element.ValidatedFixedValue)
597 HandleError ("Fixed value constraint was not satisfied.");
598 AssessStringValid (st, dt, value);
601 #region Key Constraints
602 if (checkKeyConstraints)
603 ValidateSimpleContentIdentity (dt, value);
606 shouldValidateCharacters = false;
609 #region Key Constraints
610 private void ValidateSimpleContentIdentity (
611 XmlSchemaDatatype dt, string value)
613 // Identity field value
614 if (currentKeyFieldConsumers != null) {
615 while (this.currentKeyFieldConsumers.Count > 0) {
616 XsdKeyEntryField field = this.currentKeyFieldConsumers [0] as XsdKeyEntryField;
617 if (field.Identity != null)
618 HandleError ("Two or more identical field was found. Former value is '" + field.Identity + "' .");
619 object identity = null; // This means empty value
622 identity = dt.ParseValue (value, NameTable, ParserContext.NamespaceManager);
623 } catch (Exception ex) { // FIXME: (wishlist) This is bad manner ;-(
624 HandleError ("Identity value is invalid against its data type " + dt.TokenizedType, ex);
627 if (identity == null)
630 if (!field.SetIdentityField (identity, reader.Depth == xsiNilDepth, dt as XsdAnySimpleType, this.Depth, (IXmlLineInfo) this))
631 HandleError ("Two or more identical key value was found: '" + value + "' .");
632 this.currentKeyFieldConsumers.RemoveAt (0);
638 // 3.14.4 String Valid
639 private void AssessStringValid (SimpleType st,
640 XsDatatype dt, string value)
642 XsDatatype validatedDatatype = dt;
644 string normalized = validatedDatatype.Normalize (value);
646 XsDatatype itemDatatype;
647 SimpleType itemSimpleType;
648 switch (st.DerivedBy) {
649 case XmlSchemaDerivationMethod.List:
650 SimpleTypeList listContent = st.Content as SimpleTypeList;
651 values = normalized.Split (XmlChar.WhitespaceChars);
652 itemDatatype = listContent.ValidatedListItemType as XsDatatype;
653 itemSimpleType = listContent.ValidatedListItemType as SimpleType;
654 for (int vi = 0; vi < values.Length; vi++) {
655 string each = values [vi];
656 if (each == String.Empty)
658 // validate against ValidatedItemType
659 if (itemDatatype != null) {
661 itemDatatype.ParseValue (each, NameTable, ParserContext.NamespaceManager);
662 } catch (Exception ex) { // FIXME: (wishlist) better exception handling ;-(
663 HandleError ("List type value contains one or more invalid values.", ex);
668 AssessStringValid (itemSimpleType, itemSimpleType.Datatype, each);
671 case XmlSchemaDerivationMethod.Union:
672 SimpleTypeUnion union = st.Content as SimpleTypeUnion;
674 string each = normalized;
675 // validate against ValidatedItemType
677 foreach (object eachType in union.ValidatedTypes) {
678 itemDatatype = eachType as XsDatatype;
679 itemSimpleType = eachType as SimpleType;
680 if (itemDatatype != null) {
682 itemDatatype.ParseValue (each, NameTable, ParserContext.NamespaceManager);
683 } catch (Exception) { // FIXME: (wishlist) better exception handling ;-(
689 AssessStringValid (itemSimpleType, itemSimpleType.Datatype, each);
690 } catch (XmlSchemaException) {
698 HandleError ("Union type value contains one or more invalid values.");
703 case XmlSchemaDerivationMethod.Restriction:
704 SimpleTypeRest str = st.Content as SimpleTypeRest;
707 /* Don't forget to validate against inherited type's facets
708 * Could we simplify this by assuming that the basetype will also
711 // mmm, will check later.
712 SimpleType baseType = st.BaseXmlSchemaType as SimpleType;
713 if (baseType != null) {
714 AssessStringValid(baseType, dt, normalized);
716 if (!str.ValidateValueWithFacets (normalized, NameTable)) {
717 HandleError ("Specified value was invalid against the facets.");
721 validatedDatatype = st.Datatype;
725 if (validatedDatatype != null) {
727 validatedDatatype.ParseValue (value, NameTable, ParserContext.NamespaceManager);
728 } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
729 HandleError ("Invalidly typed data was specified.", ex);
734 private object GetXsiType (string name)
736 object xsiType = null;
737 XmlQualifiedName typeQName =
738 XmlQualifiedName.Parse (name, this);
739 if (typeQName == ComplexType.AnyTypeName)
740 xsiType = ComplexType.AnyType;
741 else if (XmlSchemaUtil.IsBuiltInDatatypeName (typeQName))
742 xsiType = XsDatatype.FromName (typeQName);
744 xsiType = FindType (typeQName);
748 // It is common to ElementLocallyValid::4 and SchemaValidityAssessment::1.2.1.2.4
749 private void AssessLocalTypeDerivationOK (object xsiType, object baseType, XmlSchemaDerivationMethod flag)
751 XmlSchemaType xsiSchemaType = xsiType as XmlSchemaType;
752 ComplexType baseComplexType = baseType as ComplexType;
753 ComplexType xsiComplexType = xsiSchemaType as ComplexType;
754 if (xsiType != baseType) {
755 // Extracted (not extraneous) check for 3.4.6 TypeDerivationOK.
756 if (baseComplexType != null)
757 flag |= baseComplexType.BlockResolved;
758 if (flag == XmlSchemaDerivationMethod.All) {
759 HandleError ("Prohibited element type substitution.");
761 } else if (xsiSchemaType != null && (flag & xsiSchemaType.DerivedBy) != 0) {
762 HandleError ("Prohibited element type substitution.");
767 if (xsiComplexType != null)
769 xsiComplexType.ValidateTypeDerivationOK (baseType, null, null);
770 } catch (XmlSchemaException ex) {
771 // HandleError ("Locally specified schema complex type derivation failed. " + ex.Message, ex);
775 SimpleType xsiSimpleType = xsiType as SimpleType;
776 if (xsiSimpleType != null) {
778 xsiSimpleType.ValidateTypeDerivationOK (baseType, null, null, true);
779 } catch (XmlSchemaException ex) {
780 // HandleError ("Locally specified schema simple type derivation failed. " + ex.Message, ex);
784 else if (xsiType is XsDatatype) {
788 HandleError ("Primitive data type cannot be derived type using xsi:type specification.");
792 // Section 3.3.4 of the spec.
793 private void AssessStartElementSchemaValidity ()
795 // If the reader is inside xsi:nil (and failed
796 // on validation), then simply skip its content.
797 if (xsiNilDepth >= 0 && xsiNilDepth < reader.Depth)
798 HandleError ("Element item appeared, while current element context is nil.");
800 ValidateStartElementParticle ();
802 string xsiNilValue = reader.GetAttribute ("nil", XmlSchema.InstanceNamespace);
803 if (xsiNilValue != null)
804 xsiNilValue = xsiNilValue.Trim (XmlChar.WhitespaceChars);
805 bool isXsiNil = xsiNilValue == "true";
806 if (isXsiNil && this.xsiNilDepth < 0)
807 xsiNilDepth = reader.Depth;
809 // [Schema Validity Assessment (Element) 1.2]
810 // Evaluate "local type definition" from xsi:type.
811 // (See spec 3.3.4 Schema Validity Assessment (Element) 1.2.1.2.3.
812 // Note that Schema Validity Assessment(Element) 1.2 takes
813 // precedence than 1.1 of that.
815 string xsiTypeName = reader.GetAttribute ("type", XmlSchema.InstanceNamespace);
816 if (xsiTypeName != null) {
817 xsiTypeName = xsiTypeName.Trim (XmlChar.WhitespaceChars);
818 object xsiType = GetXsiType (xsiTypeName);
820 HandleError ("The instance type was not found: " + xsiTypeName + " .");
822 XmlSchemaType xsiSchemaType = xsiType as XmlSchemaType;
823 if (xsiSchemaType != null && this.Context.Element != null) {
824 XmlSchemaType elemBaseType = Context.Element.ElementType as XmlSchemaType;
825 if (elemBaseType != null && (xsiSchemaType.DerivedBy & elemBaseType.FinalResolved) != 0)
826 HandleError ("The instance type is prohibited by the type of the context element.");
827 if (elemBaseType != xsiType && (xsiSchemaType.DerivedBy & this.Context.Element.BlockResolved) != 0)
828 HandleError ("The instance type is prohibited by the context element.");
830 ComplexType xsiComplexType = xsiType as ComplexType;
831 if (xsiComplexType != null && xsiComplexType.IsAbstract)
832 HandleError ("The instance type is abstract: " + xsiTypeName + " .");
834 // If current schema type exists, then this xsi:type must be
835 // valid extension of that type. See 1.2.1.2.4.
836 if (Context.Element != null) {
837 AssessLocalTypeDerivationOK (xsiType, Context.Element.ElementType, Context.Element.BlockResolved);
839 AssessStartElementLocallyValidType (xsiType); // 1.2.2:
840 Context.XsiType = xsiType;
845 // Create Validation Root, if not exist.
846 // [Schema Validity Assessment (Element) 1.1]
847 if (Context.Element == null) {
848 state.CurrentElement = FindElement (reader.LocalName, reader.NamespaceURI);
849 Context.SetElement (state.CurrentElement);
851 if (Context.Element != null) {
852 if (xsiTypeName == null) {
853 AssessElementLocallyValidElement (Context.Element, xsiNilValue); // 1.1.2
856 switch (state.ProcessContents) {
857 case ContentProc.Skip:
859 case ContentProc.Lax:
862 if (xsiTypeName == null &&
863 (schemas.Contains (reader.NamespaceURI) ||
864 !schemas.MissedSubComponents (reader.NamespaceURI)))
865 HandleError ("Element declaration for " + reader.LocalName + " is missing.");
870 state.PushContext ();
872 XsdValidationState next = null;
873 if (state.ProcessContents == ContentProc.Skip)
874 skipValidationDepth = reader.Depth;
876 // create child particle state.
877 ComplexType xsComplexType = SchemaType as ComplexType;
878 if (xsComplexType != null)
879 next = state.Create (xsComplexType.ValidatableParticle);
880 else if (state.ProcessContents == ContentProc.Lax)
881 next = state.Create (XmlSchemaAny.AnyTypeContent);
883 next = state.Create (XmlSchemaParticle.Empty);
885 Context.State = next;
887 #region Key Constraints
888 if (checkKeyConstraints)
889 AssessStartIdentityConstraints ();
894 // 3.3.4 Element Locally Valid (Element)
895 private void AssessElementLocallyValidElement (XsElement element, string xsiNilValue)
897 XmlQualifiedName qname = new XmlQualifiedName (reader.LocalName, reader.NamespaceURI);
900 HandleError ("Element declaration is required for " + qname);
902 if (element.ActualIsAbstract)
903 HandleError ("Abstract element declaration was specified for " + qname);
905 if (!element.ActualIsNillable && xsiNilValue != null)
906 HandleError ("This element declaration is not nillable: " + qname);
908 // Note that 3.2.1 xsi:nil constraints are to be validated in
909 else if (xsiNilValue == "true") {
910 // AssessElementSchemaValidity() and ValidateCharacters()
912 if (element.ValidatedFixedValue != null)
913 HandleError ("Schema instance nil was specified, where the element declaration for " + qname + "has fixed value constraints.");
916 string xsiType = reader.GetAttribute ("type", XmlSchema.InstanceNamespace);
917 if (xsiType != null) {
918 Context.XsiType = GetXsiType (xsiType);
919 AssessLocalTypeDerivationOK (Context.XsiType, element.ElementType, element.BlockResolved);
922 Context.XsiType = null;
924 // 5 Not all things cannot be assessed here.
925 // It is common to 5.1 and 5.2
926 if (element.ElementType != null)
927 AssessStartElementLocallyValidType (SchemaType);
929 // 6. should be out from here.
930 // See invokation of AssessStartIdentityConstraints().
932 // 7 is going to be validated in Read() (in case of xmlreader's EOF).
935 // 3.3.4 Element Locally Valid (Type)
936 private void AssessStartElementLocallyValidType (object schemaType)
938 if (schemaType == null) { // 1.
939 HandleError ("Schema type does not exist.");
942 ComplexType cType = schemaType as ComplexType;
943 SimpleType sType = schemaType as SimpleType;
946 while (reader.MoveToNextAttribute ()) {
947 if (reader.NamespaceURI == XmlNamespaceManager.XmlnsXmlns)
949 if (reader.NamespaceURI != XmlSchema.InstanceNamespace)
950 HandleError ("Current simple type cannot accept attributes other than schema instance namespace.");
951 switch (reader.LocalName) {
954 case "schemaLocation":
955 case "noNamespaceSchemaLocation":
958 HandleError ("Unknown schema instance namespace attribute: " + reader.LocalName);
962 reader.MoveToElement ();
963 // 3.1.2 and 3.1.3 cannot be assessed here.
964 } else if (cType != null) {
965 if (cType.IsAbstract) { // 2.
966 HandleError ("Target complex type is abstract.");
970 AssessElementLocallyValidComplexType (cType);
974 // 3.4.4 Element Locally Valid (Complex Type)
975 private void AssessElementLocallyValidComplexType (ComplexType cType)
978 if (cType.IsAbstract)
979 HandleError ("Target complex type is abstract.");
981 // 2 (xsi:nil and content prohibition)
982 // See AssessStartElementSchemaValidity() and ValidateCharacters()
984 // 3. attribute uses and
986 if (reader.MoveToFirstAttribute ()) {
988 switch (reader.NamespaceURI) {
989 case"http://www.w3.org/2000/xmlns/":
990 case XmlSchema.InstanceNamespace:
993 XmlQualifiedName qname = new XmlQualifiedName (reader.LocalName, reader.NamespaceURI);
994 XmlSchemaObject attMatch = FindAttributeDeclaration (cType, qname);
995 if (attMatch == null)
996 HandleError ("Attribute declaration was not found for " + qname);
997 XsAttribute attdecl = attMatch as XsAttribute;
998 if (attdecl != null) {
999 AssessAttributeLocallyValidUse (attdecl);
1000 AssessAttributeLocallyValid (attdecl);
1001 } // otherwise anyAttribute or null.
1002 } while (reader.MoveToNextAttribute ());
1003 reader.MoveToElement ();
1006 // Collect default attributes.
1008 foreach (DictionaryEntry entry in cType.AttributeUses) {
1009 XsAttribute attr = (XsAttribute) entry.Value;
1010 if (reader [attr.QualifiedName.Name, attr.QualifiedName.Namespace] == null) {
1011 if (attr.ValidatedUse == XmlSchemaUse.Required &&
1012 attr.ValidatedFixedValue == null)
1013 HandleError ("Required attribute " + attr.QualifiedName + " was not found.");
1014 else if (attr.ValidatedDefaultValue != null || attr.ValidatedFixedValue != null)
1015 defaultAttributesCache.Add (attr);
1018 if (defaultAttributesCache.Count == 0)
1019 defaultAttributes = emptyAttributeArray;
1021 defaultAttributes = (XsAttribute [])
1022 defaultAttributesCache.ToArray (
1023 typeof (XsAttribute));
1024 defaultAttributesCache.Clear ();
1025 // 5. wild IDs was already checked above.
1028 // Spec 3.10.4 Item Valid (Wildcard)
1029 private static bool AttributeWildcardItemValid (XmlSchemaAnyAttribute anyAttr, XmlQualifiedName qname, string ns)
1031 if (anyAttr.HasValueAny)
1033 if (anyAttr.HasValueOther && (anyAttr.TargetNamespace == "" || ns != anyAttr.TargetNamespace))
1035 if (anyAttr.HasValueTargetNamespace && ns == anyAttr.TargetNamespace)
1037 if (anyAttr.HasValueLocal && ns == "")
1039 for (int i = 0; i < anyAttr.ResolvedNamespaces.Count; i++)
1040 if (anyAttr.ResolvedNamespaces [i] == ns)
1045 private XmlSchemaObject FindAttributeDeclaration (
1047 XmlQualifiedName qname)
1049 XmlSchemaObject result = cType.AttributeUses [qname];
1052 if (cType.AttributeWildcard == null)
1055 if (!AttributeWildcardItemValid (cType.AttributeWildcard, qname, reader.NamespaceURI))
1058 if (cType.AttributeWildcard.ResolvedProcessContents == ContentProc.Skip)
1059 return cType.AttributeWildcard;
1060 XsAttribute attr = schemas.GlobalAttributes [qname] as XsAttribute;
1063 if (cType.AttributeWildcard.ResolvedProcessContents == ContentProc.Lax)
1064 return cType.AttributeWildcard;
1069 // 3.2.4 Attribute Locally Valid and 3.4.4
1070 private void AssessAttributeLocallyValid (XsAttribute attr)
1073 if (attr.AttributeType == null)
1074 HandleError ("Attribute type is missing for " + attr.QualifiedName);
1075 XsDatatype dt = attr.AttributeType as XsDatatype;
1077 dt = ((SimpleType) attr.AttributeType).Datatype;
1078 // It is a bit heavy process, so let's omit as long as possible ;-)
1079 if (dt != SimpleType.AnySimpleType || attr.ValidatedFixedValue != null) {
1080 string normalized = dt.Normalize (reader.Value);
1081 object parsedValue = null;
1083 parsedValue = dt.ParseValue (normalized, reader.NameTable, this.ParserContext.NamespaceManager);
1084 } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
1085 HandleError ("Attribute value is invalid against its data type " + dt.TokenizedType, ex);
1087 if (attr.ValidatedFixedValue != null && attr.ValidatedFixedValue != normalized) {
1088 HandleError ("The value of the attribute " + attr.QualifiedName + " does not match with its fixed value.");
1089 parsedValue = dt.ParseValue (attr.ValidatedFixedValue, reader.NameTable, this.ParserContext.NamespaceManager);
1091 #region ID Constraints
1092 if (this.checkIdentity)
1093 AssessEachAttributeIdentityConstraint (dt, parsedValue);
1099 private void AssessEachAttributeIdentityConstraint (
1100 XsDatatype dt, object parsedValue)
1102 // Validate identity constraints.
1103 string str = parsedValue as string;
1104 switch (dt.TokenizedType) {
1105 case XmlTokenizedType.ID:
1106 if (thisElementId != null)
1107 HandleError ("ID type attribute was already assigned in the containing element.");
1108 thisElementId = str;
1109 if (idList.Contains (str))
1110 HandleError ("Duplicate ID value was found.");
1112 idList.Add (str, str);
1113 if (MissingIDReferences.Contains (str))
1114 MissingIDReferences.Remove (str);
1116 case XmlTokenizedType.IDREF:
1117 if (!idList.Contains (str))
1118 MissingIDReferences.Add (str);
1120 case XmlTokenizedType.IDREFS:
1121 string [] idrefs = (string []) parsedValue;
1122 for (int i = 0; i < idrefs.Length; i++) {
1123 string id = idrefs [i];
1124 if (!idList.Contains (id))
1125 MissingIDReferences.Add (id);
1131 private void AssessAttributeLocallyValidUse (XsAttribute attr)
1133 // This is extra check than spec 3.5.4
1134 if (attr.ValidatedUse == XmlSchemaUse.Prohibited)
1135 HandleError ("Attribute " + attr.QualifiedName + " is prohibited in this context.");
1138 private void AssessEndElementSchemaValidity ()
1140 ValidateEndElementParticle (); // validate against childrens' state.
1142 ValidateEndCharacters ();
1144 // 3.3.4 Assess ElementLocallyValidElement 5: value constraints.
1145 // 3.3.4 Assess ElementLocallyValidType 3.1.3. = StringValid(3.14.4)
1146 // => ValidateEndCharacters().
1148 #region Key Constraints
1149 if (checkKeyConstraints)
1150 ValidateEndElementKeyConstraints ();
1153 // Reset xsi:nil, if required.
1154 if (xsiNilDepth == reader.Depth)
1158 #region Key Constraints
1159 private void ValidateEndElementKeyConstraints ()
1161 // Reset Identity constraints.
1162 for (int i = 0; i < keyTables.Count; i++) {
1163 XsdKeyTable seq = this.keyTables [i] as XsdKeyTable;
1164 if (seq.StartDepth == reader.Depth) {
1165 EndIdentityValidation (seq);
1167 for (int k = 0; k < seq.Entries.Count; k++) {
1168 XsdKeyEntry entry = seq.Entries [k] as XsdKeyEntry;
1169 // Remove finished (maybe key not found) entries.
1170 if (entry.StartDepth == reader.Depth) {
1172 seq.FinishedEntries.Add (entry);
1173 else if (entry.KeySequence.SourceSchemaIdentity is XmlSchemaKey)
1174 HandleError ("Key sequence is missing.");
1175 seq.Entries.RemoveAt (k);
1178 // Pop validated key depth to find two or more fields.
1180 for (int j = 0; j < entry.KeyFields.Count; j++) {
1181 XsdKeyEntryField kf = entry.KeyFields [j];
1182 if (!kf.FieldFound && kf.FieldFoundDepth == reader.Depth) {
1183 kf.FieldFoundDepth = 0;
1184 kf.FieldFoundPath = null;
1191 for (int i = 0; i < keyTables.Count; i++) {
1192 XsdKeyTable seq = this.keyTables [i] as XsdKeyTable;
1193 if (seq.StartDepth == reader.Depth) {
1194 keyTables.RemoveAt (i);
1200 // 3.11.4 Identity Constraint Satisfied
1201 private void AssessStartIdentityConstraints ()
1203 if (tmpKeyrefPool != null)
1204 tmpKeyrefPool.Clear ();
1205 if (Context.Element != null && Context.Element.Constraints.Count > 0) {
1206 // (a) Create new key sequences, if required.
1207 for (int i = 0; i < Context.Element.Constraints.Count; i++) {
1208 XmlSchemaIdentityConstraint ident = (XmlSchemaIdentityConstraint) Context.Element.Constraints [i];
1209 XsdKeyTable seq = CreateNewKeyTable (ident);
1210 if (ident is XmlSchemaKeyref) {
1211 if (tmpKeyrefPool == null)
1212 tmpKeyrefPool = new ArrayList ();
1213 tmpKeyrefPool.Add (seq);
1218 // (b) Evaluate current key sequences.
1219 for (int i = 0; i < keyTables.Count; i++) {
1220 XsdKeyTable seq = (XsdKeyTable) keyTables [i];
1221 if (seq.SelectorMatches (this.elementQNameStack, reader) != null) {
1222 // creates and registers new entry.
1223 XsdKeyEntry entry = new XsdKeyEntry (seq, reader.Depth, reader as IXmlLineInfo);
1224 seq.Entries.Add (entry);
1228 // (c) Evaluate field paths.
1229 for (int i = 0; i < keyTables.Count; i++) {
1230 XsdKeyTable seq = (XsdKeyTable) keyTables [i];
1231 // If possible, create new field entry candidates.
1232 for (int j = 0; j < seq.Entries.Count; j++) {
1233 XsdKeyEntry entry = seq.Entries [j];
1235 entry.FieldMatches (this.elementQNameStack, this);
1236 } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
1237 HandleError ("Identity field value is invalid against its data type.", ex);
1243 private XsdKeyTable CreateNewKeyTable (XmlSchemaIdentityConstraint ident)
1245 XsdKeyTable seq = new XsdKeyTable (ident, this);
1246 seq.StartDepth = reader.Depth;
1247 this.keyTables.Add (seq);
1251 private void EndIdentityValidation (XsdKeyTable seq)
1253 ArrayList errors = new ArrayList ();
1254 for (int i = 0; i < seq.Entries.Count; i++) {
1255 XsdKeyEntry entry = (XsdKeyEntry) seq.Entries [i];
1258 if (seq.SourceSchemaIdentity is XmlSchemaKey)
1259 errors.Add ("line " + entry.SelectorLineNumber + "position " + entry.SelectorLinePosition);
1261 if (errors.Count > 0)
1262 HandleError ("Invalid identity constraints were found. Key was not found. "
1263 + String.Join (", ", errors.ToArray (typeof (string)) as string []));
1266 // Find reference target
1267 XmlSchemaKeyref xsdKeyref = seq.SourceSchemaIdentity as XmlSchemaKeyref;
1268 if (xsdKeyref != null) {
1269 for (int i = this.keyTables.Count - 1; i >= 0; i--) {
1270 XsdKeyTable target = this.keyTables [i] as XsdKeyTable;
1271 if (target.SourceSchemaIdentity == xsdKeyref.Target) {
1272 seq.ReferencedKey = target;
1273 for (int j = 0; j < seq.FinishedEntries.Count; j++) {
1274 XsdKeyEntry entry = (XsdKeyEntry) seq.FinishedEntries [j];
1275 for (int k = 0; k < target.FinishedEntries.Count; k++) {
1276 XsdKeyEntry targetEntry = (XsdKeyEntry) target.FinishedEntries [k];
1277 if (entry.CompareIdentity (targetEntry)) {
1278 entry.KeyRefFound = true;
1285 if (seq.ReferencedKey == null)
1286 HandleError ("Target key was not found.");
1287 for (int i = 0; i < seq.FinishedEntries.Count; i++) {
1288 XsdKeyEntry entry = (XsdKeyEntry) seq.FinishedEntries [i];
1289 if (!entry.KeyRefFound)
1290 errors.Add (" line " + entry.SelectorLineNumber + ", position " + entry.SelectorLinePosition);
1292 if (errors.Count > 0)
1293 HandleError ("Invalid identity constraints were found. Referenced key was not found: "
1294 + String.Join (" / ", errors.ToArray (typeof (string)) as string []));
1299 // Overrided Methods
1301 public override void Close ()
1306 public override string GetAttribute (int i)
1308 switch (reader.NodeType) {
1309 case XmlNodeType.XmlDeclaration:
1310 case XmlNodeType.DocumentType:
1311 return reader.GetAttribute (i);
1314 if (reader.AttributeCount > i)
1315 reader.GetAttribute (i);
1316 int defIdx = i - reader.AttributeCount;
1317 if (i < AttributeCount)
1318 return defaultAttributes [defIdx].DefaultValue;
1320 throw new ArgumentOutOfRangeException ("i", i, "Specified attribute index is out of range.");
1323 public override string GetAttribute (string name)
1325 switch (reader.NodeType) {
1326 case XmlNodeType.XmlDeclaration:
1327 case XmlNodeType.DocumentType:
1328 return reader.GetAttribute (name);
1331 string value = reader.GetAttribute (name);
1335 XmlQualifiedName qname = SplitQName (name);
1336 return GetDefaultAttribute (qname.Name, qname.Namespace);
1339 private XmlQualifiedName SplitQName (string name)
1341 if (!XmlChar.IsName (name))
1342 throw new ArgumentException ("Invalid name was specified.", "name");
1344 Exception ex = null;
1345 XmlQualifiedName qname = XmlSchemaUtil.ToQName (reader, name, out ex);
1347 return XmlQualifiedName.Empty;
1352 public override string GetAttribute (string localName, string ns)
1354 switch (reader.NodeType) {
1355 case XmlNodeType.XmlDeclaration:
1356 case XmlNodeType.DocumentType:
1357 return reader.GetAttribute (localName, ns);
1360 string value = reader.GetAttribute (localName, ns);
1364 return GetDefaultAttribute (localName, ns);
1367 private string GetDefaultAttribute (string localName, string ns)
1369 int idx = this.FindDefaultAttribute (localName, ns);
1372 string value = defaultAttributes [idx].ValidatedDefaultValue;
1374 value = defaultAttributes [idx].ValidatedFixedValue;
1378 private int FindDefaultAttribute (string localName, string ns)
1380 for (int i = 0; i < this.defaultAttributes.Length; i++) {
1381 XsAttribute attr = defaultAttributes [i];
1382 if (attr.QualifiedName.Name == localName &&
1383 (ns == null || attr.QualifiedName.Namespace == ns))
1389 bool IXmlLineInfo.HasLineInfo ()
1391 return readerLineInfo != null && readerLineInfo.HasLineInfo ();
1394 public override string LookupNamespace (string prefix)
1396 return reader.LookupNamespace (prefix);
1399 string IXmlNamespaceResolver.LookupNamespace (string prefix, bool atomizedNames)
1401 IXmlNamespaceResolver res = reader as IXmlNamespaceResolver;
1403 return res.LookupNamespace (prefix, atomizedNames);
1405 return reader.LookupNamespace (prefix);
1408 public override void MoveToAttribute (int i)
1410 switch (reader.NodeType) {
1411 case XmlNodeType.XmlDeclaration:
1412 case XmlNodeType.DocumentType:
1413 reader.MoveToAttribute (i);
1417 currentAttrType = null;
1418 if (i < reader.AttributeCount) {
1419 reader.MoveToAttribute (i);
1420 this.currentDefaultAttribute = -1;
1421 this.defaultAttributeConsumed = false;
1424 if (i < AttributeCount) {
1425 this.currentDefaultAttribute = i - reader.AttributeCount;
1426 this.defaultAttributeConsumed = false;
1429 throw new ArgumentOutOfRangeException ("i", i, "Attribute index is out of range.");
1432 public override bool MoveToAttribute (string name)
1434 switch (reader.NodeType) {
1435 case XmlNodeType.XmlDeclaration:
1436 case XmlNodeType.DocumentType:
1437 return reader.MoveToAttribute (name);
1440 currentAttrType = null;
1441 bool b = reader.MoveToAttribute (name);
1443 this.currentDefaultAttribute = -1;
1444 this.defaultAttributeConsumed = false;
1448 return MoveToDefaultAttribute (name, null);
1451 public override bool MoveToAttribute (string localName, string ns)
1453 switch (reader.NodeType) {
1454 case XmlNodeType.XmlDeclaration:
1455 case XmlNodeType.DocumentType:
1456 return reader.MoveToAttribute (localName, ns);
1459 currentAttrType = null;
1460 bool b = reader.MoveToAttribute (localName, ns);
1462 this.currentDefaultAttribute = -1;
1463 this.defaultAttributeConsumed = false;
1467 return MoveToDefaultAttribute (localName, ns);
1470 private bool MoveToDefaultAttribute (string localName, string ns)
1472 int idx = this.FindDefaultAttribute (localName, ns);
1475 currentDefaultAttribute = idx;
1476 defaultAttributeConsumed = false;
1480 public override bool MoveToElement ()
1482 currentDefaultAttribute = -1;
1483 defaultAttributeConsumed = false;
1484 currentAttrType = null;
1485 return reader.MoveToElement ();
1488 public override bool MoveToFirstAttribute ()
1490 switch (reader.NodeType) {
1491 case XmlNodeType.XmlDeclaration:
1492 case XmlNodeType.DocumentType:
1493 return reader.MoveToFirstAttribute ();
1496 currentAttrType = null;
1497 if (reader.AttributeCount > 0) {
1498 bool b = reader.MoveToFirstAttribute ();
1500 currentDefaultAttribute = -1;
1501 defaultAttributeConsumed = false;
1506 if (this.defaultAttributes.Length > 0) {
1507 currentDefaultAttribute = 0;
1508 defaultAttributeConsumed = false;
1515 public override bool MoveToNextAttribute ()
1517 switch (reader.NodeType) {
1518 case XmlNodeType.XmlDeclaration:
1519 case XmlNodeType.DocumentType:
1520 return reader.MoveToNextAttribute ();
1523 currentAttrType = null;
1524 if (currentDefaultAttribute >= 0) {
1525 if (defaultAttributes.Length == currentDefaultAttribute + 1)
1527 currentDefaultAttribute++;
1528 defaultAttributeConsumed = false;
1532 bool b = reader.MoveToNextAttribute ();
1534 currentDefaultAttribute = -1;
1535 defaultAttributeConsumed = false;
1539 if (defaultAttributes.Length > 0) {
1540 currentDefaultAttribute = 0;
1541 defaultAttributeConsumed = false;
1548 private void ExamineAdditionalSchema ()
1550 if (resolver == null)
1552 XmlSchema schema = null;
1553 string schemaLocation = reader.GetAttribute ("schemaLocation", XmlSchema.InstanceNamespace);
1554 bool schemaAdded = false;
1555 if (schemaLocation != null) {
1556 string [] tmp = null;
1558 schemaLocation = XsDatatype.FromName ("token", XmlSchema.Namespace).Normalize (schemaLocation);
1559 tmp = schemaLocation.Split (XmlChar.WhitespaceChars);
1560 } catch (Exception ex) {
1561 HandleError ("Invalid schemaLocation attribute format.", ex, true);
1562 tmp = new string [0];
1564 if (tmp.Length % 2 != 0)
1565 HandleError ("Invalid schemaLocation attribute format.");
1566 for (int i = 0; i < tmp.Length; i += 2) {
1568 XmlTextReader xtr = null;
1570 absUri = new Uri ((this.BaseURI != "" ? new Uri (BaseURI) : null), tmp [i + 1]);
1571 xtr = new XmlTextReader (
1573 (Stream) resolver.GetEntity (absUri, null, typeof (Stream)),
1575 schema = XmlSchema.Read (xtr, ValidationEventHandler);
1576 } catch (Exception) { // FIXME: (wishlist) It is bad manner ;-(
1577 HandleError ("Could not resolve schema location URI: " + absUri, null, true);
1583 if (schema.TargetNamespace == null)
1584 schema.TargetNamespace = tmp [i];
1585 else if (schema.TargetNamespace != tmp [i])
1586 HandleError ("Specified schema has different target namespace.");
1589 if (schema != null) {
1590 if (!schemas.Contains (schema.TargetNamespace)) {
1592 schemas.Add (schema);
1596 string noNsSchemaLocation = reader.GetAttribute ("noNamespaceSchemaLocation", XmlSchema.InstanceNamespace);
1597 if (noNsSchemaLocation != null) {
1599 XmlTextReader xtr = null;
1601 absUri = new Uri ((this.BaseURI != "" ? new Uri (BaseURI) : null), noNsSchemaLocation);
1602 xtr = new XmlTextReader (
1604 (Stream) resolver.GetEntity (absUri, null, typeof (Stream)),
1606 schema = XmlSchema.Read (xtr, ValidationEventHandler);
1607 } catch (Exception) { // FIXME: (wishlist) It is bad manner ;-(
1608 HandleError ("Could not resolve schema location URI: " + absUri, null, true);
1613 if (schema != null && schema.TargetNamespace != null)
1614 HandleError ("Specified schema has different target namespace.");
1616 if (schema != null) {
1617 if (!schemas.Contains (schema.TargetNamespace)) {
1619 schemas.Add (schema);
1622 // FIXME: should call Reprocess()?
1627 private bool HasMissingIDReferences ()
1629 return missingIDReferences != null
1630 && missingIDReferences.Count > 0;
1633 public override bool Read ()
1635 currentDefaultAttribute = -1;
1636 defaultAttributeConsumed = false;
1637 currentAttrType = null;
1638 #region ID Constraints
1639 if (this.checkIdentity)
1640 thisElementId = null;
1642 defaultAttributes = emptyAttributeArray;
1644 bool result = reader.Read ();
1645 #region ID Constraints
1646 // 3.3.4 ElementLocallyValidElement 7 = Root Valid.
1647 if (!result && this.checkIdentity &&
1648 HasMissingIDReferences ())
1649 HandleError ("There are missing ID references: " +
1651 this.missingIDReferences.ToArray (typeof (string)) as string []));
1654 // FIXME: schemaLocation could be specified
1656 if (reader.Depth == 0 &&
1657 reader.NodeType == XmlNodeType.Element)
1658 ExamineAdditionalSchema ();
1659 if (schemas.Count == 0)
1661 if (!schemas.IsCompiled)
1664 switch (reader.NodeType) {
1665 case XmlNodeType.Element:
1666 #region Key Constraints
1667 if (checkKeyConstraints)
1668 this.elementQNameStack.Add (new XmlQualifiedName (reader.LocalName, reader.NamespaceURI));
1671 // If there is no schema information, then no validation is performed.
1672 if (skipValidationDepth < 0 || reader.Depth <= skipValidationDepth) {
1673 ValidateEndCharacters ();
1674 AssessStartElementSchemaValidity ();
1677 if (reader.IsEmptyElement)
1678 goto case XmlNodeType.EndElement;
1680 shouldValidateCharacters = true;
1682 case XmlNodeType.EndElement:
1683 if (reader.Depth == skipValidationDepth)
1684 skipValidationDepth = -1;
1685 else if (skipValidationDepth < 0 || reader.Depth <= skipValidationDepth)
1686 AssessEndElementSchemaValidity ();
1688 if (checkKeyConstraints)
1689 elementQNameStack.RemoveAt (elementQNameStack.Count - 1);
1692 case XmlNodeType.CDATA:
1693 case XmlNodeType.SignificantWhitespace:
1694 case XmlNodeType.Text:
1695 // FIXME: does this check make sense?
1696 ComplexType ct = Context.ActualType as ComplexType;
1697 if (ct != null && storedCharacters.Length > 0) {
1698 switch (ct.ContentType) {
1699 case XmlSchemaContentType.ElementOnly:
1700 case XmlSchemaContentType.Empty:
1701 HandleError ("Not allowed character content was found.");
1706 ValidateCharacters ();
1713 public override bool ReadAttributeValue ()
1715 if (currentDefaultAttribute < 0)
1716 return reader.ReadAttributeValue ();
1718 if (this.defaultAttributeConsumed)
1721 defaultAttributeConsumed = true;
1726 public override string ReadInnerXml ()
1728 // MS.NET 1.0 has a serious bug here. It skips validation.
1729 return reader.ReadInnerXml ();
1732 public override string ReadOuterXml ()
1734 // MS.NET 1.0 has a serious bug here. It skips validation.
1735 return reader.ReadOuterXml ();
1739 // XmlReader.ReadString() should call derived this.Read().
1740 public override string ReadString ()
1743 return reader.ReadString ();
1745 return base.ReadString ();
1749 // This class itself does not have this feature.
1750 public override void ResolveEntity ()
1752 reader.ResolveEntity ();
1756 internal class XsdValidationContext
1758 public XsdValidationContext ()
1762 // Some of them might be missing (See the spec section 5.3, and also 3.3.4).
1763 public XsElement Element;
1764 public object XsiType; // xsi:type
1765 internal XsdValidationState State;
1767 // Note that it represents current element's type.
1768 public object ActualType {
1770 if (XsiType != null)
1773 return Element != null ? Element.ElementType : null;
1777 public bool IsInvalid {
1778 get { return State == XsdValidationState.Invalid; }
1781 public object Clone ()
1783 return MemberwiseClone ();
1786 public void EvaluateStartElement (
1787 string localName, string ns)
1789 State = State.EvaluateStartElement (localName, ns);
1792 public bool EvaluateEndElement ()
1794 return State.EvaluateEndElement ();
1797 public void SetElement (XsElement element)