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.
16 // Permission is hereby granted, free of charge, to any person obtaining
17 // a copy of this software and associated documentation files (the
18 // "Software"), to deal in the Software without restriction, including
19 // without limitation the rights to use, copy, modify, merge, publish,
20 // distribute, sublicense, and/or sell copies of the Software, and to
21 // permit persons to whom the Software is furnished to do so, subject to
22 // the following conditions:
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 using System.Collections;
37 using System.Collections.Specialized;
40 using System.Xml.Schema;
43 namespace Mono.Xml.Schema
45 internal class XsdValidatingReader : XmlReader, IXmlLineInfo, IHasXmlSchemaInfo, IHasXmlParserContext, IXmlNamespaceResolver
47 static char [] wsChars = new char [] {' ', '\t', '\n', '\r'};
50 XmlValidatingReader xvReader;
52 IHasXmlSchemaInfo sourceReaderSchemaInfo;
53 IXmlLineInfo readerLineInfo;
54 bool laxElementValidation = true;
55 bool reportNoValidationError;
56 XmlSchemaSet schemas = new XmlSchemaSet ();
57 bool namespaces = true;
59 Hashtable idList = new Hashtable ();
60 ArrayList missingIDReferences = new ArrayList ();
63 ArrayList keyTables = new ArrayList ();
64 ArrayList currentKeyFieldConsumers = new ArrayList ();
66 XsdValidationStateManager stateManager = new XsdValidationStateManager ();
67 XsdValidationContext context = new XsdValidationContext ();
68 XsdValidationState childParticleState;
71 StringBuilder storedCharacters = new StringBuilder ();
72 bool shouldValidateCharacters;
73 int skipValidationDepth = -1;
75 XmlSchemaAttribute [] defaultAttributes = new XmlSchemaAttribute [0];
76 int currentDefaultAttribute = -1;
77 XmlQualifiedName currentQName;
79 ArrayList elementQNameStack = new ArrayList ();
83 int nonDefaultAttributeCount;
84 bool defaultAttributeConsumed;
86 // Validation engine cached object
87 ArrayList defaultAttributesCache = new ArrayList ();
88 ArrayList tmpKeyrefPool = new ArrayList ();
91 public XsdValidatingReader (XmlReader reader)
96 public XsdValidatingReader (XmlReader reader, XmlReader validatingReader)
99 xvReader = validatingReader as XmlValidatingReader;
100 if (xvReader != null) {
101 if (xvReader.ValidationType == ValidationType.None)
102 reportNoValidationError = true;
104 readerLineInfo = reader as IXmlLineInfo;
105 sourceReaderSchemaInfo = reader as IHasXmlSchemaInfo;
108 // Provate Properties
109 private XmlQualifiedName CurrentQName {
111 if (currentQName == null)
112 currentQName = new XmlQualifiedName (LocalName, NamespaceURI);
117 internal ArrayList CurrentKeyFieldConsumers {
118 get { return currentKeyFieldConsumers; }
121 // Public Non-overrides
123 public int XsiNilDepth {
124 get { return xsiNilDepth; }
127 public bool Namespaces {
128 get { return namespaces; }
129 set { namespaces = value; }
132 public XmlReader Reader {
133 get { return reader; }
136 // This is required to resolve xsi:schemaLocation
137 public XmlResolver XmlResolver {
143 // This should be changed before the first Read() call.
144 public XmlSchemaSet Schemas {
145 get { return schemas; }
147 if (ReadState != ReadState.Initial)
148 throw new InvalidOperationException ("Schemas must be set before the first call to Read().");
153 public object SchemaType {
155 if (ReadState != ReadState.Interactive)
159 case XmlNodeType.Element:
160 if (context.ActualType != null)
161 return context.ActualType;
162 else if (context.Element != null)
163 return context.Element.ElementType;
165 return SourceReaderSchemaType;
166 case XmlNodeType.Attribute:
167 XmlSchemaComplexType ct = context.ActualType as XmlSchemaComplexType;
169 XmlSchemaAttribute attdef = ct.AttributeUses [CurrentQName] as XmlSchemaAttribute;
171 return attdef.AttributeType;
173 return SourceReaderSchemaType;
175 return SourceReaderSchemaType;
180 private object SourceReaderSchemaType {
181 get { return this.sourceReaderSchemaInfo != null ? sourceReaderSchemaInfo.SchemaType : null; }
184 // This property is never used in Mono.
185 public ValidationType ValidationType {
187 if (reportNoValidationError)
188 return ValidationType.None;
190 return ValidationType.Schema;
194 IDictionary IXmlNamespaceResolver.GetNamespacesInScope (XmlNamespaceScope scope)
196 IXmlNamespaceResolver resolver = reader as IXmlNamespaceResolver;
197 if (resolver == null)
198 throw new NotSupportedException ("The input XmlReader does not implement IXmlNamespaceResolver and thus this validating reader cannot collect in-scope namespaces.");
199 return resolver.GetNamespacesInScope (scope);
202 string IXmlNamespaceResolver.LookupPrefix (string ns)
204 return ((IXmlNamespaceResolver) this).LookupPrefix (ns, false);
207 string IXmlNamespaceResolver.LookupPrefix (string ns, bool atomizedNames)
209 IXmlNamespaceResolver resolver = reader as IXmlNamespaceResolver;
210 if (resolver == null)
211 throw new NotSupportedException ("The input XmlReader does not implement IXmlNamespaceResolver and thus this validating reader cannot execute namespace prefix lookup.");
212 return resolver.LookupPrefix (ns, atomizedNames);
215 // It is used only for independent XmlReader use, not for XmlValidatingReader.
216 public object ReadTypedValue ()
218 XmlSchemaDatatype dt = SchemaType as XmlSchemaDatatype;
219 XmlSchemaSimpleType st = SchemaType as XmlSchemaSimpleType;
226 case XmlNodeType.Element:
230 storedCharacters.Length = 0;
235 case XmlNodeType.SignificantWhitespace:
236 case XmlNodeType.Text:
237 case XmlNodeType.CDATA:
238 storedCharacters.Append (Value);
240 case XmlNodeType.Comment:
246 } while (loop && !EOF);
247 return dt.ParseValue (storedCharacters.ToString (), NameTable, ParserContext.NamespaceManager);
248 case XmlNodeType.Attribute:
249 return dt.ParseValue (Value, NameTable, ParserContext.NamespaceManager);
254 public ValidationEventHandler ValidationEventHandler;
256 // Public Overrided Properties
258 public override int AttributeCount {
260 return nonDefaultAttributeCount + defaultAttributes.Length;
264 public override string BaseURI {
265 get { return reader.BaseURI; }
268 // If this class is used to implement XmlValidatingReader,
269 // it should be left to DTDValidatingReader. In other cases,
270 // it depends on the reader's ability.
271 public override bool CanResolveEntity {
272 get { return reader.CanResolveEntity; }
275 public override int Depth {
277 if (currentDefaultAttribute < 0)
279 if (this.defaultAttributeConsumed)
280 return reader.Depth + 2;
281 return reader.Depth + 1;
285 public override bool EOF {
286 get { return reader.EOF; }
289 public override bool HasValue {
291 if (currentDefaultAttribute < 0)
292 return reader.HasValue;
297 public override bool IsDefault {
299 if (currentDefaultAttribute < 0)
300 return reader.IsDefault;
305 public override bool IsEmptyElement {
307 if (currentDefaultAttribute < 0)
308 return reader.IsEmptyElement;
313 public override string this [int i] {
314 get { return GetAttribute (i); }
317 public override string this [string name] {
318 get { return GetAttribute (name); }
321 public override string this [string localName, string ns] {
322 get { return GetAttribute (localName, ns); }
325 int IXmlLineInfo.LineNumber {
326 get { return readerLineInfo != null ? readerLineInfo.LineNumber : 0; }
329 int IXmlLineInfo.LinePosition {
330 get { return readerLineInfo != null ? readerLineInfo.LinePosition : 0; }
333 public override string LocalName {
335 if (currentDefaultAttribute < 0)
336 return reader.LocalName;
337 if (defaultAttributeConsumed)
339 return defaultAttributes [currentDefaultAttribute].QualifiedName.Name;
343 public override string Name {
345 if (currentDefaultAttribute < 0)
347 if (defaultAttributeConsumed)
350 XmlQualifiedName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
351 string prefix = Prefix;
352 if (prefix == String.Empty)
355 return String.Concat (prefix, ":", qname.Name);
359 public override string NamespaceURI {
361 if (currentDefaultAttribute < 0)
362 return reader.NamespaceURI;
363 if (defaultAttributeConsumed)
365 return defaultAttributes [currentDefaultAttribute].QualifiedName.Namespace;
369 public override XmlNameTable NameTable {
370 get { return reader.NameTable; }
373 public override XmlNodeType NodeType {
375 if (currentDefaultAttribute < 0)
376 return reader.NodeType;
377 if (defaultAttributeConsumed)
378 return XmlNodeType.Text;
379 return XmlNodeType.Attribute;
383 public XmlParserContext ParserContext {
384 get { return XmlSchemaUtil.GetParserContext (reader); }
387 public override string Prefix {
389 if (currentDefaultAttribute < 0)
390 return reader.Prefix;
391 if (defaultAttributeConsumed)
393 XmlQualifiedName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
394 string prefix = this.ParserContext.NamespaceManager.LookupPrefix (qname.Namespace, false);
402 public override char QuoteChar {
403 get { return reader.QuoteChar; }
406 public override ReadState ReadState {
407 get { return reader.ReadState; }
410 public override string Value {
412 if (currentDefaultAttribute < 0)
414 string value = defaultAttributes [currentDefaultAttribute].ValidatedDefaultValue;
416 value = defaultAttributes [currentDefaultAttribute].ValidatedFixedValue;
421 XmlQualifiedName qnameXmlLang = new XmlQualifiedName ("lang", XmlNamespaceManager.XmlnsXml);
423 public override string XmlLang {
425 string xmlLang = reader.XmlLang;
428 int idx = this.FindDefaultAttribute ("lang", XmlNamespaceManager.XmlnsXml);
431 xmlLang = defaultAttributes [idx].ValidatedDefaultValue;
433 xmlLang = defaultAttributes [idx].ValidatedFixedValue;
438 public override XmlSpace XmlSpace {
440 XmlSpace space = reader.XmlSpace;
441 if (space != XmlSpace.None)
443 int idx = this.FindDefaultAttribute ("space", XmlNamespaceManager.XmlnsXml);
445 return XmlSpace.None;
446 string spaceSpec = defaultAttributes [idx].ValidatedDefaultValue;
447 if (spaceSpec == null)
448 spaceSpec = defaultAttributes [idx].ValidatedFixedValue;
449 return (XmlSpace) Enum.Parse (typeof (XmlSpace), spaceSpec, false);
455 private XmlQualifiedName QualifyName (string name)
457 return XmlQualifiedName.Parse (name, this);
460 private void HandleError (string error)
462 HandleError (error, null);
465 private void HandleError (string error, Exception innerException)
467 HandleError (error, innerException, false);
470 private void HandleError (string error, Exception innerException, bool isWarning)
472 if (reportNoValidationError) // extra quick check
475 XmlSchemaException schemaException = new XmlSchemaException (error,
476 this, this.BaseURI, null, innerException);
477 HandleError (schemaException, isWarning);
480 private void HandleError (XmlSchemaException schemaException)
482 HandleError (schemaException, false);
485 private void HandleError (XmlSchemaException schemaException, bool isWarning)
487 if (reportNoValidationError)
490 ValidationEventArgs e = new ValidationEventArgs (schemaException,
491 schemaException.Message, isWarning ? XmlSeverityType.Warning : XmlSeverityType.Error);
493 if (this.ValidationEventHandler != null)
494 this.ValidationEventHandler (this, e);
495 else if (xvReader != null)
496 xvReader.OnValidationEvent (this, e);
497 else if (e.Severity == XmlSeverityType.Error)
499 this.xvReader.OnValidationEvent (this, e);
505 private XmlSchemaElement FindElement (string name, string ns)
507 return (XmlSchemaElement) schemas.GlobalElements [new XmlQualifiedName (name, ns)];
510 private XmlSchemaType FindType (XmlQualifiedName qname)
512 return (XmlSchemaType) schemas.GlobalTypes [qname];
515 private void ValidateStartElementParticle ()
517 stateManager.CurrentElement = null;
518 context.ParticleState = context.ParticleState.EvaluateStartElement (reader.LocalName, reader.NamespaceURI);
519 if (context.ParticleState == XsdValidationState.Invalid)
520 HandleError ("Invalid start element: " + reader.NamespaceURI + ":" + reader.LocalName);
522 context.Element = stateManager.CurrentElement;
523 if (context.Element != null)
524 context.SchemaType = context.Element.ElementType;
527 private void ValidateEndElementParticle ()
529 if (childParticleState != null) {
530 if (!childParticleState.EvaluateEndElement ()) {
531 HandleError ("Invalid end element: " + reader.Name);
534 context.PopScope (reader.Depth);
537 // Utility for missing validation completion related to child items.
538 private void ValidateCharacters ()
540 if (xsiNilDepth >= 0 && xsiNilDepth < reader.Depth)
541 HandleError ("Element item appeared, while current element context is nil.");
543 storedCharacters.Append (reader.Value);
546 // Utility for missing validation completion related to child items.
547 private void ValidateEndCharacters ()
549 if (context.ActualType == null)
552 string value = storedCharacters.ToString ();
554 if (storedCharacters.Length == 0) {
555 // 3.3.4 Element Locally Valid (Element) 5.1.2
556 if (context.Element != null) {
557 if (context.Element.ValidatedDefaultValue != null)
558 value = context.Element.ValidatedDefaultValue;
562 XmlSchemaDatatype dt = context.ActualType as XmlSchemaDatatype;
563 XmlSchemaSimpleType st = context.ActualType as XmlSchemaSimpleType;
568 XmlSchemaComplexType ct = context.ActualType as XmlSchemaComplexType;
570 switch (ct.ContentType) {
571 case XmlSchemaContentType.ElementOnly:
572 case XmlSchemaContentType.Empty:
573 if (storedCharacters.Length > 0)
574 HandleError ("Character content not allowed.");
580 // 3.3.4 Element Locally Valid (Element) :: 5.2.2.2. Fixed value constraints
581 if (context.Element != null && context.Element.ValidatedFixedValue != null)
582 if (value != context.Element.ValidatedFixedValue)
583 HandleError ("Fixed value constraint was not satisfied.");
584 AssessStringValid (st, dt, value);
587 // Identity field value
588 while (this.currentKeyFieldConsumers.Count > 0) {
589 XsdKeyEntryField field = this.currentKeyFieldConsumers [0] as XsdKeyEntryField;
590 if (field.Identity != null)
591 HandleError ("Two or more identical field was found. Former value is '" + field.Identity + "' .");
592 object identity = null; // This means empty value
595 identity = dt.ParseValue (value, NameTable, ParserContext.NamespaceManager);
596 } catch (Exception ex) { // FIXME: (wishlist) This is bad manner ;-(
597 HandleError ("Identity value is invalid against its data type " + dt.TokenizedType, ex);
600 if (identity == null)
603 if (!field.SetIdentityField (identity, reader.Depth == xsiNilDepth, dt as XsdAnySimpleType, this))
604 HandleError ("Two or more identical key value was found: '" + value + "' .");
605 this.currentKeyFieldConsumers.RemoveAt (0);
608 shouldValidateCharacters = false;
611 // 3.14.4 String Valid
612 private void AssessStringValid (XmlSchemaSimpleType st,
613 XmlSchemaDatatype dt, string value)
615 XmlSchemaDatatype validatedDatatype = dt;
617 string normalized = validatedDatatype.Normalize (value);
619 XmlSchemaDatatype itemDatatype;
620 XmlSchemaSimpleType itemSimpleType;
621 switch (st.DerivedBy) {
622 case XmlSchemaDerivationMethod.List:
623 XmlSchemaSimpleTypeList listContent = st.Content as XmlSchemaSimpleTypeList;
624 values = normalized.Split (wsChars);
625 itemDatatype = listContent.ValidatedListItemType as XmlSchemaDatatype;
626 itemSimpleType = listContent.ValidatedListItemType as XmlSchemaSimpleType;
627 for (int vi = 0; vi < values.Length; vi++) {
628 string each = values [vi];
629 if (each == String.Empty)
631 // validate against ValidatedItemType
632 if (itemDatatype != null) {
634 itemDatatype.ParseValue (each, NameTable, ParserContext.NamespaceManager);
635 } catch (Exception ex) { // FIXME: (wishlist) better exception handling ;-(
636 HandleError ("List type value contains one or more invalid values.", ex);
641 AssessStringValid (itemSimpleType, itemSimpleType.Datatype, each);
644 case XmlSchemaDerivationMethod.Union:
645 XmlSchemaSimpleTypeUnion union = st.Content as XmlSchemaSimpleTypeUnion;
647 string each = normalized;
648 // validate against ValidatedItemType
650 foreach (object eachType in union.ValidatedTypes) {
651 itemDatatype = eachType as XmlSchemaDatatype;
652 itemSimpleType = eachType as XmlSchemaSimpleType;
653 if (itemDatatype != null) {
655 itemDatatype.ParseValue (each, NameTable, ParserContext.NamespaceManager);
656 } catch (Exception) { // FIXME: (wishlist) better exception handling ;-(
662 AssessStringValid (itemSimpleType, itemSimpleType.Datatype, each);
663 } catch (XmlSchemaException) {
671 HandleError ("Union type value contains one or more invalid values.");
676 case XmlSchemaDerivationMethod.Restriction:
677 XmlSchemaSimpleTypeRestriction str = st.Content as XmlSchemaSimpleTypeRestriction;
680 /* Don't forget to validate against inherited type's facets
681 * Could we simplify this by assuming that the basetype will also
684 // mmm, will check later.
685 XmlSchemaSimpleType baseType = st.BaseXmlSchemaType as XmlSchemaSimpleType;
686 if (baseType != null) {
687 AssessStringValid(baseType, dt, normalized);
689 if (!str.ValidateValueWithFacets (normalized, NameTable)) {
690 HandleError ("Specified value was invalid against the facets.");
694 validatedDatatype = st.Datatype;
698 if (validatedDatatype != null) {
700 validatedDatatype.ParseValue (value, NameTable, ParserContext.NamespaceManager);
701 } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
702 HandleError ("Invalidly typed data was specified.", ex);
707 private object GetLocalTypeDefinition (string name)
709 object xsiType = null;
710 XmlQualifiedName typeQName = QualifyName (name);
711 if (typeQName == XmlSchemaComplexType.AnyTypeName)
712 xsiType = XmlSchemaComplexType.AnyType;
713 else if (XmlSchemaUtil.IsBuiltInDatatypeName (typeQName))
714 xsiType = XmlSchemaDatatype.FromName (typeQName);
716 xsiType = FindType (typeQName);
720 // It is common to ElementLocallyValid::4 and SchemaValidityAssessment::1.2.1.2.4
721 private void AssessLocalTypeDerivationOK (object xsiType, object baseType, XmlSchemaDerivationMethod flag)
723 XmlSchemaType xsiSchemaType = xsiType as XmlSchemaType;
724 XmlSchemaComplexType baseComplexType = baseType as XmlSchemaComplexType;
725 XmlSchemaComplexType xsiComplexType = xsiSchemaType as XmlSchemaComplexType;
726 if (xsiType != baseType) {
727 // Extracted (not extraneous) check for 3.4.6 TypeDerivationOK.
728 if (baseComplexType != null)
729 flag |= baseComplexType.BlockResolved;
730 if (flag == XmlSchemaDerivationMethod.All) {
731 HandleError ("Prohibited element type substitution.");
733 } else if (xsiSchemaType != null && (flag & xsiSchemaType.DerivedBy) != 0) {
734 HandleError ("Prohibited element type substitution.");
739 if (xsiComplexType != null)
741 xsiComplexType.ValidateTypeDerivationOK (baseType, null, null);
742 } catch (XmlSchemaException ex) {
743 // HandleError ("Locally specified schema complex type derivation failed. " + ex.Message, ex);
747 XmlSchemaSimpleType xsiSimpleType = xsiType as XmlSchemaSimpleType;
748 if (xsiSimpleType != null) {
750 xsiSimpleType.ValidateTypeDerivationOK (baseType, null, null, true);
751 } catch (XmlSchemaException ex) {
752 // HandleError ("Locally specified schema simple type derivation failed. " + ex.Message, ex);
756 else if (xsiType is XmlSchemaDatatype) {
760 HandleError ("Primitive data type cannot be derived type using xsi:type specification.");
764 // Section 3.3.4 of the spec.
765 private void AssessStartElementSchemaValidity ()
767 // If the reader is inside xsi:nil (and failed on validation),
768 // then simply skip its content.
769 if (xsiNilDepth >= 0 && xsiNilDepth < reader.Depth)
770 HandleError ("Element item appeared, while current element context is nil.");
772 context.Load (reader.Depth);
773 if (childParticleState != null) {
774 context.ParticleState = childParticleState;
775 childParticleState = null;
778 // If validation state exists, then first assess particle validity.
779 context.SchemaType = null;
780 if (context.ParticleState != null) {
781 ValidateStartElementParticle ();
784 string xsiNilValue = reader.GetAttribute ("nil", XmlSchema.InstanceNamespace);
785 if (xsiNilValue != null)
786 xsiNilValue = xsiNilValue.Trim (XmlChar.WhitespaceChars);
787 bool isXsiNil = xsiNilValue == "true";
788 if (isXsiNil && this.xsiNilDepth < 0)
789 xsiNilDepth = reader.Depth;
791 // [Schema Validity Assessment (Element) 1.2]
792 // Evaluate "local type definition" from xsi:type.
793 // (See spec 3.3.4 Schema Validity Assessment (Element) 1.2.1.2.3.
794 // Note that Schema Validity Assessment(Element) 1.2 takes
795 // precedence than 1.1 of that.
797 string xsiTypeName = reader.GetAttribute ("type", XmlSchema.InstanceNamespace);
798 if (xsiTypeName != null) {
799 xsiTypeName = xsiTypeName.Trim (XmlChar.WhitespaceChars);
800 object xsiType = GetLocalTypeDefinition (xsiTypeName);
802 HandleError ("The instance type was not found: " + xsiTypeName + " .");
804 XmlSchemaType xsiSchemaType = xsiType as XmlSchemaType;
805 if (xsiSchemaType != null && this.context.Element != null) {
806 XmlSchemaType elemBaseType = context.Element.ElementType as XmlSchemaType;
807 if (elemBaseType != null && (xsiSchemaType.DerivedBy & elemBaseType.FinalResolved) != 0)
808 HandleError ("The instance type is prohibited by the type of the context element.");
809 if (elemBaseType != xsiType && (xsiSchemaType.DerivedBy & this.context.Element.BlockResolved) != 0)
810 HandleError ("The instance type is prohibited by the context element.");
812 XmlSchemaComplexType xsiComplexType = xsiType as XmlSchemaComplexType;
813 if (xsiComplexType != null && xsiComplexType.IsAbstract)
814 HandleError ("The instance type is abstract: " + xsiTypeName + " .");
816 // If current schema type exists, then this xsi:type must be
817 // valid extension of that type. See 1.2.1.2.4.
818 if (context.Element != null) {
819 AssessLocalTypeDerivationOK (xsiType, context.Element.ElementType, context.Element.BlockResolved);
821 AssessStartElementLocallyValidType (xsiType); // 1.2.2:
822 context.LocalTypeDefinition = xsiType;
827 context.LocalTypeDefinition = null;
829 // Create Validation Root, if not exist.
830 // [Schema Validity Assessment (Element) 1.1]
831 if (context.Element == null)
832 context.Element = FindElement (reader.LocalName, reader.NamespaceURI);
833 if (context.Element != null) {
834 if (xsiTypeName == null) {
835 context.SchemaType = context.Element.ElementType;
836 AssessElementLocallyValidElement (context.Element, xsiNilValue); // 1.1.2
840 switch (stateManager.ProcessContents) {
841 case XmlSchemaContentProcessing.Skip:
843 case XmlSchemaContentProcessing.Lax:
845 schema = schemas [reader.NamespaceURI];
846 if (schema != null && !schema.missedSubComponents)
847 HandleError ("Element declaration for " + reader.LocalName + " is missing.");
851 if (xsiTypeName == null &&
852 (schemas.Contains (reader.NamespaceURI) ||
853 !schemas.MissedSubComponents (reader.NamespaceURI)))
854 HandleError ("Element declaration for " + reader.LocalName + " is missing.");
859 if (stateManager.ProcessContents == XmlSchemaContentProcessing.Skip)
860 skipValidationDepth = reader.Depth;
862 // Finally, create child particle state.
863 XmlSchemaComplexType xsComplexType = SchemaType as XmlSchemaComplexType;
864 if (xsComplexType != null)
865 childParticleState = stateManager.Create (xsComplexType.ValidatableParticle);
866 else if (stateManager.ProcessContents == XmlSchemaContentProcessing.Lax)
867 childParticleState = stateManager.Create (XmlSchemaAny.AnyTypeContent);
869 childParticleState = stateManager.Create (XmlSchemaParticle.Empty);
871 AssessStartIdentityConstraints ();
873 context.PushScope (reader.Depth);
876 // 3.3.4 Element Locally Valid (Element)
877 private void AssessElementLocallyValidElement (XmlSchemaElement element, string xsiNilValue)
879 XmlQualifiedName qname = new XmlQualifiedName (reader.LocalName, reader.NamespaceURI);
882 HandleError ("Element declaration is required for " + qname);
884 if (element.ActualIsAbstract)
885 HandleError ("Abstract element declaration was specified for " + qname);
887 if (!element.ActualIsNillable && xsiNilValue != null)
888 HandleError ("This element declaration is not nillable: " + qname);
890 // Note that 3.2.1 xsi:nil constraints are to be validated in
891 else if (xsiNilValue == "true") {
892 // AssessElementSchemaValidity() and ValidateCharacters()
894 if (element.ValidatedFixedValue != null)
895 HandleError ("Schema instance nil was specified, where the element declaration for " + qname + "has fixed value constraints.");
898 string xsiType = reader.GetAttribute ("type", XmlSchema.InstanceNamespace);
899 if (xsiType != null) {
900 context.LocalTypeDefinition = GetLocalTypeDefinition (xsiType);
901 AssessLocalTypeDerivationOK (context.LocalTypeDefinition, element.ElementType, element.BlockResolved);
904 context.LocalTypeDefinition = null;
906 // 5 Not all things cannot be assessed here.
907 // It is common to 5.1 and 5.2
908 if (element.ElementType != null)
909 AssessStartElementLocallyValidType (SchemaType);
911 // 6. should be out from here.
912 // See invokation of AssessStartIdentityConstraints().
914 // 7 is going to be validated in Read() (in case of xmlreader's EOF).
917 // 3.3.4 Element Locally Valid (Type)
918 private void AssessStartElementLocallyValidType (object schemaType)
920 if (schemaType == null) { // 1.
921 HandleError ("Schema type does not exist.");
924 XmlSchemaComplexType cType = schemaType as XmlSchemaComplexType;
925 XmlSchemaSimpleType sType = schemaType as XmlSchemaSimpleType;
928 while (reader.MoveToNextAttribute ()) {
929 if (reader.NamespaceURI == XmlNamespaceManager.XmlnsXmlns)
931 if (reader.NamespaceURI != XmlSchema.InstanceNamespace)
932 HandleError ("Current simple type cannot accept attributes other than schema instance namespace.");
933 switch (reader.LocalName) {
936 case "schemaLocation":
937 case "noNamespaceSchemaLocation":
940 HandleError ("Unknown schema instance namespace attribute: " + reader.LocalName);
944 reader.MoveToElement ();
945 // 3.1.2 and 3.1.3 cannot be assessed here.
946 } else if (cType != null) {
947 if (cType.IsAbstract) { // 2.
948 HandleError ("Target complex type is abstract.");
952 AssessElementLocallyValidComplexType (cType);
956 // 3.4.4 Element Locally Valid (Complex Type)
957 private void AssessElementLocallyValidComplexType (XmlSchemaComplexType cType)
960 if (cType.IsAbstract)
961 HandleError ("Target complex type is abstract.");
963 // 2 (xsi:nil and content prohibition)
964 // See AssessStartElementSchemaValidity() and ValidateCharacters()
966 string elementNs = reader.NamespaceURI;
967 // 3. attribute uses and
969 while (reader.MoveToNextAttribute ()) {
970 if (reader.NamespaceURI == "http://www.w3.org/2000/xmlns/")
972 else if (reader.NamespaceURI == XmlSchema.InstanceNamespace)
974 XmlQualifiedName qname = new XmlQualifiedName (reader.LocalName, reader.NamespaceURI);
975 XmlSchemaObject attMatch = FindAttributeDeclaration (cType, qname, elementNs);
976 if (attMatch == null)
977 HandleError ("Attribute declaration was not found for " + qname);
979 XmlSchemaAttribute attdecl = attMatch as XmlSchemaAttribute;
980 if (attdecl == null) { // i.e. anyAttribute
981 XmlSchemaAnyAttribute anyAttrMatch = attMatch as XmlSchemaAnyAttribute;
983 AssessAttributeLocallyValidUse (attdecl);
984 AssessAttributeLocallyValid (attdecl, true);
988 reader.MoveToElement ();
990 // Collect default attributes.
992 foreach (DictionaryEntry entry in cType.AttributeUses) {
993 XmlSchemaAttribute attr = (XmlSchemaAttribute) entry.Value;
994 if (reader [attr.QualifiedName.Name, attr.QualifiedName.Namespace] == null) {
995 if (attr.ValidatedUse == XmlSchemaUse.Required &&
996 attr.ValidatedFixedValue == null)
997 HandleError ("Required attribute " + attr.QualifiedName + " was not found.");
998 else if (attr.ValidatedDefaultValue != null)
999 defaultAttributesCache.Add (attr);
1000 else if (attr.ValidatedFixedValue != null)
1001 defaultAttributesCache.Add (attr);
1004 defaultAttributes = (XmlSchemaAttribute [])
1005 defaultAttributesCache.ToArray (typeof (XmlSchemaAttribute));
1006 context.DefaultAttributes = defaultAttributes;
1007 defaultAttributesCache.Clear ();
1008 // 5. wild IDs was already checked above.
1011 // Spec 3.10.4 Item Valid (Wildcard)
1012 private bool AttributeWildcardItemValid (XmlSchemaAnyAttribute anyAttr, XmlQualifiedName qname)
1014 if (anyAttr.HasValueAny)
1016 if (anyAttr.HasValueOther && (anyAttr.TargetNamespace == "" || reader.NamespaceURI != anyAttr.TargetNamespace))
1018 if (anyAttr.HasValueTargetNamespace && reader.NamespaceURI == anyAttr.TargetNamespace)
1020 if (anyAttr.HasValueLocal && reader.NamespaceURI == "")
1022 for (int i = 0; i < anyAttr.ResolvedNamespaces.Count; i++)
1023 if (anyAttr.ResolvedNamespaces [i] == reader.NamespaceURI)
1028 private XmlSchemaObject FindAttributeDeclaration (
1029 XmlSchemaComplexType cType,
1030 XmlQualifiedName qname,
1033 XmlSchemaObject result = cType.AttributeUses [qname];
1036 if (cType.AttributeWildcard == null)
1039 if (!AttributeWildcardItemValid (cType.AttributeWildcard, qname))
1042 if (cType.AttributeWildcard.ResolvedProcessContents == XmlSchemaContentProcessing.Skip)
1043 return cType.AttributeWildcard;
1044 XmlSchemaAttribute attr = schemas.GlobalAttributes [qname] as XmlSchemaAttribute;
1047 if (cType.AttributeWildcard.ResolvedProcessContents == XmlSchemaContentProcessing.Lax)
1048 return cType.AttributeWildcard;
1053 // 3.2.4 Attribute Locally Valid and 3.4.4 - 5.wildIDs
1054 private void AssessAttributeLocallyValid (XmlSchemaAttribute attr, bool checkWildIDs)
1057 switch (reader.NamespaceURI) {
1058 case XmlNamespaceManager.XmlnsXml:
1059 case XmlNamespaceManager.XmlnsXmlns:
1060 case XmlSchema.InstanceNamespace:
1064 if (attr.AttributeType == null)
1065 HandleError ("Attribute type is missing for " + attr.QualifiedName);
1066 XmlSchemaDatatype dt = attr.AttributeType as XmlSchemaDatatype;
1068 dt = ((XmlSchemaSimpleType) attr.AttributeType).Datatype;
1069 // It is a bit heavy process, so let's omit as long as possible ;-)
1070 if (dt != XmlSchemaSimpleType.AnySimpleType || attr.ValidatedFixedValue != null) {
1071 string normalized = dt.Normalize (reader.Value);
1072 object parsedValue = null;
1074 parsedValue = dt.ParseValue (normalized, reader.NameTable, this.ParserContext.NamespaceManager);
1075 } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
1076 HandleError ("Attribute value is invalid against its data type " + dt.TokenizedType, ex);
1078 if (attr.ValidatedFixedValue != null && attr.ValidatedFixedValue != normalized)
1079 HandleError ("The value of the attribute " + attr.QualifiedName + " does not match with its fixed value.");
1081 AssessEachAttributeIdentityConstraint (dt, normalized, parsedValue);
1085 private void AssessEachAttributeIdentityConstraint (XmlSchemaDatatype dt,
1086 string normalized, object parsedValue)
1088 // Get normalized value and (if required) parsedValue if missing.
1089 switch (dt.TokenizedType) {
1090 case XmlTokenizedType.IDREFS:
1091 if (normalized == null)
1092 normalized = dt.Normalize (reader.Value);
1093 if (parsedValue == null)
1094 parsedValue = dt.ParseValue (normalized, reader.NameTable, ParserContext.NamespaceManager);
1096 case XmlTokenizedType.ID:
1097 case XmlTokenizedType.IDREF:
1098 if (normalized == null)
1099 normalized = dt.Normalize (reader.Value);
1103 // Validate identity constraints.
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 = normalized;
1109 if (idList.Contains (normalized))
1110 HandleError ("Duplicate ID value was found.");
1112 idList.Add (normalized, normalized);
1113 if (missingIDReferences.Contains (normalized))
1114 missingIDReferences.Remove (normalized);
1116 case XmlTokenizedType.IDREF:
1117 if (!idList.Contains (normalized))
1118 missingIDReferences.Add (normalized);
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 (XmlSchemaAttribute 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 if (childParticleState == null)
1141 childParticleState = context.ParticleState;
1142 ValidateEndElementParticle (); // validate against childrens' state.
1144 if (shouldValidateCharacters) {
1145 ValidateEndCharacters ();
1146 shouldValidateCharacters = false;
1149 // 3.3.4 Assess ElementLocallyValidElement 5: value constraints.
1150 // 3.3.4 Assess ElementLocallyValidType 3.1.3. = StringValid(3.14.4)
1151 // => ValidateEndCharacters().
1153 // Reset Identity constraints.
1154 for (int i = 0; i < keyTables.Count; i++) {
1155 XsdKeyTable keyTable = this.keyTables [i] as XsdKeyTable;
1156 if (keyTable.StartDepth == reader.Depth) {
1157 EndIdentityValidation (keyTable);
1159 for (int k = 0; k < keyTable.Entries.Count; k++) {
1160 XsdKeyEntry entry = keyTable.Entries [k] as XsdKeyEntry;
1161 // Remove finished (maybe key not found) entries.
1162 if (entry.StartDepth == reader.Depth) {
1164 keyTable.FinishedEntries.Add (entry);
1165 else if (entry.KeySequence.SourceSchemaIdentity is XmlSchemaKey)
1166 HandleError ("Key sequence is missing.");
1167 keyTable.Entries.RemoveAt (k);
1170 // Pop validated key depth to find two or more fields.
1172 for (int j = 0; j < entry.KeyFields.Count; j++) {
1173 XsdKeyEntryField kf = entry.KeyFields [j];
1174 if (!kf.FieldFound && kf.FieldFoundDepth == reader.Depth) {
1175 kf.FieldFoundDepth = 0;
1176 kf.FieldFoundPath = null;
1183 for (int i = 0; i < keyTables.Count; i++) {
1184 XsdKeyTable keyseq = this.keyTables [i] as XsdKeyTable;
1185 if (keyseq.StartDepth == reader.Depth) {
1186 keyTables.RemoveAt (i);
1191 // Reset xsi:nil, if required.
1192 if (xsiNilDepth == reader.Depth)
1196 // 3.11.4 Identity Constraint Satisfied
1197 private void AssessStartIdentityConstraints ()
1199 tmpKeyrefPool.Clear ();
1200 if (context.Element != null && context.Element.Constraints.Count > 0) {
1201 // (a) Create new key sequences, if required.
1202 for (int i = 0; i < context.Element.Constraints.Count; i++) {
1203 XmlSchemaIdentityConstraint ident = (XmlSchemaIdentityConstraint) context.Element.Constraints [i];
1204 XsdKeyTable seq = CreateNewKeyTable (ident);
1205 if (ident is XmlSchemaKeyref)
1206 tmpKeyrefPool.Add (seq);
1210 // (b) Evaluate current key sequences.
1211 for (int i = 0; i < keyTables.Count; i++) {
1212 XsdKeyTable seq = (XsdKeyTable) keyTables [i];
1213 if (seq.SelectorMatches (this.elementQNameStack, reader) != null) {
1214 // creates and registers new entry.
1215 XsdKeyEntry entry = new XsdKeyEntry (seq, reader);
1216 seq.Entries.Add (entry);
1220 // (c) Evaluate field paths.
1221 for (int i = 0; i < keyTables.Count; i++) {
1222 XsdKeyTable seq = (XsdKeyTable) keyTables [i];
1223 // If possible, create new field entry candidates.
1224 for (int j = 0; j < seq.Entries.Count; j++) {
1225 XsdKeyEntry entry = seq.Entries [j] as XsdKeyEntry;
1227 entry.FieldMatches (this.elementQNameStack, this);
1228 } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
1229 HandleError ("Identity field value is invalid against its data type.", ex);
1235 private XsdKeyTable CreateNewKeyTable (XmlSchemaIdentityConstraint ident)
1237 XsdKeyTable seq = new XsdKeyTable (ident, this);
1238 seq.StartDepth = reader.Depth;
1239 XmlSchemaKeyref keyref = ident as XmlSchemaKeyref;
1240 this.keyTables.Add (seq);
1244 private void EndIdentityValidation (XsdKeyTable seq)
1246 ArrayList errors = new ArrayList ();
1247 for (int i = 0; i < seq.Entries.Count; i++) {
1248 XsdKeyEntry entry = (XsdKeyEntry) seq.Entries [i];
1251 if (seq.SourceSchemaIdentity is XmlSchemaKey)
1252 errors.Add ("line " + entry.SelectorLineNumber + "position " + entry.SelectorLinePosition);
1254 if (errors.Count > 0)
1255 HandleError ("Invalid identity constraints were found. Key was not found. "
1256 + String.Join (", ", errors.ToArray (typeof (string)) as string []));
1259 // Find reference target
1260 XmlSchemaKeyref xsdKeyref = seq.SourceSchemaIdentity as XmlSchemaKeyref;
1261 if (xsdKeyref != null) {
1262 for (int i = this.keyTables.Count - 1; i >= 0; i--) {
1263 XsdKeyTable target = this.keyTables [i] as XsdKeyTable;
1264 if (target.SourceSchemaIdentity == xsdKeyref.Target) {
1265 seq.ReferencedKey = target;
1266 for (int j = 0; j < seq.FinishedEntries.Count; j++) {
1267 XsdKeyEntry entry = (XsdKeyEntry) seq.FinishedEntries [j];
1268 for (int k = 0; k < target.FinishedEntries.Count; k++) {
1269 XsdKeyEntry targetEntry = (XsdKeyEntry) target.FinishedEntries [k];
1270 if (entry.CompareIdentity (targetEntry)) {
1271 entry.KeyRefFound = true;
1278 if (seq.ReferencedKey == null)
1279 HandleError ("Target key was not found.");
1280 for (int i = 0; i < seq.FinishedEntries.Count; i++) {
1281 XsdKeyEntry entry = (XsdKeyEntry) seq.FinishedEntries [i];
1282 if (!entry.KeyRefFound)
1283 errors.Add (" line " + entry.SelectorLineNumber + ", position " + entry.SelectorLinePosition);
1285 if (errors.Count > 0)
1286 HandleError ("Invalid identity constraints were found. Referenced key was not found: "
1287 + String.Join (" / ", errors.ToArray (typeof (string)) as string []));
1291 // Overrided Methods
1293 public override void Close ()
1298 public override string GetAttribute (int i)
1300 switch (reader.NodeType) {
1301 case XmlNodeType.XmlDeclaration:
1302 case XmlNodeType.DocumentType:
1303 return reader.GetAttribute (i);
1306 if (reader.AttributeCount > i)
1307 reader.GetAttribute (i);
1308 int defIdx = i - nonDefaultAttributeCount;
1309 if (i < AttributeCount)
1310 return defaultAttributes [defIdx].DefaultValue;
1312 throw new ArgumentOutOfRangeException ("i", i, "Specified attribute index is out of range.");
1315 public override string GetAttribute (string name)
1317 switch (reader.NodeType) {
1318 case XmlNodeType.XmlDeclaration:
1319 case XmlNodeType.DocumentType:
1320 return reader.GetAttribute (name);
1323 string value = reader.GetAttribute (name);
1327 XmlQualifiedName qname = SplitQName (name);
1328 return GetDefaultAttribute (qname.Name, qname.Namespace);
1331 private XmlQualifiedName SplitQName (string name)
1333 if (!XmlChar.IsName (name))
1334 throw new ArgumentException ("Invalid name was specified.", "name");
1336 Exception ex = null;
1337 XmlQualifiedName qname = XmlSchemaUtil.ToQName (reader, name, out ex);
1339 return XmlQualifiedName.Empty;
1344 public override string GetAttribute (string localName, string ns)
1346 switch (reader.NodeType) {
1347 case XmlNodeType.XmlDeclaration:
1348 case XmlNodeType.DocumentType:
1349 return reader.GetAttribute (localName, ns);
1352 string value = reader.GetAttribute (localName, ns);
1356 return GetDefaultAttribute (localName, ns);
1359 private string GetDefaultAttribute (string localName, string ns)
1361 int idx = this.FindDefaultAttribute (localName, ns);
1364 string value = defaultAttributes [idx].ValidatedDefaultValue;
1366 value = defaultAttributes [idx].ValidatedFixedValue;
1370 private int FindDefaultAttribute (string localName, string ns)
1372 for (int i = 0; i < this.defaultAttributes.Length; i++) {
1373 XmlSchemaAttribute attr = defaultAttributes [i];
1374 if (attr.QualifiedName.Name == localName &&
1375 (ns == null || attr.QualifiedName.Namespace == ns))
1381 bool IXmlLineInfo.HasLineInfo ()
1383 return readerLineInfo != null && readerLineInfo.HasLineInfo ();
1386 public override string LookupNamespace (string prefix)
1388 return reader.LookupNamespace (prefix);
1391 string IXmlNamespaceResolver.LookupNamespace (string prefix, bool atomizedNames)
1393 IXmlNamespaceResolver res = reader as IXmlNamespaceResolver;
1395 return res.LookupNamespace (prefix, atomizedNames);
1397 return reader.LookupNamespace (prefix);
1400 public override void MoveToAttribute (int i)
1402 switch (reader.NodeType) {
1403 case XmlNodeType.XmlDeclaration:
1404 case XmlNodeType.DocumentType:
1405 reader.MoveToAttribute (i);
1409 currentQName = null;
1410 if (i < this.nonDefaultAttributeCount) {
1411 reader.MoveToAttribute (i);
1412 this.currentDefaultAttribute = -1;
1413 this.defaultAttributeConsumed = false;
1416 if (i < AttributeCount) {
1417 this.currentDefaultAttribute = i - nonDefaultAttributeCount;
1418 this.defaultAttributeConsumed = false;
1421 throw new ArgumentOutOfRangeException ("i", i, "Attribute index is out of range.");
1424 public override bool MoveToAttribute (string name)
1426 switch (reader.NodeType) {
1427 case XmlNodeType.XmlDeclaration:
1428 case XmlNodeType.DocumentType:
1429 return reader.MoveToAttribute (name);
1432 currentQName = null;
1433 bool b = reader.MoveToAttribute (name);
1435 this.currentDefaultAttribute = -1;
1436 this.defaultAttributeConsumed = false;
1440 return MoveToDefaultAttribute (name, null);
1443 public override bool MoveToAttribute (string localName, string ns)
1445 switch (reader.NodeType) {
1446 case XmlNodeType.XmlDeclaration:
1447 case XmlNodeType.DocumentType:
1448 return reader.MoveToAttribute (localName, ns);
1451 currentQName = null;
1452 bool b = reader.MoveToAttribute (localName, ns);
1454 this.currentDefaultAttribute = -1;
1455 this.defaultAttributeConsumed = false;
1459 return MoveToDefaultAttribute (localName, ns);
1462 private bool MoveToDefaultAttribute (string localName, string ns)
1464 int idx = this.FindDefaultAttribute (localName, ns);
1467 currentDefaultAttribute = idx;
1468 defaultAttributeConsumed = false;
1472 public override bool MoveToElement ()
1474 currentDefaultAttribute = -1;
1475 defaultAttributeConsumed = false;
1476 currentQName = null;
1477 return reader.MoveToElement ();
1480 public override bool MoveToFirstAttribute ()
1482 switch (reader.NodeType) {
1483 case XmlNodeType.XmlDeclaration:
1484 case XmlNodeType.DocumentType:
1485 return reader.MoveToFirstAttribute ();
1488 currentQName = null;
1489 if (this.nonDefaultAttributeCount > 0) {
1490 bool b = reader.MoveToFirstAttribute ();
1492 currentDefaultAttribute = -1;
1493 defaultAttributeConsumed = false;
1498 if (this.defaultAttributes.Length > 0) {
1499 currentDefaultAttribute = 0;
1500 defaultAttributeConsumed = false;
1507 public override bool MoveToNextAttribute ()
1509 switch (reader.NodeType) {
1510 case XmlNodeType.XmlDeclaration:
1511 case XmlNodeType.DocumentType:
1512 return reader.MoveToNextAttribute ();
1515 currentQName = null;
1516 if (currentDefaultAttribute >= 0) {
1517 if (defaultAttributes.Length == currentDefaultAttribute + 1)
1519 currentDefaultAttribute++;
1520 defaultAttributeConsumed = false;
1524 bool b = reader.MoveToNextAttribute ();
1526 currentDefaultAttribute = -1;
1527 defaultAttributeConsumed = false;
1531 if (defaultAttributes.Length > 0) {
1532 currentDefaultAttribute = 0;
1533 defaultAttributeConsumed = false;
1540 private void ExamineAdditionalSchema ()
1542 XmlSchema schema = null;
1543 string schemaLocation = reader.GetAttribute ("schemaLocation", XmlSchema.InstanceNamespace);
1544 bool schemaAdded = false;
1545 if (schemaLocation != null) {
1546 string [] tmp = null;
1548 schemaLocation = XmlSchemaDatatype.FromName ("token", XmlSchema.Namespace).Normalize (schemaLocation);
1549 tmp = schemaLocation.Split (XmlChar.WhitespaceChars);
1550 } catch (Exception ex) {
1551 HandleError ("Invalid schemaLocation attribute format.", ex, true);
1552 tmp = new string [0];
1554 if (tmp.Length % 2 != 0)
1555 HandleError ("Invalid schemaLocation attribute format.");
1556 for (int i = 0; i < tmp.Length; i += 2) {
1558 XmlTextReader xtr = null;
1560 absUri = new Uri ((this.BaseURI != "" ? new Uri (BaseURI) : null), tmp [i + 1]);
1561 xtr = new XmlTextReader (absUri.ToString ());
1562 schema = XmlSchema.Read (xtr, null);
1563 } catch (Exception) { // FIXME: (wishlist) It is bad manner ;-(
1564 HandleError ("Could not resolve schema location URI: " + absUri, null, true);
1570 if (schema.TargetNamespace == null)
1571 schema.TargetNamespace = tmp [i];
1572 else if (schema.TargetNamespace != tmp [i])
1573 HandleError ("Specified schema has different target namespace.");
1576 if (schema != null) {
1577 if (!schemas.Contains (schema.TargetNamespace)) {
1579 schemas.Add (schema);
1583 string noNsSchemaLocation = reader.GetAttribute ("noNamespaceSchemaLocation", XmlSchema.InstanceNamespace);
1584 if (noNsSchemaLocation != null) {
1586 XmlTextReader xtr = null;
1588 absUri = new Uri ((this.BaseURI != "" ? new Uri (BaseURI) : null), noNsSchemaLocation);
1589 xtr = new XmlTextReader (absUri.ToString ());
1590 schema = XmlSchema.Read (xtr, null);
1591 } catch (Exception) { // FIXME: (wishlist) It is bad manner ;-(
1592 HandleError ("Could not resolve schema location URI: " + absUri, null, true);
1597 if (schema != null && schema.TargetNamespace != null)
1598 HandleError ("Specified schema has different target namespace.");
1600 if (schema != null) {
1601 if (!schemas.Contains (schema.TargetNamespace)) {
1603 schemas.Add (schema);
1606 // FIXME: should call Reprocess()?
1611 public override bool Read ()
1613 nonDefaultAttributeCount = 0;
1614 currentDefaultAttribute = -1;
1615 defaultAttributeConsumed = false;
1616 currentQName = null;
1617 thisElementId = null;
1618 defaultAttributes = new XmlSchemaAttribute [0];
1620 elementQNameStack.RemoveAt (elementQNameStack.Count - 1);
1624 bool result = reader.Read ();
1625 // 3.3.4 ElementLocallyValidElement 7 = Root Valid.
1626 if (!result && missingIDReferences.Count > 0)
1627 HandleError ("There are missing ID references: " +
1629 this.missingIDReferences.ToArray (typeof (string)) as string []));
1631 switch (reader.NodeType) {
1632 case XmlNodeType.XmlDeclaration:
1633 this.nonDefaultAttributeCount = reader.AttributeCount;
1635 case XmlNodeType.Element:
1636 nonDefaultAttributeCount = reader.AttributeCount;
1638 // FIXME: schemaLocation could be specified
1640 if (reader.Depth == 0)
1641 ExamineAdditionalSchema ();
1643 this.elementQNameStack.Add (new XmlQualifiedName (reader.LocalName, reader.NamespaceURI));
1645 // If there is no schema information, then no validation is performed.
1646 if (schemas.Count == 0)
1649 if (skipValidationDepth < 0 || reader.Depth <= skipValidationDepth) {
1650 if (shouldValidateCharacters) {
1651 ValidateEndCharacters ();
1652 shouldValidateCharacters = false;
1654 AssessStartElementSchemaValidity ();
1655 storedCharacters.Length = 0;
1660 if (reader.IsEmptyElement)
1661 goto case XmlNodeType.EndElement;
1663 shouldValidateCharacters = true;
1665 case XmlNodeType.EndElement:
1666 if (reader.Depth == skipValidationDepth) {
1667 skipValidationDepth = -1;
1671 AssessEndElementSchemaValidity ();
1673 storedCharacters.Length = 0;
1674 childParticleState = null;
1678 case XmlNodeType.CDATA:
1679 case XmlNodeType.SignificantWhitespace:
1680 case XmlNodeType.Text:
1681 XmlSchemaComplexType ct = context.ActualType as XmlSchemaComplexType;
1682 if (ct != null && storedCharacters.Length > 0) {
1683 switch (ct.ContentType) {
1684 case XmlSchemaContentType.ElementOnly:
1685 case XmlSchemaContentType.Empty:
1686 HandleError ("Not allowed character content was found.");
1691 ValidateCharacters ();
1698 public override bool ReadAttributeValue ()
1700 if (currentDefaultAttribute < 0)
1701 return reader.ReadAttributeValue ();
1703 if (this.defaultAttributeConsumed)
1706 defaultAttributeConsumed = true;
1711 public override string ReadInnerXml ()
1713 // MS.NET 1.0 has a serious bug here. It skips validation.
1714 return reader.ReadInnerXml ();
1717 public override string ReadOuterXml ()
1719 // MS.NET 1.0 has a serious bug here. It skips validation.
1720 return reader.ReadOuterXml ();
1724 // XmlReader.ReadString() should call derived this.Read().
1725 public override string ReadString ()
1728 return reader.ReadString ();
1730 return base.ReadString ();
1734 // This class itself does not have this feature.
1735 public override void ResolveEntity ()
1737 reader.ResolveEntity ();
1740 internal class XsdValidationContext
1742 Hashtable contextStack;
1744 public XsdValidationContext ()
1746 contextStack = new Hashtable ();
1749 // Some of them might be missing (See the spec section 5.3, and also 3.3.4).
1750 public XmlSchemaElement Element;
1751 public XsdValidationState ParticleState;
1752 public XmlSchemaAttribute [] DefaultAttributes;
1754 // Some of them might be missing (See the spec section 5.3).
1755 public object SchemaType;
1757 public object LocalTypeDefinition;
1759 public object ActualType {
1761 if (LocalTypeDefinition != null)
1762 return LocalTypeDefinition;
1768 public void Clear ()
1772 ParticleState = null;
1773 LocalTypeDefinition = null;
1776 public void PushScope (int depth)
1778 contextStack [depth] = this.MemberwiseClone ();
1781 public void PopScope (int depth)
1784 contextStack.Remove (depth + 1);
1787 public void Load (int depth)
1790 XsdValidationContext restored = (XsdValidationContext) contextStack [depth];
1791 if (restored != null) {
1792 this.Element = restored.Element;
1793 this.ParticleState = restored.ParticleState;
1794 this.SchemaType = restored.SchemaType;
1795 this.LocalTypeDefinition = restored.LocalTypeDefinition;