2 // Mono.Xml.Schema.XsdValidatingReader.cs
5 // Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
7 // (C)2003 Atsushi Enomoto
11 // This class doesn't support set_XmlResolver, since it isn't common to XmlReader interface.
12 // Try to set that of xml reader which is used to construct this object.
15 using System.Collections;
16 using System.Collections.Specialized;
19 using System.Xml.Schema;
22 namespace Mono.Xml.Schema
24 internal class XsdValidatingReader : XmlReader, IXmlLineInfo, IHasXmlSchemaInfo, IHasXmlParserContext
26 static char [] wsChars = new char [] {' ', '\t', '\n', '\r'};
29 XmlValidatingReader xvReader;
31 IHasXmlSchemaInfo sourceReaderSchemaInfo;
32 IXmlLineInfo readerLineInfo;
33 bool laxElementValidation = true;
34 bool reportNoValidationError;
35 XmlSchemaCollection schemas = new XmlSchemaCollection ();
36 bool namespaces = true;
38 Hashtable idList = new Hashtable ();
39 ArrayList missingIDReferences = new ArrayList ();
42 ArrayList keyTables = new ArrayList ();
43 ArrayList currentKeyFieldConsumers = new ArrayList ();
45 XsdValidationStateManager stateManager = new XsdValidationStateManager ();
46 XsdValidationContext context = new XsdValidationContext ();
47 XsdValidationState childParticleState;
50 StringBuilder storedCharacters = new StringBuilder ();
51 bool shouldValidateCharacters;
52 int skipValidationDepth = -1;
54 XmlSchemaAttribute [] defaultAttributes = new XmlSchemaAttribute [0];
55 int currentDefaultAttribute = -1;
56 XmlQualifiedName currentQName;
58 ArrayList elementQNameStack = new ArrayList ();
62 int nonDefaultAttributeCount;
63 bool defaultAttributeConsumed;
65 // Validation engine cached object
66 ArrayList defaultAttributesCache = new ArrayList ();
67 ArrayList tmpKeyrefPool = new ArrayList ();
70 public XsdValidatingReader (XmlReader reader)
75 public XsdValidatingReader (XmlReader reader, XmlReader validatingReader)
78 xvReader = validatingReader as XmlValidatingReader;
79 if (xvReader != null) {
80 if (xvReader.ValidationType == ValidationType.None)
81 reportNoValidationError = true;
83 readerLineInfo = reader as IXmlLineInfo;
84 sourceReaderSchemaInfo = reader as IHasXmlSchemaInfo;
88 private XmlQualifiedName CurrentQName {
90 if (currentQName == null)
91 currentQName = new XmlQualifiedName (LocalName, NamespaceURI);
96 internal ArrayList CurrentKeyFieldConsumers {
97 get { return currentKeyFieldConsumers; }
100 // Public Non-overrides
102 public int XsiNilDepth {
103 get { return xsiNilDepth; }
106 public bool Namespaces {
107 get { return namespaces; }
108 set { namespaces = value; }
111 public XmlReader Reader {
112 get { return reader; }
115 // This is required to resolve xsi:schemaLocation
116 public XmlResolver XmlResolver {
122 // This should be changed before the first Read() call.
123 public XmlSchemaCollection Schemas {
124 get { return schemas; }
127 public object SchemaType {
129 if (ReadState != ReadState.Interactive)
133 case XmlNodeType.Element:
134 if (context.ActualType != null)
135 return context.ActualType;
136 else if (context.Element != null)
137 return context.Element.ElementType;
139 return SourceReaderSchemaType;
140 case XmlNodeType.Attribute:
141 XmlSchemaComplexType ct = context.ActualType as XmlSchemaComplexType;
143 XmlSchemaAttribute attdef = ct.AttributeUses [CurrentQName] as XmlSchemaAttribute;
145 return attdef.AttributeType;
147 return SourceReaderSchemaType;
149 return SourceReaderSchemaType;
154 private object SourceReaderSchemaType {
155 get { return this.sourceReaderSchemaInfo != null ? sourceReaderSchemaInfo.SchemaType : null; }
158 // This property is never used in Mono.
159 public ValidationType ValidationType {
161 if (reportNoValidationError)
162 return ValidationType.None;
164 return ValidationType.Schema;
168 // It is used only for independent XmlReader use, not for XmlValidatingReader.
169 public object ReadTypedValue ()
171 XmlSchemaDatatype dt = SchemaType as XmlSchemaDatatype;
172 XmlSchemaSimpleType st = SchemaType as XmlSchemaSimpleType;
179 case XmlNodeType.Element:
183 storedCharacters.Length = 0;
188 case XmlNodeType.SignificantWhitespace:
189 case XmlNodeType.Text:
190 case XmlNodeType.CDATA:
191 storedCharacters.Append (Value);
193 case XmlNodeType.Comment:
199 } while (loop && !EOF);
200 return dt.ParseValue (storedCharacters.ToString (), NameTable, ParserContext.NamespaceManager);
201 case XmlNodeType.Attribute:
202 return dt.ParseValue (Value, NameTable, ParserContext.NamespaceManager);
208 public ValueType ReadTypedValueType ()
210 XmlSchemaDatatype dt = SchemaType as XmlSchemaDatatype;
211 XmlSchemaSimpleType st = SchemaType as XmlSchemaSimpleType;
218 case XmlNodeType.Element:
222 storedCharacters.Length = 0;
227 case XmlNodeType.SignificantWhitespace:
228 case XmlNodeType.Text:
229 case XmlNodeType.CDATA:
230 storedCharacters.Append (Value);
232 case XmlNodeType.Comment:
238 } while (loop && !EOF);
239 return dt.ParseValueType (storedCharacters.ToString (), NameTable, ParserContext.NamespaceManager);
240 case XmlNodeType.Attribute:
241 return dt.ParseValueType (Value, NameTable, ParserContext.NamespaceManager);
247 public ValidationEventHandler ValidationEventHandler;
249 // Public Overrided Properties
251 public override int AttributeCount {
254 if (NodeType == XmlNodeType.Element)
255 return attributeCount;
259 return reader.AttributeCount;
261 return nonDefaultAttributeCount + defaultAttributes.Length;
265 public override string BaseURI {
266 get { return reader.BaseURI; }
269 // If this class is used to implement XmlValidatingReader,
270 // it should be left to DTDValidatingReader. In other cases,
271 // it depends on the reader's ability.
272 public override bool CanResolveEntity {
273 get { return reader.CanResolveEntity; }
276 public override int Depth {
278 if (currentDefaultAttribute < 0)
280 if (this.defaultAttributeConsumed)
281 return reader.Depth + 2;
282 return reader.Depth + 1;
286 public override bool EOF {
287 get { return reader.EOF; }
290 public override bool HasValue {
292 if (currentDefaultAttribute < 0)
293 return reader.HasValue;
298 public override bool IsDefault {
300 if (currentDefaultAttribute < 0)
301 return reader.IsDefault;
306 public override bool IsEmptyElement {
308 if (currentDefaultAttribute < 0)
309 return reader.IsEmptyElement;
314 public override string this [int i] {
315 get { return GetAttribute (i); }
318 public override string this [string name] {
319 get { return GetAttribute (name); }
322 public override string this [string localName, string ns] {
323 get { return GetAttribute (localName, ns); }
326 int IXmlLineInfo.LineNumber {
327 get { return readerLineInfo != null ? readerLineInfo.LineNumber : 0; }
330 int IXmlLineInfo.LinePosition {
331 get { return readerLineInfo != null ? readerLineInfo.LinePosition : 0; }
334 public override string LocalName {
336 if (currentDefaultAttribute < 0)
337 return reader.LocalName;
338 if (defaultAttributeConsumed)
340 return defaultAttributes [currentDefaultAttribute].QualifiedName.Name;
344 public override string Name {
346 if (currentDefaultAttribute < 0)
348 if (defaultAttributeConsumed)
351 XmlQualifiedName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
352 string prefix = Prefix;
353 if (prefix == String.Empty)
356 return String.Concat (prefix, ":", qname.Name);
360 public override string NamespaceURI {
362 if (currentDefaultAttribute < 0)
363 return reader.NamespaceURI;
364 if (defaultAttributeConsumed)
366 return defaultAttributes [currentDefaultAttribute].QualifiedName.Namespace;
370 public override XmlNameTable NameTable {
371 get { return reader.NameTable; }
374 public override XmlNodeType NodeType {
376 if (currentDefaultAttribute < 0)
377 return reader.NodeType;
378 if (defaultAttributeConsumed)
379 return XmlNodeType.Text;
380 return XmlNodeType.Attribute;
384 public XmlParserContext ParserContext {
385 get { return XmlSchemaUtil.GetParserContext (reader); }
388 public override string Prefix {
390 if (currentDefaultAttribute < 0)
391 return reader.Prefix;
392 if (defaultAttributeConsumed)
394 XmlQualifiedName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
395 string prefix = this.ParserContext.NamespaceManager.LookupPrefix (qname.Namespace, false);
403 public override char QuoteChar {
404 get { return reader.QuoteChar; }
407 public override ReadState ReadState {
408 get { return reader.ReadState; }
411 public override string Value {
413 if (currentDefaultAttribute < 0)
415 string value = defaultAttributes [currentDefaultAttribute].ValidatedDefaultValue;
417 value = defaultAttributes [currentDefaultAttribute].ValidatedFixedValue;
422 XmlQualifiedName qnameXmlLang = new XmlQualifiedName ("lang", XmlNamespaceManager.XmlnsXml);
424 public override string XmlLang {
426 string xmlLang = reader.XmlLang;
429 int idx = this.FindDefaultAttribute ("lang", XmlNamespaceManager.XmlnsXml);
432 xmlLang = defaultAttributes [idx].ValidatedDefaultValue;
434 xmlLang = defaultAttributes [idx].ValidatedFixedValue;
439 public override XmlSpace XmlSpace {
441 XmlSpace space = reader.XmlSpace;
442 if (space != XmlSpace.None)
444 int idx = this.FindDefaultAttribute ("space", XmlNamespaceManager.XmlnsXml);
446 return XmlSpace.None;
447 string spaceSpec = defaultAttributes [idx].ValidatedDefaultValue;
448 if (spaceSpec == null)
449 spaceSpec = defaultAttributes [idx].ValidatedFixedValue;
450 return (XmlSpace) Enum.Parse (typeof (XmlSpace), spaceSpec, false);
456 private XmlQualifiedName QualifyName (string name)
458 int colonAt = name.IndexOf (':');
460 return new XmlQualifiedName (name, null);
462 return new XmlQualifiedName (name.Substring (colonAt + 1),
463 LookupNamespace (name.Substring (0, colonAt)));
466 private void HandleError (string error)
468 HandleError (error, null);
471 private void HandleError (string error, Exception innerException)
473 HandleError (error, innerException, false);
476 private void HandleError (string error, Exception innerException, bool isWarning)
478 if (reportNoValidationError) // extra quick check
481 XmlSchemaException schemaException = new XmlSchemaException (error,
482 this, this.BaseURI, null, innerException);
483 HandleError (schemaException, isWarning);
486 private void HandleError (XmlSchemaException schemaException)
488 HandleError (schemaException, false);
491 private void HandleError (XmlSchemaException schemaException, bool isWarning)
493 if (reportNoValidationError)
496 ValidationEventArgs e = new ValidationEventArgs (schemaException,
497 schemaException.Message, isWarning ? XmlSeverityType.Warning : XmlSeverityType.Error);
499 if (this.ValidationEventHandler != null)
500 this.ValidationEventHandler (this, e);
501 else if (xvReader != null)
502 xvReader.OnValidationEvent (this, e);
503 else if (e.Severity == XmlSeverityType.Error)
505 this.xvReader.OnValidationEvent (this, e);
511 private XmlSchemaElement FindElement (string name, string ns)
513 foreach (XmlSchema target in schemas) {
514 XmlSchema matches = target.Schemas [ns];
515 if (matches != null) {
516 XmlSchemaElement result = target.Elements [new XmlQualifiedName (name, ns)] as XmlSchemaElement;
524 private XmlSchemaType FindType (XmlQualifiedName qname)
526 foreach (XmlSchema target in schemas) {
527 XmlSchemaType type = target.SchemaTypes [qname] as XmlSchemaType;
534 private void ValidateStartElementParticle ()
536 stateManager.CurrentElement = null;
537 context.ParticleState = context.ParticleState.EvaluateStartElement (reader.LocalName, reader.NamespaceURI);
538 if (context.ParticleState == XsdValidationState.Invalid)
539 HandleError ("Invalid start element: " + reader.NamespaceURI + ":" + reader.LocalName);
541 context.Element = stateManager.CurrentElement;
542 if (context.Element != null)
543 context.SchemaType = context.Element.ElementType;
546 private void ValidateEndElementParticle ()
548 if (childParticleState != null) {
549 if (!childParticleState.EvaluateEndElement ()) {
550 HandleError ("Invalid end element: " + reader.Name);
553 context.PopScope (reader.Depth);
556 // Utility for missing validation completion related to child items.
557 private void ValidateCharacters ()
559 if (xsiNilDepth >= 0 && xsiNilDepth < reader.Depth)
560 HandleError ("Element item appeared, while current element context is nil.");
562 storedCharacters.Append (reader.Value);
565 // Utility for missing validation completion related to child items.
566 private void ValidateEndCharacters ()
568 if (context.ActualType == null)
571 string value = storedCharacters.ToString ();
573 if (storedCharacters.Length == 0) {
574 // 3.3.4 Element Locally Valid (Element) 5.1.2
575 if (context.Element != null) {
576 if (context.Element.ValidatedDefaultValue != null)
577 value = context.Element.ValidatedDefaultValue;
581 XmlSchemaDatatype dt = context.ActualType as XmlSchemaDatatype;
582 XmlSchemaSimpleType st = context.ActualType as XmlSchemaSimpleType;
587 XmlSchemaComplexType ct = context.ActualType as XmlSchemaComplexType;
589 switch (ct.ContentType) {
590 case XmlSchemaContentType.ElementOnly:
591 case XmlSchemaContentType.Empty:
592 if (storedCharacters.Length > 0)
593 HandleError ("Character content not allowed.");
599 // 3.3.4 Element Locally Valid (Element) :: 5.2.2.2. Fixed value constraints
600 if (context.Element != null && context.Element.ValidatedFixedValue != null)
601 if (value != context.Element.ValidatedFixedValue)
602 HandleError ("Fixed value constraint was not satisfied.");
603 AssessStringValid (st, dt, value);
606 // Identity field value
607 while (this.currentKeyFieldConsumers.Count > 0) {
608 XsdKeyEntryField field = this.currentKeyFieldConsumers [0] as XsdKeyEntryField;
609 if (field.Identity != null)
610 HandleError ("Two or more identical field was found. Former value is '" + field.Identity + "' .");
611 object identity = null; // This means empty value
614 identity = dt.ParseValue (value, NameTable, ParserContext.NamespaceManager);
615 } catch (Exception ex) { // FIXME: (wishlist) This is bad manner ;-(
616 HandleError ("Identity value is invalid against its data type " + dt.TokenizedType, ex);
619 if (identity == null)
622 if (!field.SetIdentityField (identity, reader.Depth == xsiNilDepth, dt as XsdAnySimpleType, this))
623 HandleError ("Two or more identical key value was found: '" + value + "' .");
624 this.currentKeyFieldConsumers.RemoveAt (0);
627 shouldValidateCharacters = false;
630 // 3.14.4 String Valid
631 private void AssessStringValid (XmlSchemaSimpleType st,
632 XmlSchemaDatatype dt, string value)
634 XmlSchemaDatatype validatedDatatype = dt;
636 string normalized = validatedDatatype.Normalize (value);
638 XmlSchemaDatatype itemDatatype;
639 XmlSchemaSimpleType itemSimpleType;
640 switch (st.DerivedBy) {
641 case XmlSchemaDerivationMethod.List:
642 XmlSchemaSimpleTypeList listContent = st.Content as XmlSchemaSimpleTypeList;
643 values = normalized.Split (wsChars);
644 itemDatatype = listContent.ValidatedListItemType as XmlSchemaDatatype;
645 itemSimpleType = listContent.ValidatedListItemType as XmlSchemaSimpleType;
646 for (int vi = 0; vi < values.Length; vi++) {
647 string each = values [vi];
648 if (each == String.Empty)
650 // validate against ValidatedItemType
651 if (itemDatatype != null) {
653 itemDatatype.ParseValue (each, NameTable, ParserContext.NamespaceManager);
654 } catch (Exception ex) { // FIXME: (wishlist) better exception handling ;-(
655 HandleError ("List type value contains one or more invalid values.", ex);
660 AssessStringValid (itemSimpleType, itemSimpleType.Datatype, each);
663 case XmlSchemaDerivationMethod.Union:
664 XmlSchemaSimpleTypeUnion union = st.Content as XmlSchemaSimpleTypeUnion;
666 string each = normalized;
667 // validate against ValidatedItemType
669 foreach (object eachType in union.ValidatedTypes) {
670 itemDatatype = eachType as XmlSchemaDatatype;
671 itemSimpleType = eachType as XmlSchemaSimpleType;
672 if (itemDatatype != null) {
674 itemDatatype.ParseValue (each, NameTable, ParserContext.NamespaceManager);
675 } catch (Exception) { // FIXME: (wishlist) better exception handling ;-(
681 AssessStringValid (itemSimpleType, itemSimpleType.Datatype, each);
682 } catch (XmlSchemaException) {
690 HandleError ("Union type value contains one or more invalid values.");
695 case XmlSchemaDerivationMethod.Restriction:
696 XmlSchemaSimpleTypeRestriction str = st.Content as XmlSchemaSimpleTypeRestriction;
699 /* Don't forget to validate against inherited type's facets
700 * Could we simplify this by assuming that the basetype will also
703 // mmm, will check later.
704 XmlSchemaSimpleType baseType = st.BaseXmlSchemaType as XmlSchemaSimpleType;
705 if (baseType != null) {
706 AssessStringValid(baseType, dt, normalized);
708 if (!str.ValidateValueWithFacets (normalized, NameTable)) {
709 HandleError ("Specified value was invalid against the facets.");
713 validatedDatatype = st.Datatype;
717 if (validatedDatatype != null) {
719 validatedDatatype.ParseValue (value, NameTable, ParserContext.NamespaceManager);
720 } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
721 HandleError ("Invalidly typed data was specified.", ex);
726 private object GetLocalTypeDefinition (string name)
728 object xsiType = null;
729 XmlQualifiedName typeQName = QualifyName (name);
730 if (typeQName == XmlSchemaComplexType.AnyTypeName)
731 xsiType = XmlSchemaComplexType.AnyType;
732 else if (XmlSchemaUtil.IsBuiltInDatatypeName (typeQName))
733 xsiType = XmlSchemaDatatype.FromName (typeQName);
735 xsiType = FindType (typeQName);
739 // It is common to ElementLocallyValid::4 and SchemaValidityAssessment::1.2.1.2.4
740 private void AssessLocalTypeDerivationOK (object xsiType, object baseType, XmlSchemaDerivationMethod flag)
742 XmlSchemaType xsiSchemaType = xsiType as XmlSchemaType;
743 XmlSchemaComplexType baseComplexType = baseType as XmlSchemaComplexType;
744 XmlSchemaComplexType xsiComplexType = xsiSchemaType as XmlSchemaComplexType;
745 if (xsiType != baseType) {
746 // Extracted (not extraneous) check for 3.4.6 TypeDerivationOK.
747 if (baseComplexType != null)
748 flag |= baseComplexType.BlockResolved;
749 if (flag == XmlSchemaDerivationMethod.All) {
750 HandleError ("Prohibited element type substitution.");
752 } else if (xsiSchemaType != null && (flag & xsiSchemaType.DerivedBy) != 0) {
753 HandleError ("Prohibited element type substitution.");
758 if (xsiComplexType != null)
760 xsiComplexType.ValidateTypeDerivationOK (baseType, null, null);
761 } catch (XmlSchemaException ex) {
762 // HandleError ("Locally specified schema complex type derivation failed. " + ex.Message, ex);
766 XmlSchemaSimpleType xsiSimpleType = xsiType as XmlSchemaSimpleType;
767 if (xsiSimpleType != null) {
769 xsiSimpleType.ValidateTypeDerivationOK (baseType, null, null, true);
770 } catch (XmlSchemaException ex) {
771 // HandleError ("Locally specified schema simple type derivation failed. " + ex.Message, ex);
775 else if (xsiType is XmlSchemaDatatype) {
779 HandleError ("Primitive data type cannot be derived type using xsi:type specification.");
783 // Section 3.3.4 of the spec.
784 private void AssessStartElementSchemaValidity ()
786 // If the reader is inside xsi:nil (and failed on validation),
787 // then simply skip its content.
788 if (xsiNilDepth >= 0 && xsiNilDepth < reader.Depth)
789 HandleError ("Element item appeared, while current element context is nil.");
791 context.Load (reader.Depth);
792 if (childParticleState != null) {
793 context.ParticleState = childParticleState;
794 childParticleState = null;
797 // If validation state exists, then first assess particle validity.
798 context.SchemaType = null;
799 if (context.ParticleState != null) {
800 ValidateStartElementParticle ();
803 string xsiNilValue = reader.GetAttribute ("nil", XmlSchema.InstanceNamespace);
804 if (xsiNilValue != null)
805 xsiNilValue = xsiNilValue.Trim (XmlChar.WhitespaceChars);
806 bool isXsiNil = xsiNilValue == "true";
807 if (isXsiNil && this.xsiNilDepth < 0)
808 xsiNilDepth = reader.Depth;
810 // [Schema Validity Assessment (Element) 1.2]
811 // Evaluate "local type definition" from xsi:type.
812 // (See spec 3.3.4 Schema Validity Assessment (Element) 1.2.1.2.3.
813 // Note that Schema Validity Assessment(Element) 1.2 takes
814 // precedence than 1.1 of that.
816 string xsiTypeName = reader.GetAttribute ("type", XmlSchema.InstanceNamespace);
817 if (xsiTypeName != null) {
818 xsiTypeName = xsiTypeName.Trim (XmlChar.WhitespaceChars);
819 object xsiType = GetLocalTypeDefinition (xsiTypeName);
821 HandleError ("The instance type was not found: " + xsiTypeName + " .");
823 XmlSchemaType xsiSchemaType = xsiType as XmlSchemaType;
824 if (xsiSchemaType != null && this.context.Element != null) {
825 XmlSchemaType elemBaseType = context.Element.ElementType as XmlSchemaType;
826 if (elemBaseType != null && (xsiSchemaType.DerivedBy & elemBaseType.FinalResolved) != 0)
827 HandleError ("The instance type is prohibited by the type of the context element.");
828 if (elemBaseType != xsiType && (xsiSchemaType.DerivedBy & this.context.Element.BlockResolved) != 0)
829 HandleError ("The instance type is prohibited by the context element.");
831 XmlSchemaComplexType xsiComplexType = xsiType as XmlSchemaComplexType;
832 if (xsiComplexType != null && xsiComplexType.IsAbstract)
833 HandleError ("The instance type is abstract: " + xsiTypeName + " .");
835 // If current schema type exists, then this xsi:type must be
836 // valid extension of that type. See 1.2.1.2.4.
837 if (context.Element != null) {
838 AssessLocalTypeDerivationOK (xsiType, context.Element.ElementType, context.Element.BlockResolved);
840 AssessStartElementLocallyValidType (xsiType); // 1.2.2:
841 context.LocalTypeDefinition = xsiType;
846 context.LocalTypeDefinition = null;
848 // Create Validation Root, if not exist.
849 // [Schema Validity Assessment (Element) 1.1]
850 if (context.Element == null)
851 context.Element = FindElement (reader.LocalName, reader.NamespaceURI);
852 if (context.Element != null) {
853 if (xsiTypeName == null) {
854 context.SchemaType = context.Element.ElementType;
855 AssessElementLocallyValidElement (context.Element, xsiNilValue); // 1.1.2
859 switch (stateManager.ProcessContents) {
860 case XmlSchemaContentProcessing.Skip:
862 case XmlSchemaContentProcessing.Lax:
864 schema = schemas [reader.NamespaceURI];
865 if (schema != null && !schema.missedSubComponents)
866 HandleError ("Element declaration for " + reader.LocalName + " is missing.");
870 schema = schemas [reader.NamespaceURI];
871 if (xsiTypeName == null && (schema == null || !schema.missedSubComponents))
872 HandleError ("Element declaration for " + reader.LocalName + " is missing.");
877 if (stateManager.ProcessContents == XmlSchemaContentProcessing.Skip)
878 skipValidationDepth = reader.Depth;
880 // Finally, create child particle state.
881 XmlSchemaComplexType xsComplexType = SchemaType as XmlSchemaComplexType;
882 if (xsComplexType != null)
883 childParticleState = stateManager.Create (xsComplexType.ValidatableParticle);
884 else if (stateManager.ProcessContents == XmlSchemaContentProcessing.Lax)
885 childParticleState = stateManager.Create (XmlSchemaAny.AnyTypeContent);
887 childParticleState = stateManager.Create (XmlSchemaParticle.Empty);
889 AssessStartIdentityConstraints ();
891 context.PushScope (reader.Depth);
894 // 3.3.4 Element Locally Valid (Element)
895 private void AssessElementLocallyValidElement (XmlSchemaElement 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.LocalTypeDefinition = GetLocalTypeDefinition (xsiType);
919 AssessLocalTypeDerivationOK (context.LocalTypeDefinition, element.ElementType, element.BlockResolved);
922 context.LocalTypeDefinition = 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 XmlSchemaComplexType cType = schemaType as XmlSchemaComplexType;
943 XmlSchemaSimpleType sType = schemaType as XmlSchemaSimpleType;
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 (XmlSchemaComplexType 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 string elementNs = reader.NamespaceURI;
985 // 3. attribute uses and
987 while (reader.MoveToNextAttribute ()) {
988 if (reader.NamespaceURI == "http://www.w3.org/2000/xmlns/")
990 else if (reader.NamespaceURI == XmlSchema.InstanceNamespace)
992 XmlQualifiedName qname = new XmlQualifiedName (reader.LocalName, reader.NamespaceURI);
993 object attMatch = FindAttributeDeclaration (cType, qname, elementNs);
994 if (attMatch == null)
995 HandleError ("Attribute declaration was not found for " + qname);
997 XmlSchemaAttribute attdecl = attMatch as XmlSchemaAttribute;
998 if (attdecl == null) { // i.e. anyAttribute
999 XmlSchemaAnyAttribute anyAttrMatch = attMatch as XmlSchemaAnyAttribute;
1001 AssessAttributeLocallyValidUse (attdecl);
1002 AssessAttributeLocallyValid (attdecl, true);
1006 reader.MoveToElement ();
1008 // Collect default attributes.
1010 foreach (DictionaryEntry entry in cType.AttributeUses) {
1011 XmlSchemaAttribute attr = (XmlSchemaAttribute) entry.Value;
1012 if (reader [attr.QualifiedName.Name, attr.QualifiedName.Namespace] == null) {
1013 if (attr.ValidatedUse == XmlSchemaUse.Required &&
1014 attr.ValidatedFixedValue == null)
1015 HandleError ("Required attribute " + attr.QualifiedName + " was not found.");
1016 else if (attr.ValidatedDefaultValue != null)
1017 defaultAttributesCache.Add (attr);
1018 else if (attr.ValidatedFixedValue != null)
1019 defaultAttributesCache.Add (attr);
1022 defaultAttributes = (XmlSchemaAttribute [])
1023 defaultAttributesCache.ToArray (typeof (XmlSchemaAttribute));
1024 context.DefaultAttributes = defaultAttributes;
1025 defaultAttributesCache.Clear ();
1026 // 5. wild IDs was already checked above.
1029 // Spec 3.10.4 Item Valid (Wildcard)
1030 private bool AttributeWildcardItemValid (XmlSchemaAnyAttribute anyAttr, XmlQualifiedName qname)
1032 if (anyAttr.HasValueAny)
1034 if (anyAttr.HasValueOther && (anyAttr.TargetNamespace == "" || reader.NamespaceURI != anyAttr.TargetNamespace))
1036 if (anyAttr.HasValueTargetNamespace && reader.NamespaceURI == anyAttr.TargetNamespace)
1038 if (anyAttr.HasValueLocal && reader.NamespaceURI == "")
1040 for (int i = 0; i < anyAttr.ResolvedNamespaces.Count; i++)
1041 if (anyAttr.ResolvedNamespaces [i] == reader.NamespaceURI)
1046 private XmlSchemaObject FindAttributeDeclaration (XmlSchemaComplexType cType,
1047 XmlQualifiedName qname, string elementNs)
1049 XmlSchemaObject result = cType.AttributeUses [qname];
1052 if (cType.AttributeWildcard == null)
1055 if (!AttributeWildcardItemValid (cType.AttributeWildcard, qname))
1058 if (cType.AttributeWildcard.ResolvedProcessContents == XmlSchemaContentProcessing.Skip)
1059 return cType.AttributeWildcard;
1060 foreach (XmlSchema schema in schemas) {
1061 foreach (DictionaryEntry entry in schema.Attributes) {
1062 XmlSchemaAttribute attr = (XmlSchemaAttribute) entry.Value;
1063 if (attr.QualifiedName == qname)
1067 if (cType.AttributeWildcard.ResolvedProcessContents == XmlSchemaContentProcessing.Lax)
1068 return cType.AttributeWildcard;
1073 // 3.2.4 Attribute Locally Valid and 3.4.4 - 5.wildIDs
1074 private void AssessAttributeLocallyValid (XmlSchemaAttribute attr, bool checkWildIDs)
1077 switch (reader.NamespaceURI) {
1078 case XmlNamespaceManager.XmlnsXml:
1079 case XmlNamespaceManager.XmlnsXmlns:
1080 case XmlSchema.InstanceNamespace:
1084 if (attr.AttributeType == null)
1085 HandleError ("Attribute type is missing for " + attr.QualifiedName);
1086 XmlSchemaDatatype dt = attr.AttributeType as XmlSchemaDatatype;
1088 dt = ((XmlSchemaSimpleType) attr.AttributeType).Datatype;
1089 // It is a bit heavy process, so let's omit as long as possible ;-)
1090 if (dt != XmlSchemaSimpleType.AnySimpleType || attr.ValidatedFixedValue != null) {
1091 string normalized = dt.Normalize (reader.Value);
1092 object parsedValue = null;
1094 parsedValue = dt.ParseValue (normalized, reader.NameTable, this.ParserContext.NamespaceManager);
1095 } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
1096 HandleError ("Attribute value is invalid against its data type " + dt.TokenizedType, ex);
1098 if (attr.ValidatedFixedValue != null && attr.ValidatedFixedValue != normalized)
1099 HandleError ("The value of the attribute " + attr.QualifiedName + " does not match with its fixed value.");
1101 AssessEachAttributeIdentityConstraint (dt, normalized, parsedValue);
1105 private void AssessEachAttributeIdentityConstraint (XmlSchemaDatatype dt,
1106 string normalized, object parsedValue)
1108 // Get normalized value and (if required) parsedValue if missing.
1109 switch (dt.TokenizedType) {
1110 case XmlTokenizedType.IDREFS:
1111 if (normalized == null)
1112 normalized = dt.Normalize (reader.Value);
1113 if (parsedValue == null)
1114 parsedValue = dt.ParseValue (normalized, reader.NameTable, ParserContext.NamespaceManager);
1116 case XmlTokenizedType.ID:
1117 case XmlTokenizedType.IDREF:
1118 if (normalized == null)
1119 normalized = dt.Normalize (reader.Value);
1123 // Validate identity constraints.
1124 switch (dt.TokenizedType) {
1125 case XmlTokenizedType.ID:
1126 if (thisElementId != null)
1127 HandleError ("ID type attribute was already assigned in the containing element.");
1128 thisElementId = normalized;
1129 if (idList.Contains (normalized))
1130 HandleError ("Duplicate ID value was found.");
1132 idList.Add (normalized, normalized);
1133 if (missingIDReferences.Contains (normalized))
1134 missingIDReferences.Remove (normalized);
1136 case XmlTokenizedType.IDREF:
1137 if (!idList.Contains (normalized))
1138 missingIDReferences.Add (normalized);
1140 case XmlTokenizedType.IDREFS:
1141 string [] idrefs = (string []) parsedValue;
1142 for (int i = 0; i < idrefs.Length; i++) {
1143 string id = idrefs [i];
1144 if (!idList.Contains (id))
1145 missingIDReferences.Add (id);
1151 private void AssessAttributeLocallyValidUse (XmlSchemaAttribute attr)
1153 // This is extra check than spec 3.5.4
1154 if (attr.ValidatedUse == XmlSchemaUse.Prohibited)
1155 HandleError ("Attribute " + attr.QualifiedName + " is prohibited in this context.");
1158 private void AssessEndElementSchemaValidity ()
1160 if (childParticleState == null)
1161 childParticleState = context.ParticleState;
1162 ValidateEndElementParticle (); // validate against childrens' state.
1164 if (shouldValidateCharacters) {
1165 ValidateEndCharacters ();
1166 shouldValidateCharacters = false;
1169 // 3.3.4 Assess ElementLocallyValidElement 5: value constraints.
1170 // 3.3.4 Assess ElementLocallyValidType 3.1.3. = StringValid(3.14.4)
1171 // => ValidateEndCharacters().
1173 // Reset Identity constraints.
1174 for (int i = 0; i < keyTables.Count; i++) {
1175 XsdKeyTable keyTable = this.keyTables [i] as XsdKeyTable;
1176 if (keyTable.StartDepth == reader.Depth) {
1177 EndIdentityValidation (keyTable);
1179 for (int k = 0; k < keyTable.Entries.Count; k++) {
1180 XsdKeyEntry entry = keyTable.Entries [k] as XsdKeyEntry;
1181 // Remove finished (maybe key not found) entries.
1182 if (entry.StartDepth == reader.Depth) {
1184 keyTable.FinishedEntries.Add (entry);
1185 else if (entry.KeySequence.SourceSchemaIdentity is XmlSchemaKey)
1186 HandleError ("Key sequence is missing.");
1187 keyTable.Entries.RemoveAt (k);
1190 // Pop validated key depth to find two or more fields.
1192 for (int j = 0; j < entry.KeyFields.Count; j++) {
1193 XsdKeyEntryField kf = entry.KeyFields [j];
1194 if (!kf.FieldFound && kf.FieldFoundDepth == reader.Depth) {
1195 kf.FieldFoundDepth = 0;
1196 kf.FieldFoundPath = null;
1203 for (int i = 0; i < keyTables.Count; i++) {
1204 XsdKeyTable keyseq = this.keyTables [i] as XsdKeyTable;
1205 if (keyseq.StartDepth == reader.Depth) {
1206 keyTables.RemoveAt (i);
1211 // Reset xsi:nil, if required.
1212 if (xsiNilDepth == reader.Depth)
1216 // 3.11.4 Identity Constraint Satisfied
1217 private void AssessStartIdentityConstraints ()
1219 tmpKeyrefPool.Clear ();
1220 if (context.Element != null && context.Element.Constraints.Count > 0) {
1221 // (a) Create new key sequences, if required.
1222 for (int i = 0; i < context.Element.Constraints.Count; i++) {
1223 XmlSchemaIdentityConstraint ident = (XmlSchemaIdentityConstraint) context.Element.Constraints [i];
1224 XsdKeyTable seq = CreateNewKeyTable (ident);
1225 if (ident is XmlSchemaKeyref)
1226 tmpKeyrefPool.Add (seq);
1230 // (b) Evaluate current key sequences.
1231 for (int i = 0; i < keyTables.Count; i++) {
1232 XsdKeyTable seq = (XsdKeyTable) keyTables [i];
1233 if (seq.SelectorMatches (this.elementQNameStack, reader) != null) {
1234 // creates and registers new entry.
1235 XsdKeyEntry entry = new XsdKeyEntry (seq, reader);
1236 seq.Entries.Add (entry);
1240 // (c) Evaluate field paths.
1241 for (int i = 0; i < keyTables.Count; i++) {
1242 XsdKeyTable seq = (XsdKeyTable) keyTables [i];
1243 // If possible, create new field entry candidates.
1244 for (int j = 0; j < seq.Entries.Count; j++) {
1245 XsdKeyEntry entry = seq.Entries [j] as XsdKeyEntry;
1247 entry.FieldMatches (this.elementQNameStack, this);
1248 } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
1249 HandleError ("Identity field value is invalid against its data type.", ex);
1255 private XsdKeyTable CreateNewKeyTable (XmlSchemaIdentityConstraint ident)
1257 XsdKeyTable seq = new XsdKeyTable (ident, this);
1258 seq.StartDepth = reader.Depth;
1259 XmlSchemaKeyref keyref = ident as XmlSchemaKeyref;
1260 this.keyTables.Add (seq);
1264 private void EndIdentityValidation (XsdKeyTable seq)
1266 ArrayList errors = new ArrayList ();
1267 for (int i = 0; i < seq.Entries.Count; i++) {
1268 XsdKeyEntry entry = (XsdKeyEntry) seq.Entries [i];
1271 if (seq.SourceSchemaIdentity is XmlSchemaKey)
1272 errors.Add ("line " + entry.SelectorLineNumber + "position " + entry.SelectorLinePosition);
1274 if (errors.Count > 0)
1275 HandleError ("Invalid identity constraints were found. Key was not found. "
1276 + String.Join (", ", errors.ToArray (typeof (string)) as string []));
1279 // Find reference target
1280 XmlSchemaKeyref xsdKeyref = seq.SourceSchemaIdentity as XmlSchemaKeyref;
1281 if (xsdKeyref != null) {
1282 for (int i = this.keyTables.Count - 1; i >= 0; i--) {
1283 XsdKeyTable target = this.keyTables [i] as XsdKeyTable;
1284 if (target.SourceSchemaIdentity == xsdKeyref.Target) {
1285 seq.ReferencedKey = target;
1286 for (int j = 0; j < seq.FinishedEntries.Count; j++) {
1287 XsdKeyEntry entry = (XsdKeyEntry) seq.FinishedEntries [j];
1288 for (int k = 0; k < target.FinishedEntries.Count; k++) {
1289 XsdKeyEntry targetEntry = (XsdKeyEntry) target.FinishedEntries [k];
1290 if (entry.CompareIdentity (targetEntry)) {
1291 entry.KeyRefFound = true;
1298 if (seq.ReferencedKey == null)
1299 HandleError ("Target key was not found.");
1300 for (int i = 0; i < seq.FinishedEntries.Count; i++) {
1301 XsdKeyEntry entry = (XsdKeyEntry) seq.FinishedEntries [i];
1302 if (!entry.KeyRefFound)
1303 errors.Add (" line " + entry.SelectorLineNumber + ", position " + entry.SelectorLinePosition);
1305 if (errors.Count > 0)
1306 HandleError ("Invalid identity constraints were found. Referenced key was not found: "
1307 + String.Join (" / ", errors.ToArray (typeof (string)) as string []));
1311 // Overrided Methods
1313 public override void Close ()
1318 public override string GetAttribute (int i)
1320 switch (reader.NodeType) {
1321 case XmlNodeType.XmlDeclaration:
1322 case XmlNodeType.DocumentType:
1323 return reader.GetAttribute (i);
1326 if (reader.AttributeCount > i)
1327 reader.GetAttribute (i);
1328 int defIdx = i - nonDefaultAttributeCount;
1329 if (i < AttributeCount)
1330 return defaultAttributes [defIdx].DefaultValue;
1332 throw new ArgumentOutOfRangeException ("i", i, "Specified attribute index is out of range.");
1335 public override string GetAttribute (string name)
1337 switch (reader.NodeType) {
1338 case XmlNodeType.XmlDeclaration:
1339 case XmlNodeType.DocumentType:
1340 return reader.GetAttribute (name);
1343 string value = reader.GetAttribute (name);
1347 XmlQualifiedName qname = SplitQName (name);
1348 return GetDefaultAttribute (qname.Name, qname.Namespace);
1351 private XmlQualifiedName SplitQName (string name)
1353 if (!XmlChar.IsName (name))
1354 throw new ArgumentException ("Invalid name was specified.", "name");
1356 Exception ex = null;
1357 XmlQualifiedName qname = XmlSchemaUtil.ToQName (reader, name, out ex);
1359 return XmlQualifiedName.Empty;
1364 public override string GetAttribute (string localName, string ns)
1366 switch (reader.NodeType) {
1367 case XmlNodeType.XmlDeclaration:
1368 case XmlNodeType.DocumentType:
1369 return reader.GetAttribute (localName, ns);
1372 string value = reader.GetAttribute (localName, ns);
1376 return GetDefaultAttribute (localName, ns);
1379 private string GetDefaultAttribute (string localName, string ns)
1381 int idx = this.FindDefaultAttribute (localName, ns);
1384 string value = defaultAttributes [idx].ValidatedDefaultValue;
1386 value = defaultAttributes [idx].ValidatedFixedValue;
1390 private int FindDefaultAttribute (string localName, string ns)
1392 for (int i = 0; i < this.defaultAttributes.Length; i++) {
1393 XmlSchemaAttribute attr = defaultAttributes [i];
1394 if (attr.QualifiedName.Name == localName &&
1395 (ns == null || attr.QualifiedName.Namespace == ns))
1401 bool IXmlLineInfo.HasLineInfo ()
1403 return readerLineInfo != null && readerLineInfo.HasLineInfo ();
1406 public override string LookupNamespace (string prefix)
1408 return reader.LookupNamespace (prefix);
1411 public override void MoveToAttribute (int i)
1413 switch (reader.NodeType) {
1414 case XmlNodeType.XmlDeclaration:
1415 case XmlNodeType.DocumentType:
1416 reader.MoveToAttribute (i);
1420 currentQName = null;
1421 if (i < this.nonDefaultAttributeCount) {
1422 reader.MoveToAttribute (i);
1423 this.currentDefaultAttribute = -1;
1424 this.defaultAttributeConsumed = false;
1427 if (i < AttributeCount) {
1428 this.currentDefaultAttribute = i - nonDefaultAttributeCount;
1429 this.defaultAttributeConsumed = false;
1432 throw new ArgumentOutOfRangeException ("i", i, "Attribute index is out of range.");
1435 public override bool MoveToAttribute (string name)
1437 switch (reader.NodeType) {
1438 case XmlNodeType.XmlDeclaration:
1439 case XmlNodeType.DocumentType:
1440 return reader.MoveToAttribute (name);
1443 currentQName = null;
1444 bool b = reader.MoveToAttribute (name);
1446 this.currentDefaultAttribute = -1;
1447 this.defaultAttributeConsumed = false;
1451 return MoveToDefaultAttribute (name, null);
1454 public override bool MoveToAttribute (string localName, string ns)
1456 switch (reader.NodeType) {
1457 case XmlNodeType.XmlDeclaration:
1458 case XmlNodeType.DocumentType:
1459 return reader.MoveToAttribute (localName, ns);
1462 currentQName = null;
1463 bool b = reader.MoveToAttribute (localName, ns);
1465 this.currentDefaultAttribute = -1;
1466 this.defaultAttributeConsumed = false;
1470 return MoveToDefaultAttribute (localName, ns);
1473 private bool MoveToDefaultAttribute (string localName, string ns)
1475 int idx = this.FindDefaultAttribute (localName, ns);
1478 currentDefaultAttribute = idx;
1479 defaultAttributeConsumed = false;
1483 public override bool MoveToElement ()
1485 currentDefaultAttribute = -1;
1486 defaultAttributeConsumed = false;
1487 currentQName = null;
1488 return reader.MoveToElement ();
1491 public override bool MoveToFirstAttribute ()
1493 switch (reader.NodeType) {
1494 case XmlNodeType.XmlDeclaration:
1495 case XmlNodeType.DocumentType:
1496 return reader.MoveToFirstAttribute ();
1499 currentQName = null;
1500 if (this.nonDefaultAttributeCount > 0) {
1501 bool b = reader.MoveToFirstAttribute ();
1503 currentDefaultAttribute = -1;
1504 defaultAttributeConsumed = false;
1509 if (this.defaultAttributes.Length > 0) {
1510 currentDefaultAttribute = 0;
1511 defaultAttributeConsumed = false;
1518 public override bool MoveToNextAttribute ()
1520 switch (reader.NodeType) {
1521 case XmlNodeType.XmlDeclaration:
1522 case XmlNodeType.DocumentType:
1523 return reader.MoveToNextAttribute ();
1526 currentQName = null;
1527 if (currentDefaultAttribute >= 0) {
1528 if (defaultAttributes.Length == currentDefaultAttribute + 1)
1530 currentDefaultAttribute++;
1531 defaultAttributeConsumed = false;
1535 bool b = reader.MoveToNextAttribute ();
1537 currentDefaultAttribute = -1;
1538 defaultAttributeConsumed = false;
1542 if (defaultAttributes.Length > 0) {
1543 currentDefaultAttribute = 0;
1544 defaultAttributeConsumed = false;
1551 private void ExamineAdditionalSchema ()
1553 XmlSchema schema = null;
1554 string schemaLocation = reader.GetAttribute ("schemaLocation", XmlSchema.InstanceNamespace);
1555 if (schemaLocation != null) {
1556 string [] tmp = null;
1558 schemaLocation = XmlSchemaDatatype.FromName ("token").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 (absUri.ToString ());
1572 schema = XmlSchema.Read (xtr, null);
1573 } catch (Exception) { // FIXME: (wishlist) It is bad manner ;-(
1574 HandleError ("Could not resolve schema location URI: " + absUri, null, true);
\r
1580 if (schema.TargetNamespace == null)
1581 schema.TargetNamespace = tmp [i];
1582 else if (schema.TargetNamespace != tmp [i])
1583 HandleError ("Specified schema has different target namespace.");
1586 if (schema != null) {
1588 schemas.Add (schema, resolver);
1589 } catch (XmlSchemaException ex) {
1594 string noNsSchemaLocation = reader.GetAttribute ("noNamespaceSchemaLocation", XmlSchema.InstanceNamespace);
1595 if (noNsSchemaLocation != null) {
1597 XmlTextReader xtr = null;
1599 absUri = new Uri ((this.BaseURI != "" ? new Uri (BaseURI) : null), noNsSchemaLocation);
1600 xtr = new XmlTextReader (absUri.ToString ());
1601 schema = XmlSchema.Read (xtr, null);
1602 } catch (Exception) { // FIXME: (wishlist) It is bad manner ;-(
1603 HandleError ("Could not resolve schema location URI: " + absUri, null, true);
\r
1608 if (schema != null && schema.TargetNamespace != null)
1609 HandleError ("Specified schema has different target namespace.");
1611 if (schema != null) {
1613 schema.Compile (ValidationEventHandler, resolver);
1614 schemas.Add (schema);
1615 } catch (XmlSchemaException ex) {
1621 public override bool Read ()
1623 nonDefaultAttributeCount = 0;
1624 currentDefaultAttribute = -1;
1625 defaultAttributeConsumed = false;
1626 currentQName = null;
1627 thisElementId = null;
1628 defaultAttributes = new XmlSchemaAttribute [0];
1630 elementQNameStack.RemoveAt (elementQNameStack.Count - 1);
1634 bool result = reader.Read ();
1635 // 3.3.4 ElementLocallyValidElement 7 = Root Valid.
1636 if (!result && missingIDReferences.Count > 0)
1637 HandleError ("There are missing ID references: " +
1639 this.missingIDReferences.ToArray (typeof (string)) as string []));
1641 switch (reader.NodeType) {
1642 case XmlNodeType.XmlDeclaration:
1643 this.nonDefaultAttributeCount = reader.AttributeCount;
1645 case XmlNodeType.Element:
1646 nonDefaultAttributeCount = reader.AttributeCount;
1648 if (reader.Depth == 0)
1649 ExamineAdditionalSchema ();
1651 this.elementQNameStack.Add (new XmlQualifiedName (reader.LocalName, reader.NamespaceURI));
1653 // If there is no schema information, then no validation is performed.
1654 if (schemas.Count == 0)
1657 if (skipValidationDepth < 0 || reader.Depth <= skipValidationDepth) {
1658 if (shouldValidateCharacters) {
1659 ValidateEndCharacters ();
1660 shouldValidateCharacters = false;
1662 AssessStartElementSchemaValidity ();
1663 storedCharacters.Length = 0;
1668 if (reader.IsEmptyElement)
1669 goto case XmlNodeType.EndElement;
1671 shouldValidateCharacters = true;
1673 case XmlNodeType.EndElement:
1674 if (reader.Depth == skipValidationDepth) {
1675 skipValidationDepth = -1;
1679 AssessEndElementSchemaValidity ();
1681 storedCharacters.Length = 0;
1682 childParticleState = null;
1686 case XmlNodeType.CDATA:
1687 case XmlNodeType.SignificantWhitespace:
1688 case XmlNodeType.Text:
1689 XmlSchemaComplexType ct = context.ActualType as XmlSchemaComplexType;
1690 if (ct != null && storedCharacters.Length > 0) {
1691 switch (ct.ContentType) {
1692 case XmlSchemaContentType.ElementOnly:
1693 case XmlSchemaContentType.Empty:
1694 HandleError ("Not allowed character content was found.");
1699 ValidateCharacters ();
1706 public override bool ReadAttributeValue ()
1708 if (currentDefaultAttribute < 0)
1709 return reader.ReadAttributeValue ();
1711 if (this.defaultAttributeConsumed)
1714 defaultAttributeConsumed = true;
1719 public override string ReadInnerXml ()
1721 // MS.NET 1.0 has a serious bug here. It skips validation.
1722 return reader.ReadInnerXml ();
1725 public override string ReadOuterXml ()
1727 // MS.NET 1.0 has a serious bug here. It skips validation.
1728 return reader.ReadOuterXml ();
1732 // XmlReader.ReadString() should call derived this.Read().
1733 public override string ReadString ()
1736 return reader.ReadString ();
1738 return base.ReadString ();
1742 // This class itself does not have this feature.
1743 public override void ResolveEntity ()
1745 reader.ResolveEntity ();
1748 internal class XsdValidationContext
1750 Hashtable contextStack;
1752 public XsdValidationContext ()
1754 contextStack = new Hashtable ();
1757 // Some of them might be missing (See the spec section 5.3, and also 3.3.4).
1758 public XmlSchemaElement Element;
1759 public XsdValidationState ParticleState;
1760 public XmlSchemaAttribute [] DefaultAttributes;
1762 // Some of them might be missing (See the spec section 5.3).
1763 public object SchemaType;
1765 public object LocalTypeDefinition;
1767 public object ActualType {
1769 if (LocalTypeDefinition != null)
1770 return LocalTypeDefinition;
1776 public void Clear ()
1780 ParticleState = null;
1781 LocalTypeDefinition = null;
1784 public void PushScope (int depth)
1786 contextStack [depth] = this.MemberwiseClone ();
1789 public void PopScope (int depth)
1792 contextStack.Remove (depth + 1);
1795 public void Load (int depth)
1798 XsdValidationContext restored = (XsdValidationContext) contextStack [depth];
1799 if (restored != null) {
1800 this.Element = restored.Element;
1801 this.ParticleState = restored.ParticleState;
1802 this.SchemaType = restored.SchemaType;
1803 this.LocalTypeDefinition = restored.LocalTypeDefinition;
1809 internal class XsdValidityState
1811 ArrayList currentParticles = new ArrayList ();
1812 ArrayList occured = new ArrayList ();
1813 Hashtable xsAllConsumed = new Hashtable ();
1814 XmlSchemaParticle parciele;
1817 public XsdValidityState (XmlSchemaParticle particle)
1819 this.parciele = particle;
1820 currentParticles.Add (particle);