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
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 XmlSchemaCollection schemas = new XmlSchemaCollection ();
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 XmlSchemaCollection Schemas {
145 get { return schemas; }
148 public object SchemaType {
150 if (ReadState != ReadState.Interactive)
154 case XmlNodeType.Element:
155 if (context.ActualType != null)
156 return context.ActualType;
157 else if (context.Element != null)
158 return context.Element.ElementType;
160 return SourceReaderSchemaType;
161 case XmlNodeType.Attribute:
162 XmlSchemaComplexType ct = context.ActualType as XmlSchemaComplexType;
164 XmlSchemaAttribute attdef = ct.AttributeUses [CurrentQName] as XmlSchemaAttribute;
166 return attdef.AttributeType;
168 return SourceReaderSchemaType;
170 return SourceReaderSchemaType;
175 private object SourceReaderSchemaType {
176 get { return this.sourceReaderSchemaInfo != null ? sourceReaderSchemaInfo.SchemaType : null; }
179 // This property is never used in Mono.
180 public ValidationType ValidationType {
182 if (reportNoValidationError)
183 return ValidationType.None;
185 return ValidationType.Schema;
189 // It is used only for independent XmlReader use, not for XmlValidatingReader.
190 public object ReadTypedValue ()
192 XmlSchemaDatatype dt = SchemaType as XmlSchemaDatatype;
193 XmlSchemaSimpleType st = SchemaType as XmlSchemaSimpleType;
200 case XmlNodeType.Element:
204 storedCharacters.Length = 0;
209 case XmlNodeType.SignificantWhitespace:
210 case XmlNodeType.Text:
211 case XmlNodeType.CDATA:
212 storedCharacters.Append (Value);
214 case XmlNodeType.Comment:
220 } while (loop && !EOF);
221 return dt.ParseValue (storedCharacters.ToString (), NameTable, ParserContext.NamespaceManager);
222 case XmlNodeType.Attribute:
223 return dt.ParseValue (Value, NameTable, ParserContext.NamespaceManager);
229 public ValueType ReadTypedValueType ()
231 XmlSchemaDatatype dt = SchemaType as XmlSchemaDatatype;
232 XmlSchemaSimpleType st = SchemaType as XmlSchemaSimpleType;
239 case XmlNodeType.Element:
243 storedCharacters.Length = 0;
248 case XmlNodeType.SignificantWhitespace:
249 case XmlNodeType.Text:
250 case XmlNodeType.CDATA:
251 storedCharacters.Append (Value);
253 case XmlNodeType.Comment:
259 } while (loop && !EOF);
260 return dt.ParseValueType (storedCharacters.ToString (), NameTable, ParserContext.NamespaceManager);
261 case XmlNodeType.Attribute:
262 return dt.ParseValueType (Value, NameTable, ParserContext.NamespaceManager);
268 public ValidationEventHandler ValidationEventHandler;
270 // Public Overrided Properties
272 public override int AttributeCount {
275 if (NodeType == XmlNodeType.Element)
276 return attributeCount;
280 return reader.AttributeCount;
282 return nonDefaultAttributeCount + defaultAttributes.Length;
286 public override string BaseURI {
287 get { return reader.BaseURI; }
290 // If this class is used to implement XmlValidatingReader,
291 // it should be left to DTDValidatingReader. In other cases,
292 // it depends on the reader's ability.
293 public override bool CanResolveEntity {
294 get { return reader.CanResolveEntity; }
297 public override int Depth {
299 if (currentDefaultAttribute < 0)
301 if (this.defaultAttributeConsumed)
302 return reader.Depth + 2;
303 return reader.Depth + 1;
307 public override bool EOF {
308 get { return reader.EOF; }
311 public override bool HasValue {
313 if (currentDefaultAttribute < 0)
314 return reader.HasValue;
319 public override bool IsDefault {
321 if (currentDefaultAttribute < 0)
322 return reader.IsDefault;
327 public override bool IsEmptyElement {
329 if (currentDefaultAttribute < 0)
330 return reader.IsEmptyElement;
335 public override string this [int i] {
336 get { return GetAttribute (i); }
339 public override string this [string name] {
340 get { return GetAttribute (name); }
343 public override string this [string localName, string ns] {
344 get { return GetAttribute (localName, ns); }
347 int IXmlLineInfo.LineNumber {
348 get { return readerLineInfo != null ? readerLineInfo.LineNumber : 0; }
351 int IXmlLineInfo.LinePosition {
352 get { return readerLineInfo != null ? readerLineInfo.LinePosition : 0; }
355 public override string LocalName {
357 if (currentDefaultAttribute < 0)
358 return reader.LocalName;
359 if (defaultAttributeConsumed)
361 return defaultAttributes [currentDefaultAttribute].QualifiedName.Name;
365 public override string Name {
367 if (currentDefaultAttribute < 0)
369 if (defaultAttributeConsumed)
372 XmlQualifiedName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
373 string prefix = Prefix;
374 if (prefix == String.Empty)
377 return String.Concat (prefix, ":", qname.Name);
381 public override string NamespaceURI {
383 if (currentDefaultAttribute < 0)
384 return reader.NamespaceURI;
385 if (defaultAttributeConsumed)
387 return defaultAttributes [currentDefaultAttribute].QualifiedName.Namespace;
391 public override XmlNameTable NameTable {
392 get { return reader.NameTable; }
395 public override XmlNodeType NodeType {
397 if (currentDefaultAttribute < 0)
398 return reader.NodeType;
399 if (defaultAttributeConsumed)
400 return XmlNodeType.Text;
401 return XmlNodeType.Attribute;
405 public XmlParserContext ParserContext {
406 get { return XmlSchemaUtil.GetParserContext (reader); }
409 public override string Prefix {
411 if (currentDefaultAttribute < 0)
412 return reader.Prefix;
413 if (defaultAttributeConsumed)
415 XmlQualifiedName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
416 string prefix = this.ParserContext.NamespaceManager.LookupPrefix (qname.Namespace, false);
424 public override char QuoteChar {
425 get { return reader.QuoteChar; }
428 public override ReadState ReadState {
429 get { return reader.ReadState; }
432 public override string Value {
434 if (currentDefaultAttribute < 0)
436 string value = defaultAttributes [currentDefaultAttribute].ValidatedDefaultValue;
438 value = defaultAttributes [currentDefaultAttribute].ValidatedFixedValue;
443 XmlQualifiedName qnameXmlLang = new XmlQualifiedName ("lang", XmlNamespaceManager.XmlnsXml);
445 public override string XmlLang {
447 string xmlLang = reader.XmlLang;
450 int idx = this.FindDefaultAttribute ("lang", XmlNamespaceManager.XmlnsXml);
453 xmlLang = defaultAttributes [idx].ValidatedDefaultValue;
455 xmlLang = defaultAttributes [idx].ValidatedFixedValue;
460 public override XmlSpace XmlSpace {
462 XmlSpace space = reader.XmlSpace;
463 if (space != XmlSpace.None)
465 int idx = this.FindDefaultAttribute ("space", XmlNamespaceManager.XmlnsXml);
467 return XmlSpace.None;
468 string spaceSpec = defaultAttributes [idx].ValidatedDefaultValue;
469 if (spaceSpec == null)
470 spaceSpec = defaultAttributes [idx].ValidatedFixedValue;
471 return (XmlSpace) Enum.Parse (typeof (XmlSpace), spaceSpec, false);
477 private XmlQualifiedName QualifyName (string name)
479 int colonAt = name.IndexOf (':');
481 return new XmlQualifiedName (name, null);
483 return new XmlQualifiedName (name.Substring (colonAt + 1),
484 LookupNamespace (name.Substring (0, colonAt)));
487 private void HandleError (string error)
489 HandleError (error, null);
492 private void HandleError (string error, Exception innerException)
494 HandleError (error, innerException, false);
497 private void HandleError (string error, Exception innerException, bool isWarning)
499 if (reportNoValidationError) // extra quick check
502 XmlSchemaException schemaException = new XmlSchemaException (error,
503 this, this.BaseURI, null, innerException);
504 HandleError (schemaException, isWarning);
507 private void HandleError (XmlSchemaException schemaException)
509 HandleError (schemaException, false);
512 private void HandleError (XmlSchemaException schemaException, bool isWarning)
514 if (reportNoValidationError)
517 ValidationEventArgs e = new ValidationEventArgs (schemaException,
518 schemaException.Message, isWarning ? XmlSeverityType.Warning : XmlSeverityType.Error);
520 if (this.ValidationEventHandler != null)
521 this.ValidationEventHandler (this, e);
522 else if (xvReader != null)
523 xvReader.OnValidationEvent (this, e);
524 else if (e.Severity == XmlSeverityType.Error)
526 this.xvReader.OnValidationEvent (this, e);
532 private XmlSchemaElement FindElement (string name, string ns)
534 foreach (XmlSchema target in schemas) {
535 XmlSchema matches = target.Schemas [ns];
536 if (matches != null) {
537 XmlSchemaElement result = target.Elements [new XmlQualifiedName (name, ns)] as XmlSchemaElement;
545 private XmlSchemaType FindType (XmlQualifiedName qname)
547 foreach (XmlSchema target in schemas) {
548 XmlSchemaType type = target.SchemaTypes [qname] as XmlSchemaType;
555 private void ValidateStartElementParticle ()
557 stateManager.CurrentElement = null;
558 context.ParticleState = context.ParticleState.EvaluateStartElement (reader.LocalName, reader.NamespaceURI);
559 if (context.ParticleState == XsdValidationState.Invalid)
560 HandleError ("Invalid start element: " + reader.NamespaceURI + ":" + reader.LocalName);
562 context.Element = stateManager.CurrentElement;
563 if (context.Element != null)
564 context.SchemaType = context.Element.ElementType;
567 private void ValidateEndElementParticle ()
569 if (childParticleState != null) {
570 if (!childParticleState.EvaluateEndElement ()) {
571 HandleError ("Invalid end element: " + reader.Name);
574 context.PopScope (reader.Depth);
577 // Utility for missing validation completion related to child items.
578 private void ValidateCharacters ()
580 if (xsiNilDepth >= 0 && xsiNilDepth < reader.Depth)
581 HandleError ("Element item appeared, while current element context is nil.");
583 storedCharacters.Append (reader.Value);
586 // Utility for missing validation completion related to child items.
587 private void ValidateEndCharacters ()
589 if (context.ActualType == null)
592 string value = storedCharacters.ToString ();
594 if (storedCharacters.Length == 0) {
595 // 3.3.4 Element Locally Valid (Element) 5.1.2
596 if (context.Element != null) {
597 if (context.Element.ValidatedDefaultValue != null)
598 value = context.Element.ValidatedDefaultValue;
602 XmlSchemaDatatype dt = context.ActualType as XmlSchemaDatatype;
603 XmlSchemaSimpleType st = context.ActualType as XmlSchemaSimpleType;
608 XmlSchemaComplexType ct = context.ActualType as XmlSchemaComplexType;
610 switch (ct.ContentType) {
611 case XmlSchemaContentType.ElementOnly:
612 case XmlSchemaContentType.Empty:
613 if (storedCharacters.Length > 0)
614 HandleError ("Character content not allowed.");
620 // 3.3.4 Element Locally Valid (Element) :: 5.2.2.2. Fixed value constraints
621 if (context.Element != null && context.Element.ValidatedFixedValue != null)
622 if (value != context.Element.ValidatedFixedValue)
623 HandleError ("Fixed value constraint was not satisfied.");
624 AssessStringValid (st, dt, value);
627 // Identity field value
628 while (this.currentKeyFieldConsumers.Count > 0) {
629 XsdKeyEntryField field = this.currentKeyFieldConsumers [0] as XsdKeyEntryField;
630 if (field.Identity != null)
631 HandleError ("Two or more identical field was found. Former value is '" + field.Identity + "' .");
632 object identity = null; // This means empty value
635 identity = dt.ParseValue (value, NameTable, ParserContext.NamespaceManager);
636 } catch (Exception ex) { // FIXME: (wishlist) This is bad manner ;-(
637 HandleError ("Identity value is invalid against its data type " + dt.TokenizedType, ex);
640 if (identity == null)
643 if (!field.SetIdentityField (identity, reader.Depth == xsiNilDepth, dt as XsdAnySimpleType, this))
644 HandleError ("Two or more identical key value was found: '" + value + "' .");
645 this.currentKeyFieldConsumers.RemoveAt (0);
648 shouldValidateCharacters = false;
651 // 3.14.4 String Valid
652 private void AssessStringValid (XmlSchemaSimpleType st,
653 XmlSchemaDatatype dt, string value)
655 XmlSchemaDatatype validatedDatatype = dt;
657 string normalized = validatedDatatype.Normalize (value);
659 XmlSchemaDatatype itemDatatype;
660 XmlSchemaSimpleType itemSimpleType;
661 switch (st.DerivedBy) {
662 case XmlSchemaDerivationMethod.List:
663 XmlSchemaSimpleTypeList listContent = st.Content as XmlSchemaSimpleTypeList;
664 values = normalized.Split (wsChars);
665 itemDatatype = listContent.ValidatedListItemType as XmlSchemaDatatype;
666 itemSimpleType = listContent.ValidatedListItemType as XmlSchemaSimpleType;
667 for (int vi = 0; vi < values.Length; vi++) {
668 string each = values [vi];
669 if (each == String.Empty)
671 // validate against ValidatedItemType
672 if (itemDatatype != null) {
674 itemDatatype.ParseValue (each, NameTable, ParserContext.NamespaceManager);
675 } catch (Exception ex) { // FIXME: (wishlist) better exception handling ;-(
676 HandleError ("List type value contains one or more invalid values.", ex);
681 AssessStringValid (itemSimpleType, itemSimpleType.Datatype, each);
684 case XmlSchemaDerivationMethod.Union:
685 XmlSchemaSimpleTypeUnion union = st.Content as XmlSchemaSimpleTypeUnion;
687 string each = normalized;
688 // validate against ValidatedItemType
690 foreach (object eachType in union.ValidatedTypes) {
691 itemDatatype = eachType as XmlSchemaDatatype;
692 itemSimpleType = eachType as XmlSchemaSimpleType;
693 if (itemDatatype != null) {
695 itemDatatype.ParseValue (each, NameTable, ParserContext.NamespaceManager);
696 } catch (Exception) { // FIXME: (wishlist) better exception handling ;-(
702 AssessStringValid (itemSimpleType, itemSimpleType.Datatype, each);
703 } catch (XmlSchemaException) {
711 HandleError ("Union type value contains one or more invalid values.");
716 case XmlSchemaDerivationMethod.Restriction:
717 XmlSchemaSimpleTypeRestriction str = st.Content as XmlSchemaSimpleTypeRestriction;
720 /* Don't forget to validate against inherited type's facets
721 * Could we simplify this by assuming that the basetype will also
724 // mmm, will check later.
725 XmlSchemaSimpleType baseType = st.BaseXmlSchemaType as XmlSchemaSimpleType;
726 if (baseType != null) {
727 AssessStringValid(baseType, dt, normalized);
729 if (!str.ValidateValueWithFacets (normalized, NameTable)) {
730 HandleError ("Specified value was invalid against the facets.");
734 validatedDatatype = st.Datatype;
738 if (validatedDatatype != null) {
740 validatedDatatype.ParseValue (value, NameTable, ParserContext.NamespaceManager);
741 } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
742 HandleError ("Invalidly typed data was specified.", ex);
747 private object GetLocalTypeDefinition (string name)
749 object xsiType = null;
750 XmlQualifiedName typeQName = QualifyName (name);
751 if (typeQName == XmlSchemaComplexType.AnyTypeName)
752 xsiType = XmlSchemaComplexType.AnyType;
753 else if (XmlSchemaUtil.IsBuiltInDatatypeName (typeQName))
754 xsiType = XmlSchemaDatatype.FromName (typeQName);
756 xsiType = FindType (typeQName);
760 // It is common to ElementLocallyValid::4 and SchemaValidityAssessment::1.2.1.2.4
761 private void AssessLocalTypeDerivationOK (object xsiType, object baseType, XmlSchemaDerivationMethod flag)
763 XmlSchemaType xsiSchemaType = xsiType as XmlSchemaType;
764 XmlSchemaComplexType baseComplexType = baseType as XmlSchemaComplexType;
765 XmlSchemaComplexType xsiComplexType = xsiSchemaType as XmlSchemaComplexType;
766 if (xsiType != baseType) {
767 // Extracted (not extraneous) check for 3.4.6 TypeDerivationOK.
768 if (baseComplexType != null)
769 flag |= baseComplexType.BlockResolved;
770 if (flag == XmlSchemaDerivationMethod.All) {
771 HandleError ("Prohibited element type substitution.");
773 } else if (xsiSchemaType != null && (flag & xsiSchemaType.DerivedBy) != 0) {
774 HandleError ("Prohibited element type substitution.");
779 if (xsiComplexType != null)
781 xsiComplexType.ValidateTypeDerivationOK (baseType, null, null);
782 } catch (XmlSchemaException ex) {
783 // HandleError ("Locally specified schema complex type derivation failed. " + ex.Message, ex);
787 XmlSchemaSimpleType xsiSimpleType = xsiType as XmlSchemaSimpleType;
788 if (xsiSimpleType != null) {
790 xsiSimpleType.ValidateTypeDerivationOK (baseType, null, null, true);
791 } catch (XmlSchemaException ex) {
792 // HandleError ("Locally specified schema simple type derivation failed. " + ex.Message, ex);
796 else if (xsiType is XmlSchemaDatatype) {
800 HandleError ("Primitive data type cannot be derived type using xsi:type specification.");
804 // Section 3.3.4 of the spec.
805 private void AssessStartElementSchemaValidity ()
807 // If the reader is inside xsi:nil (and failed on validation),
808 // then simply skip its content.
809 if (xsiNilDepth >= 0 && xsiNilDepth < reader.Depth)
810 HandleError ("Element item appeared, while current element context is nil.");
812 context.Load (reader.Depth);
813 if (childParticleState != null) {
814 context.ParticleState = childParticleState;
815 childParticleState = null;
818 // If validation state exists, then first assess particle validity.
819 context.SchemaType = null;
820 if (context.ParticleState != null) {
821 ValidateStartElementParticle ();
824 string xsiNilValue = reader.GetAttribute ("nil", XmlSchema.InstanceNamespace);
825 if (xsiNilValue != null)
826 xsiNilValue = xsiNilValue.Trim (XmlChar.WhitespaceChars);
827 bool isXsiNil = xsiNilValue == "true";
828 if (isXsiNil && this.xsiNilDepth < 0)
829 xsiNilDepth = reader.Depth;
831 // [Schema Validity Assessment (Element) 1.2]
832 // Evaluate "local type definition" from xsi:type.
833 // (See spec 3.3.4 Schema Validity Assessment (Element) 1.2.1.2.3.
834 // Note that Schema Validity Assessment(Element) 1.2 takes
835 // precedence than 1.1 of that.
837 string xsiTypeName = reader.GetAttribute ("type", XmlSchema.InstanceNamespace);
838 if (xsiTypeName != null) {
839 xsiTypeName = xsiTypeName.Trim (XmlChar.WhitespaceChars);
840 object xsiType = GetLocalTypeDefinition (xsiTypeName);
842 HandleError ("The instance type was not found: " + xsiTypeName + " .");
844 XmlSchemaType xsiSchemaType = xsiType as XmlSchemaType;
845 if (xsiSchemaType != null && this.context.Element != null) {
846 XmlSchemaType elemBaseType = context.Element.ElementType as XmlSchemaType;
847 if (elemBaseType != null && (xsiSchemaType.DerivedBy & elemBaseType.FinalResolved) != 0)
848 HandleError ("The instance type is prohibited by the type of the context element.");
849 if (elemBaseType != xsiType && (xsiSchemaType.DerivedBy & this.context.Element.BlockResolved) != 0)
850 HandleError ("The instance type is prohibited by the context element.");
852 XmlSchemaComplexType xsiComplexType = xsiType as XmlSchemaComplexType;
853 if (xsiComplexType != null && xsiComplexType.IsAbstract)
854 HandleError ("The instance type is abstract: " + xsiTypeName + " .");
856 // If current schema type exists, then this xsi:type must be
857 // valid extension of that type. See 1.2.1.2.4.
858 if (context.Element != null) {
859 AssessLocalTypeDerivationOK (xsiType, context.Element.ElementType, context.Element.BlockResolved);
861 AssessStartElementLocallyValidType (xsiType); // 1.2.2:
862 context.LocalTypeDefinition = xsiType;
867 context.LocalTypeDefinition = null;
869 // Create Validation Root, if not exist.
870 // [Schema Validity Assessment (Element) 1.1]
871 if (context.Element == null)
872 context.Element = FindElement (reader.LocalName, reader.NamespaceURI);
873 if (context.Element != null) {
874 if (xsiTypeName == null) {
875 context.SchemaType = context.Element.ElementType;
876 AssessElementLocallyValidElement (context.Element, xsiNilValue); // 1.1.2
880 switch (stateManager.ProcessContents) {
881 case XmlSchemaContentProcessing.Skip:
883 case XmlSchemaContentProcessing.Lax:
885 schema = schemas [reader.NamespaceURI];
886 if (schema != null && !schema.missedSubComponents)
887 HandleError ("Element declaration for " + reader.LocalName + " is missing.");
891 schema = schemas [reader.NamespaceURI];
892 if (xsiTypeName == null && (schema == null || !schema.missedSubComponents))
893 HandleError ("Element declaration for " + reader.LocalName + " is missing.");
898 if (stateManager.ProcessContents == XmlSchemaContentProcessing.Skip)
899 skipValidationDepth = reader.Depth;
901 // Finally, create child particle state.
902 XmlSchemaComplexType xsComplexType = SchemaType as XmlSchemaComplexType;
903 if (xsComplexType != null)
904 childParticleState = stateManager.Create (xsComplexType.ValidatableParticle);
905 else if (stateManager.ProcessContents == XmlSchemaContentProcessing.Lax)
906 childParticleState = stateManager.Create (XmlSchemaAny.AnyTypeContent);
908 childParticleState = stateManager.Create (XmlSchemaParticle.Empty);
910 AssessStartIdentityConstraints ();
912 context.PushScope (reader.Depth);
915 // 3.3.4 Element Locally Valid (Element)
916 private void AssessElementLocallyValidElement (XmlSchemaElement element, string xsiNilValue)
918 XmlQualifiedName qname = new XmlQualifiedName (reader.LocalName, reader.NamespaceURI);
921 HandleError ("Element declaration is required for " + qname);
923 if (element.ActualIsAbstract)
924 HandleError ("Abstract element declaration was specified for " + qname);
926 if (!element.ActualIsNillable && xsiNilValue != null)
927 HandleError ("This element declaration is not nillable: " + qname);
929 // Note that 3.2.1 xsi:nil constraints are to be validated in
930 else if (xsiNilValue == "true") {
931 // AssessElementSchemaValidity() and ValidateCharacters()
933 if (element.ValidatedFixedValue != null)
934 HandleError ("Schema instance nil was specified, where the element declaration for " + qname + "has fixed value constraints.");
937 string xsiType = reader.GetAttribute ("type", XmlSchema.InstanceNamespace);
938 if (xsiType != null) {
939 context.LocalTypeDefinition = GetLocalTypeDefinition (xsiType);
940 AssessLocalTypeDerivationOK (context.LocalTypeDefinition, element.ElementType, element.BlockResolved);
943 context.LocalTypeDefinition = null;
945 // 5 Not all things cannot be assessed here.
946 // It is common to 5.1 and 5.2
947 if (element.ElementType != null)
948 AssessStartElementLocallyValidType (SchemaType);
950 // 6. should be out from here.
951 // See invokation of AssessStartIdentityConstraints().
953 // 7 is going to be validated in Read() (in case of xmlreader's EOF).
956 // 3.3.4 Element Locally Valid (Type)
957 private void AssessStartElementLocallyValidType (object schemaType)
959 if (schemaType == null) { // 1.
960 HandleError ("Schema type does not exist.");
963 XmlSchemaComplexType cType = schemaType as XmlSchemaComplexType;
964 XmlSchemaSimpleType sType = schemaType as XmlSchemaSimpleType;
967 while (reader.MoveToNextAttribute ()) {
968 if (reader.NamespaceURI == XmlNamespaceManager.XmlnsXmlns)
970 if (reader.NamespaceURI != XmlSchema.InstanceNamespace)
971 HandleError ("Current simple type cannot accept attributes other than schema instance namespace.");
972 switch (reader.LocalName) {
975 case "schemaLocation":
976 case "noNamespaceSchemaLocation":
979 HandleError ("Unknown schema instance namespace attribute: " + reader.LocalName);
983 reader.MoveToElement ();
984 // 3.1.2 and 3.1.3 cannot be assessed here.
985 } else if (cType != null) {
986 if (cType.IsAbstract) { // 2.
987 HandleError ("Target complex type is abstract.");
991 AssessElementLocallyValidComplexType (cType);
995 // 3.4.4 Element Locally Valid (Complex Type)
996 private void AssessElementLocallyValidComplexType (XmlSchemaComplexType cType)
999 if (cType.IsAbstract)
1000 HandleError ("Target complex type is abstract.");
1002 // 2 (xsi:nil and content prohibition)
1003 // See AssessStartElementSchemaValidity() and ValidateCharacters()
1005 string elementNs = reader.NamespaceURI;
1006 // 3. attribute uses and
1008 while (reader.MoveToNextAttribute ()) {
1009 if (reader.NamespaceURI == "http://www.w3.org/2000/xmlns/")
1011 else if (reader.NamespaceURI == XmlSchema.InstanceNamespace)
1013 XmlQualifiedName qname = new XmlQualifiedName (reader.LocalName, reader.NamespaceURI);
1014 object attMatch = FindAttributeDeclaration (cType, qname, elementNs);
1015 if (attMatch == null)
1016 HandleError ("Attribute declaration was not found for " + qname);
1018 XmlSchemaAttribute attdecl = attMatch as XmlSchemaAttribute;
1019 if (attdecl == null) { // i.e. anyAttribute
1020 XmlSchemaAnyAttribute anyAttrMatch = attMatch as XmlSchemaAnyAttribute;
1022 AssessAttributeLocallyValidUse (attdecl);
1023 AssessAttributeLocallyValid (attdecl, true);
1027 reader.MoveToElement ();
1029 // Collect default attributes.
1031 foreach (DictionaryEntry entry in cType.AttributeUses) {
1032 XmlSchemaAttribute attr = (XmlSchemaAttribute) entry.Value;
1033 if (reader [attr.QualifiedName.Name, attr.QualifiedName.Namespace] == null) {
1034 if (attr.ValidatedUse == XmlSchemaUse.Required &&
1035 attr.ValidatedFixedValue == null)
1036 HandleError ("Required attribute " + attr.QualifiedName + " was not found.");
1037 else if (attr.ValidatedDefaultValue != null)
1038 defaultAttributesCache.Add (attr);
1039 else if (attr.ValidatedFixedValue != null)
1040 defaultAttributesCache.Add (attr);
1043 defaultAttributes = (XmlSchemaAttribute [])
1044 defaultAttributesCache.ToArray (typeof (XmlSchemaAttribute));
1045 context.DefaultAttributes = defaultAttributes;
1046 defaultAttributesCache.Clear ();
1047 // 5. wild IDs was already checked above.
1050 // Spec 3.10.4 Item Valid (Wildcard)
1051 private bool AttributeWildcardItemValid (XmlSchemaAnyAttribute anyAttr, XmlQualifiedName qname)
1053 if (anyAttr.HasValueAny)
1055 if (anyAttr.HasValueOther && (anyAttr.TargetNamespace == "" || reader.NamespaceURI != anyAttr.TargetNamespace))
1057 if (anyAttr.HasValueTargetNamespace && reader.NamespaceURI == anyAttr.TargetNamespace)
1059 if (anyAttr.HasValueLocal && reader.NamespaceURI == "")
1061 for (int i = 0; i < anyAttr.ResolvedNamespaces.Count; i++)
1062 if (anyAttr.ResolvedNamespaces [i] == reader.NamespaceURI)
1067 private XmlSchemaObject FindAttributeDeclaration (XmlSchemaComplexType cType,
1068 XmlQualifiedName qname, string elementNs)
1070 XmlSchemaObject result = cType.AttributeUses [qname];
1073 if (cType.AttributeWildcard == null)
1076 if (!AttributeWildcardItemValid (cType.AttributeWildcard, qname))
1079 if (cType.AttributeWildcard.ResolvedProcessContents == XmlSchemaContentProcessing.Skip)
1080 return cType.AttributeWildcard;
1081 foreach (XmlSchema schema in schemas) {
1082 foreach (DictionaryEntry entry in schema.Attributes) {
1083 XmlSchemaAttribute attr = (XmlSchemaAttribute) entry.Value;
1084 if (attr.QualifiedName == qname)
1088 if (cType.AttributeWildcard.ResolvedProcessContents == XmlSchemaContentProcessing.Lax)
1089 return cType.AttributeWildcard;
1094 // 3.2.4 Attribute Locally Valid and 3.4.4 - 5.wildIDs
1095 private void AssessAttributeLocallyValid (XmlSchemaAttribute attr, bool checkWildIDs)
1098 switch (reader.NamespaceURI) {
1099 case XmlNamespaceManager.XmlnsXml:
1100 case XmlNamespaceManager.XmlnsXmlns:
1101 case XmlSchema.InstanceNamespace:
1105 if (attr.AttributeType == null)
1106 HandleError ("Attribute type is missing for " + attr.QualifiedName);
1107 XmlSchemaDatatype dt = attr.AttributeType as XmlSchemaDatatype;
1109 dt = ((XmlSchemaSimpleType) attr.AttributeType).Datatype;
1110 // It is a bit heavy process, so let's omit as long as possible ;-)
1111 if (dt != XmlSchemaSimpleType.AnySimpleType || attr.ValidatedFixedValue != null) {
1112 string normalized = dt.Normalize (reader.Value);
1113 object parsedValue = null;
1115 parsedValue = dt.ParseValue (normalized, reader.NameTable, this.ParserContext.NamespaceManager);
1116 } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
1117 HandleError ("Attribute value is invalid against its data type " + dt.TokenizedType, ex);
1119 if (attr.ValidatedFixedValue != null && attr.ValidatedFixedValue != normalized)
1120 HandleError ("The value of the attribute " + attr.QualifiedName + " does not match with its fixed value.");
1122 AssessEachAttributeIdentityConstraint (dt, normalized, parsedValue);
1126 private void AssessEachAttributeIdentityConstraint (XmlSchemaDatatype dt,
1127 string normalized, object parsedValue)
1129 // Get normalized value and (if required) parsedValue if missing.
1130 switch (dt.TokenizedType) {
1131 case XmlTokenizedType.IDREFS:
1132 if (normalized == null)
1133 normalized = dt.Normalize (reader.Value);
1134 if (parsedValue == null)
1135 parsedValue = dt.ParseValue (normalized, reader.NameTable, ParserContext.NamespaceManager);
1137 case XmlTokenizedType.ID:
1138 case XmlTokenizedType.IDREF:
1139 if (normalized == null)
1140 normalized = dt.Normalize (reader.Value);
1144 // Validate identity constraints.
1145 switch (dt.TokenizedType) {
1146 case XmlTokenizedType.ID:
1147 if (thisElementId != null)
1148 HandleError ("ID type attribute was already assigned in the containing element.");
1149 thisElementId = normalized;
1150 if (idList.Contains (normalized))
1151 HandleError ("Duplicate ID value was found.");
1153 idList.Add (normalized, normalized);
1154 if (missingIDReferences.Contains (normalized))
1155 missingIDReferences.Remove (normalized);
1157 case XmlTokenizedType.IDREF:
1158 if (!idList.Contains (normalized))
1159 missingIDReferences.Add (normalized);
1161 case XmlTokenizedType.IDREFS:
1162 string [] idrefs = (string []) parsedValue;
1163 for (int i = 0; i < idrefs.Length; i++) {
1164 string id = idrefs [i];
1165 if (!idList.Contains (id))
1166 missingIDReferences.Add (id);
1172 private void AssessAttributeLocallyValidUse (XmlSchemaAttribute attr)
1174 // This is extra check than spec 3.5.4
1175 if (attr.ValidatedUse == XmlSchemaUse.Prohibited)
1176 HandleError ("Attribute " + attr.QualifiedName + " is prohibited in this context.");
1179 private void AssessEndElementSchemaValidity ()
1181 if (childParticleState == null)
1182 childParticleState = context.ParticleState;
1183 ValidateEndElementParticle (); // validate against childrens' state.
1185 if (shouldValidateCharacters) {
1186 ValidateEndCharacters ();
1187 shouldValidateCharacters = false;
1190 // 3.3.4 Assess ElementLocallyValidElement 5: value constraints.
1191 // 3.3.4 Assess ElementLocallyValidType 3.1.3. = StringValid(3.14.4)
1192 // => ValidateEndCharacters().
1194 // Reset Identity constraints.
1195 for (int i = 0; i < keyTables.Count; i++) {
1196 XsdKeyTable keyTable = this.keyTables [i] as XsdKeyTable;
1197 if (keyTable.StartDepth == reader.Depth) {
1198 EndIdentityValidation (keyTable);
1200 for (int k = 0; k < keyTable.Entries.Count; k++) {
1201 XsdKeyEntry entry = keyTable.Entries [k] as XsdKeyEntry;
1202 // Remove finished (maybe key not found) entries.
1203 if (entry.StartDepth == reader.Depth) {
1205 keyTable.FinishedEntries.Add (entry);
1206 else if (entry.KeySequence.SourceSchemaIdentity is XmlSchemaKey)
1207 HandleError ("Key sequence is missing.");
1208 keyTable.Entries.RemoveAt (k);
1211 // Pop validated key depth to find two or more fields.
1213 for (int j = 0; j < entry.KeyFields.Count; j++) {
1214 XsdKeyEntryField kf = entry.KeyFields [j];
1215 if (!kf.FieldFound && kf.FieldFoundDepth == reader.Depth) {
1216 kf.FieldFoundDepth = 0;
1217 kf.FieldFoundPath = null;
1224 for (int i = 0; i < keyTables.Count; i++) {
1225 XsdKeyTable keyseq = this.keyTables [i] as XsdKeyTable;
1226 if (keyseq.StartDepth == reader.Depth) {
1227 keyTables.RemoveAt (i);
1232 // Reset xsi:nil, if required.
1233 if (xsiNilDepth == reader.Depth)
1237 // 3.11.4 Identity Constraint Satisfied
1238 private void AssessStartIdentityConstraints ()
1240 tmpKeyrefPool.Clear ();
1241 if (context.Element != null && context.Element.Constraints.Count > 0) {
1242 // (a) Create new key sequences, if required.
1243 for (int i = 0; i < context.Element.Constraints.Count; i++) {
1244 XmlSchemaIdentityConstraint ident = (XmlSchemaIdentityConstraint) context.Element.Constraints [i];
1245 XsdKeyTable seq = CreateNewKeyTable (ident);
1246 if (ident is XmlSchemaKeyref)
1247 tmpKeyrefPool.Add (seq);
1251 // (b) Evaluate current key sequences.
1252 for (int i = 0; i < keyTables.Count; i++) {
1253 XsdKeyTable seq = (XsdKeyTable) keyTables [i];
1254 if (seq.SelectorMatches (this.elementQNameStack, reader) != null) {
1255 // creates and registers new entry.
1256 XsdKeyEntry entry = new XsdKeyEntry (seq, reader);
1257 seq.Entries.Add (entry);
1261 // (c) Evaluate field paths.
1262 for (int i = 0; i < keyTables.Count; i++) {
1263 XsdKeyTable seq = (XsdKeyTable) keyTables [i];
1264 // If possible, create new field entry candidates.
1265 for (int j = 0; j < seq.Entries.Count; j++) {
1266 XsdKeyEntry entry = seq.Entries [j] as XsdKeyEntry;
1268 entry.FieldMatches (this.elementQNameStack, this);
1269 } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
1270 HandleError ("Identity field value is invalid against its data type.", ex);
1276 private XsdKeyTable CreateNewKeyTable (XmlSchemaIdentityConstraint ident)
1278 XsdKeyTable seq = new XsdKeyTable (ident, this);
1279 seq.StartDepth = reader.Depth;
1280 XmlSchemaKeyref keyref = ident as XmlSchemaKeyref;
1281 this.keyTables.Add (seq);
1285 private void EndIdentityValidation (XsdKeyTable seq)
1287 ArrayList errors = new ArrayList ();
1288 for (int i = 0; i < seq.Entries.Count; i++) {
1289 XsdKeyEntry entry = (XsdKeyEntry) seq.Entries [i];
1292 if (seq.SourceSchemaIdentity is XmlSchemaKey)
1293 errors.Add ("line " + entry.SelectorLineNumber + "position " + entry.SelectorLinePosition);
1295 if (errors.Count > 0)
1296 HandleError ("Invalid identity constraints were found. Key was not found. "
1297 + String.Join (", ", errors.ToArray (typeof (string)) as string []));
1300 // Find reference target
1301 XmlSchemaKeyref xsdKeyref = seq.SourceSchemaIdentity as XmlSchemaKeyref;
1302 if (xsdKeyref != null) {
1303 for (int i = this.keyTables.Count - 1; i >= 0; i--) {
1304 XsdKeyTable target = this.keyTables [i] as XsdKeyTable;
1305 if (target.SourceSchemaIdentity == xsdKeyref.Target) {
1306 seq.ReferencedKey = target;
1307 for (int j = 0; j < seq.FinishedEntries.Count; j++) {
1308 XsdKeyEntry entry = (XsdKeyEntry) seq.FinishedEntries [j];
1309 for (int k = 0; k < target.FinishedEntries.Count; k++) {
1310 XsdKeyEntry targetEntry = (XsdKeyEntry) target.FinishedEntries [k];
1311 if (entry.CompareIdentity (targetEntry)) {
1312 entry.KeyRefFound = true;
1319 if (seq.ReferencedKey == null)
1320 HandleError ("Target key was not found.");
1321 for (int i = 0; i < seq.FinishedEntries.Count; i++) {
1322 XsdKeyEntry entry = (XsdKeyEntry) seq.FinishedEntries [i];
1323 if (!entry.KeyRefFound)
1324 errors.Add (" line " + entry.SelectorLineNumber + ", position " + entry.SelectorLinePosition);
1326 if (errors.Count > 0)
1327 HandleError ("Invalid identity constraints were found. Referenced key was not found: "
1328 + String.Join (" / ", errors.ToArray (typeof (string)) as string []));
1332 // Overrided Methods
1334 public override void Close ()
1339 public override string GetAttribute (int i)
1341 switch (reader.NodeType) {
1342 case XmlNodeType.XmlDeclaration:
1343 case XmlNodeType.DocumentType:
1344 return reader.GetAttribute (i);
1347 if (reader.AttributeCount > i)
1348 reader.GetAttribute (i);
1349 int defIdx = i - nonDefaultAttributeCount;
1350 if (i < AttributeCount)
1351 return defaultAttributes [defIdx].DefaultValue;
1353 throw new ArgumentOutOfRangeException ("i", i, "Specified attribute index is out of range.");
1356 public override string GetAttribute (string name)
1358 switch (reader.NodeType) {
1359 case XmlNodeType.XmlDeclaration:
1360 case XmlNodeType.DocumentType:
1361 return reader.GetAttribute (name);
1364 string value = reader.GetAttribute (name);
1368 XmlQualifiedName qname = SplitQName (name);
1369 return GetDefaultAttribute (qname.Name, qname.Namespace);
1372 private XmlQualifiedName SplitQName (string name)
1374 if (!XmlChar.IsName (name))
1375 throw new ArgumentException ("Invalid name was specified.", "name");
1377 Exception ex = null;
1378 XmlQualifiedName qname = XmlSchemaUtil.ToQName (reader, name, out ex);
1380 return XmlQualifiedName.Empty;
1385 public override string GetAttribute (string localName, string ns)
1387 switch (reader.NodeType) {
1388 case XmlNodeType.XmlDeclaration:
1389 case XmlNodeType.DocumentType:
1390 return reader.GetAttribute (localName, ns);
1393 string value = reader.GetAttribute (localName, ns);
1397 return GetDefaultAttribute (localName, ns);
1400 private string GetDefaultAttribute (string localName, string ns)
1402 int idx = this.FindDefaultAttribute (localName, ns);
1405 string value = defaultAttributes [idx].ValidatedDefaultValue;
1407 value = defaultAttributes [idx].ValidatedFixedValue;
1411 private int FindDefaultAttribute (string localName, string ns)
1413 for (int i = 0; i < this.defaultAttributes.Length; i++) {
1414 XmlSchemaAttribute attr = defaultAttributes [i];
1415 if (attr.QualifiedName.Name == localName &&
1416 (ns == null || attr.QualifiedName.Namespace == ns))
1422 bool IXmlLineInfo.HasLineInfo ()
1424 return readerLineInfo != null && readerLineInfo.HasLineInfo ();
1427 public override string LookupNamespace (string prefix)
1429 return reader.LookupNamespace (prefix);
1432 public override void MoveToAttribute (int i)
1434 switch (reader.NodeType) {
1435 case XmlNodeType.XmlDeclaration:
1436 case XmlNodeType.DocumentType:
1437 reader.MoveToAttribute (i);
1441 currentQName = null;
1442 if (i < this.nonDefaultAttributeCount) {
1443 reader.MoveToAttribute (i);
1444 this.currentDefaultAttribute = -1;
1445 this.defaultAttributeConsumed = false;
1448 if (i < AttributeCount) {
1449 this.currentDefaultAttribute = i - nonDefaultAttributeCount;
1450 this.defaultAttributeConsumed = false;
1453 throw new ArgumentOutOfRangeException ("i", i, "Attribute index is out of range.");
1456 public override bool MoveToAttribute (string name)
1458 switch (reader.NodeType) {
1459 case XmlNodeType.XmlDeclaration:
1460 case XmlNodeType.DocumentType:
1461 return reader.MoveToAttribute (name);
1464 currentQName = null;
1465 bool b = reader.MoveToAttribute (name);
1467 this.currentDefaultAttribute = -1;
1468 this.defaultAttributeConsumed = false;
1472 return MoveToDefaultAttribute (name, null);
1475 public override bool MoveToAttribute (string localName, string ns)
1477 switch (reader.NodeType) {
1478 case XmlNodeType.XmlDeclaration:
1479 case XmlNodeType.DocumentType:
1480 return reader.MoveToAttribute (localName, ns);
1483 currentQName = null;
1484 bool b = reader.MoveToAttribute (localName, ns);
1486 this.currentDefaultAttribute = -1;
1487 this.defaultAttributeConsumed = false;
1491 return MoveToDefaultAttribute (localName, ns);
1494 private bool MoveToDefaultAttribute (string localName, string ns)
1496 int idx = this.FindDefaultAttribute (localName, ns);
1499 currentDefaultAttribute = idx;
1500 defaultAttributeConsumed = false;
1504 public override bool MoveToElement ()
1506 currentDefaultAttribute = -1;
1507 defaultAttributeConsumed = false;
1508 currentQName = null;
1509 return reader.MoveToElement ();
1512 public override bool MoveToFirstAttribute ()
1514 switch (reader.NodeType) {
1515 case XmlNodeType.XmlDeclaration:
1516 case XmlNodeType.DocumentType:
1517 return reader.MoveToFirstAttribute ();
1520 currentQName = null;
1521 if (this.nonDefaultAttributeCount > 0) {
1522 bool b = reader.MoveToFirstAttribute ();
1524 currentDefaultAttribute = -1;
1525 defaultAttributeConsumed = false;
1530 if (this.defaultAttributes.Length > 0) {
1531 currentDefaultAttribute = 0;
1532 defaultAttributeConsumed = false;
1539 public override bool MoveToNextAttribute ()
1541 switch (reader.NodeType) {
1542 case XmlNodeType.XmlDeclaration:
1543 case XmlNodeType.DocumentType:
1544 return reader.MoveToNextAttribute ();
1547 currentQName = null;
1548 if (currentDefaultAttribute >= 0) {
1549 if (defaultAttributes.Length == currentDefaultAttribute + 1)
1551 currentDefaultAttribute++;
1552 defaultAttributeConsumed = false;
1556 bool b = reader.MoveToNextAttribute ();
1558 currentDefaultAttribute = -1;
1559 defaultAttributeConsumed = false;
1563 if (defaultAttributes.Length > 0) {
1564 currentDefaultAttribute = 0;
1565 defaultAttributeConsumed = false;
1572 private void ExamineAdditionalSchema ()
1574 XmlSchema schema = null;
1575 string schemaLocation = reader.GetAttribute ("schemaLocation", XmlSchema.InstanceNamespace);
1576 if (schemaLocation != null) {
1577 string [] tmp = null;
1579 schemaLocation = XmlSchemaDatatype.FromName ("token").Normalize (schemaLocation);
1580 tmp = schemaLocation.Split (XmlChar.WhitespaceChars);
1581 } catch (Exception ex) {
1582 HandleError ("Invalid schemaLocation attribute format.", ex, true);
1583 tmp = new string [0];
1585 if (tmp.Length % 2 != 0)
1586 HandleError ("Invalid schemaLocation attribute format.");
1587 for (int i = 0; i < tmp.Length; i += 2) {
1589 XmlTextReader xtr = null;
1591 absUri = new Uri ((this.BaseURI != "" ? new Uri (BaseURI) : null), tmp [i + 1]);
1592 xtr = new XmlTextReader (absUri.ToString ());
1593 schema = XmlSchema.Read (xtr, null);
1594 } catch (Exception) { // FIXME: (wishlist) It is bad manner ;-(
1595 HandleError ("Could not resolve schema location URI: " + absUri, null, true);
\r
1601 if (schema.TargetNamespace == null)
1602 schema.TargetNamespace = tmp [i];
1603 else if (schema.TargetNamespace != tmp [i])
1604 HandleError ("Specified schema has different target namespace.");
1607 if (schema != null) {
1609 schemas.Add (schema, resolver);
1610 } catch (XmlSchemaException ex) {
1615 string noNsSchemaLocation = reader.GetAttribute ("noNamespaceSchemaLocation", XmlSchema.InstanceNamespace);
1616 if (noNsSchemaLocation != null) {
1618 XmlTextReader xtr = null;
1620 absUri = new Uri ((this.BaseURI != "" ? new Uri (BaseURI) : null), noNsSchemaLocation);
1621 xtr = new XmlTextReader (absUri.ToString ());
1622 schema = XmlSchema.Read (xtr, null);
1623 } catch (Exception) { // FIXME: (wishlist) It is bad manner ;-(
1624 HandleError ("Could not resolve schema location URI: " + absUri, null, true);
\r
1629 if (schema != null && schema.TargetNamespace != null)
1630 HandleError ("Specified schema has different target namespace.");
1632 if (schema != null) {
1634 schema.Compile (ValidationEventHandler, resolver);
1635 schemas.Add (schema);
1636 } catch (XmlSchemaException ex) {
1642 public override bool Read ()
1644 nonDefaultAttributeCount = 0;
1645 currentDefaultAttribute = -1;
1646 defaultAttributeConsumed = false;
1647 currentQName = null;
1648 thisElementId = null;
1649 defaultAttributes = new XmlSchemaAttribute [0];
1651 elementQNameStack.RemoveAt (elementQNameStack.Count - 1);
1655 bool result = reader.Read ();
1656 // 3.3.4 ElementLocallyValidElement 7 = Root Valid.
1657 if (!result && missingIDReferences.Count > 0)
1658 HandleError ("There are missing ID references: " +
1660 this.missingIDReferences.ToArray (typeof (string)) as string []));
1662 switch (reader.NodeType) {
1663 case XmlNodeType.XmlDeclaration:
1664 this.nonDefaultAttributeCount = reader.AttributeCount;
1666 case XmlNodeType.Element:
1667 nonDefaultAttributeCount = reader.AttributeCount;
1669 if (reader.Depth == 0)
1670 ExamineAdditionalSchema ();
1672 this.elementQNameStack.Add (new XmlQualifiedName (reader.LocalName, reader.NamespaceURI));
1674 // If there is no schema information, then no validation is performed.
1675 if (schemas.Count == 0)
1678 if (skipValidationDepth < 0 || reader.Depth <= skipValidationDepth) {
1679 if (shouldValidateCharacters) {
1680 ValidateEndCharacters ();
1681 shouldValidateCharacters = false;
1683 AssessStartElementSchemaValidity ();
1684 storedCharacters.Length = 0;
1689 if (reader.IsEmptyElement)
1690 goto case XmlNodeType.EndElement;
1692 shouldValidateCharacters = true;
1694 case XmlNodeType.EndElement:
1695 if (reader.Depth == skipValidationDepth) {
1696 skipValidationDepth = -1;
1700 AssessEndElementSchemaValidity ();
1702 storedCharacters.Length = 0;
1703 childParticleState = null;
1707 case XmlNodeType.CDATA:
1708 case XmlNodeType.SignificantWhitespace:
1709 case XmlNodeType.Text:
1710 XmlSchemaComplexType ct = context.ActualType as XmlSchemaComplexType;
1711 if (ct != null && storedCharacters.Length > 0) {
1712 switch (ct.ContentType) {
1713 case XmlSchemaContentType.ElementOnly:
1714 case XmlSchemaContentType.Empty:
1715 HandleError ("Not allowed character content was found.");
1720 ValidateCharacters ();
1727 public override bool ReadAttributeValue ()
1729 if (currentDefaultAttribute < 0)
1730 return reader.ReadAttributeValue ();
1732 if (this.defaultAttributeConsumed)
1735 defaultAttributeConsumed = true;
1740 public override string ReadInnerXml ()
1742 // MS.NET 1.0 has a serious bug here. It skips validation.
1743 return reader.ReadInnerXml ();
1746 public override string ReadOuterXml ()
1748 // MS.NET 1.0 has a serious bug here. It skips validation.
1749 return reader.ReadOuterXml ();
1753 // XmlReader.ReadString() should call derived this.Read().
1754 public override string ReadString ()
1757 return reader.ReadString ();
1759 return base.ReadString ();
1763 // This class itself does not have this feature.
1764 public override void ResolveEntity ()
1766 reader.ResolveEntity ();
1769 internal class XsdValidationContext
1771 Hashtable contextStack;
1773 public XsdValidationContext ()
1775 contextStack = new Hashtable ();
1778 // Some of them might be missing (See the spec section 5.3, and also 3.3.4).
1779 public XmlSchemaElement Element;
1780 public XsdValidationState ParticleState;
1781 public XmlSchemaAttribute [] DefaultAttributes;
1783 // Some of them might be missing (See the spec section 5.3).
1784 public object SchemaType;
1786 public object LocalTypeDefinition;
1788 public object ActualType {
1790 if (LocalTypeDefinition != null)
1791 return LocalTypeDefinition;
1797 public void Clear ()
1801 ParticleState = null;
1802 LocalTypeDefinition = null;
1805 public void PushScope (int depth)
1807 contextStack [depth] = this.MemberwiseClone ();
1810 public void PopScope (int depth)
1813 contextStack.Remove (depth + 1);
1816 public void Load (int depth)
1819 XsdValidationContext restored = (XsdValidationContext) contextStack [depth];
1820 if (restored != null) {
1821 this.Element = restored.Element;
1822 this.ParticleState = restored.ParticleState;
1823 this.SchemaType = restored.SchemaType;
1824 this.LocalTypeDefinition = restored.LocalTypeDefinition;
1830 internal class XsdValidityState
1832 ArrayList currentParticles = new ArrayList ();
1833 ArrayList occured = new ArrayList ();
1834 Hashtable xsAllConsumed = new Hashtable ();
1835 XmlSchemaParticle parciele;
1838 public XsdValidityState (XmlSchemaParticle particle)
1840 this.parciele = particle;
1841 currentParticles.Add (particle);