2 // Mono.Xml.Schema.XsdValidatingReader.cs
5 // Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
7 // (C)2003 Atsushi Enomoto
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System.Collections;
32 using System.Collections.Specialized;
36 using System.Xml.Schema;
40 using ValException = System.Xml.Schema.XmlSchemaValidationException;
42 using ValException = System.Xml.Schema.XmlSchemaException;
45 using QName = System.Xml.XmlQualifiedName;
46 using ContentProc = System.Xml.Schema.XmlSchemaContentProcessing;
47 using XsElement = System.Xml.Schema.XmlSchemaElement;
48 using XsAttribute = System.Xml.Schema.XmlSchemaAttribute;
49 using ComplexType = System.Xml.Schema.XmlSchemaComplexType;
50 using SimpleType = System.Xml.Schema.XmlSchemaSimpleType;
51 using SimpleTypeRest = System.Xml.Schema.XmlSchemaSimpleTypeRestriction;
52 using SimpleTypeList = System.Xml.Schema.XmlSchemaSimpleTypeList;
53 using SimpleTypeUnion = System.Xml.Schema.XmlSchemaSimpleTypeUnion;
54 using XsDatatype = System.Xml.Schema.XmlSchemaDatatype;
56 namespace Mono.Xml.Schema
58 internal class XsdValidatingReader : XmlReader, IXmlLineInfo, IHasXmlSchemaInfo, IHasXmlParserContext, IXmlNamespaceResolver
60 static readonly XsAttribute [] emptyAttributeArray =
65 IHasXmlSchemaInfo sourceReaderSchemaInfo;
66 IXmlLineInfo readerLineInfo;
67 ValidationType validationType;
68 XmlSchemaSet schemas = new XmlSchemaSet ();
69 bool namespaces = true;
71 #region ID Constraints
72 bool checkIdentity = true;
73 XsdIDManager idManager = new XsdIDManager ();
76 #region Key Constraints
77 bool checkKeyConstraints = true;
78 ArrayList keyTables = new ArrayList ();
79 ArrayList currentKeyFieldConsumers;
80 ArrayList tmpKeyrefPool;
82 ArrayList elementQNameStack = new ArrayList ();
84 XsdParticleStateManager state = new XsdParticleStateManager ();
86 int skipValidationDepth = -1;
88 StringBuilder storedCharacters = new StringBuilder ();
89 bool shouldValidateCharacters;
91 XsAttribute [] defaultAttributes = emptyAttributeArray;
92 int currentDefaultAttribute = -1;
93 ArrayList defaultAttributesCache = new ArrayList ();
94 bool defaultAttributeConsumed;
95 object currentAttrType;
98 public XsdValidatingReader (XmlReader reader)
100 this.reader = reader;
101 readerLineInfo = reader as IXmlLineInfo;
102 sourceReaderSchemaInfo = reader as IHasXmlSchemaInfo;
103 schemas.ValidationEventHandler += ValidationEventHandler;
107 public ValidationEventHandler ValidationEventHandler;
109 // Private Properties
111 private XsdValidationContext Context {
112 get { return state.Context; }
115 #region Key Constraints
116 internal ArrayList CurrentKeyFieldConsumers {
118 if (currentKeyFieldConsumers == null)
119 currentKeyFieldConsumers = new ArrayList ();
120 return currentKeyFieldConsumers;
125 // Public Non-overrides
127 public int XsiNilDepth {
128 get { return xsiNilDepth; }
131 public bool Namespaces {
132 get { return namespaces; }
133 set { namespaces = value; }
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;
163 return SourceReaderSchemaType;
164 case XmlNodeType.Attribute:
165 if (currentAttrType == null) {
166 ComplexType ct = Context.ActualType as ComplexType;
168 XsAttribute attdef = ct.AttributeUses [new QName (LocalName, NamespaceURI)] as XsAttribute;
170 currentAttrType = attdef.AttributeType;
171 return currentAttrType;
173 currentAttrType = SourceReaderSchemaType;
175 return currentAttrType;
177 return SourceReaderSchemaType;
182 private object SourceReaderSchemaType {
183 get { return this.sourceReaderSchemaInfo != null ? sourceReaderSchemaInfo.SchemaType : null; }
186 public ValidationType ValidationType {
187 get { return validationType; }
189 if (ReadState != ReadState.Initial)
190 throw new InvalidOperationException ("ValidationType must be set before reading.");
191 validationType = value;
195 IDictionary IXmlNamespaceResolver.GetNamespacesInScope (XmlNamespaceScope scope)
197 IXmlNamespaceResolver resolver = reader as IXmlNamespaceResolver;
198 if (resolver == null)
199 throw new NotSupportedException ("The input XmlReader does not implement IXmlNamespaceResolver and thus this validating reader cannot collect in-scope namespaces.");
200 return resolver.GetNamespacesInScope (scope);
203 string IXmlNamespaceResolver.LookupPrefix (string ns)
205 return ((IXmlNamespaceResolver) this).LookupPrefix (ns, false);
208 string IXmlNamespaceResolver.LookupPrefix (string ns, bool atomizedNames)
210 IXmlNamespaceResolver resolver = reader as IXmlNamespaceResolver;
211 if (resolver == null)
212 throw new NotSupportedException ("The input XmlReader does not implement IXmlNamespaceResolver and thus this validating reader cannot execute namespace prefix lookup.");
213 return resolver.LookupPrefix (ns, atomizedNames);
216 // It is used only for independent XmlReader use, not for XmlValidatingReader.
218 public override object ReadTypedValue ()
220 public object ReadTypedValue ()
223 object o = XmlSchemaUtil.ReadTypedValue (this,
224 SchemaType, ParserContext.NamespaceManager,
226 storedCharacters.Length = 0;
230 private object ReadTypedValueCore ()
232 XsDatatype dt = SchemaType as XsDatatype;
233 SimpleType st = SchemaType as SimpleType;
240 case XmlNodeType.Element:
244 storedCharacters.Length = 0;
249 case XmlNodeType.SignificantWhitespace:
250 case XmlNodeType.Text:
251 case XmlNodeType.CDATA:
252 storedCharacters.Append (Value);
254 case XmlNodeType.Comment:
260 } while (loop && !EOF && ReadState == ReadState.Interactive);
261 return dt.ParseValue (storedCharacters.ToString (), NameTable, ParserContext.NamespaceManager);
262 case XmlNodeType.Attribute:
263 return dt.ParseValue (Value, NameTable, ParserContext.NamespaceManager);
268 // Public Overriden Properties
270 public override int AttributeCount {
272 return reader.AttributeCount + defaultAttributes.Length;
276 public override string BaseURI {
277 get { return reader.BaseURI; }
280 // If this class is used to implement XmlValidatingReader,
281 // it should be left to DTDValidatingReader. In other cases,
282 // it depends on the reader's ability.
283 public override bool CanResolveEntity {
284 get { return reader.CanResolveEntity; }
287 public override int Depth {
289 if (currentDefaultAttribute < 0)
291 if (this.defaultAttributeConsumed)
292 return reader.Depth + 2;
293 return reader.Depth + 1;
297 public override bool EOF {
298 get { return reader.EOF; }
301 public override bool HasValue {
303 if (currentDefaultAttribute < 0)
304 return reader.HasValue;
309 public override bool IsDefault {
311 if (currentDefaultAttribute < 0)
312 return reader.IsDefault;
317 public override bool IsEmptyElement {
319 if (currentDefaultAttribute < 0)
320 return reader.IsEmptyElement;
325 public override string this [int i] {
326 get { return GetAttribute (i); }
329 public override string this [string name] {
330 get { return GetAttribute (name); }
333 public override string this [string localName, string ns] {
334 get { return GetAttribute (localName, ns); }
337 public int LineNumber {
338 get { return readerLineInfo != null ? readerLineInfo.LineNumber : 0; }
341 public int LinePosition {
342 get { return readerLineInfo != null ? readerLineInfo.LinePosition : 0; }
345 public override string LocalName {
347 if (currentDefaultAttribute < 0)
348 return reader.LocalName;
349 if (defaultAttributeConsumed)
351 return defaultAttributes [currentDefaultAttribute].QualifiedName.Name;
355 public override string Name {
357 if (currentDefaultAttribute < 0)
359 if (defaultAttributeConsumed)
362 QName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
363 string prefix = Prefix;
364 if (prefix == String.Empty)
367 return String.Concat (prefix, ":", qname.Name);
371 public override string NamespaceURI {
373 if (currentDefaultAttribute < 0)
374 return reader.NamespaceURI;
375 if (defaultAttributeConsumed)
377 return defaultAttributes [currentDefaultAttribute].QualifiedName.Namespace;
381 public override XmlNameTable NameTable {
382 get { return reader.NameTable; }
385 public override XmlNodeType NodeType {
387 if (currentDefaultAttribute < 0)
388 return reader.NodeType;
389 if (defaultAttributeConsumed)
390 return XmlNodeType.Text;
391 return XmlNodeType.Attribute;
395 public XmlParserContext ParserContext {
396 get { return XmlSchemaUtil.GetParserContext (reader); }
399 public override string Prefix {
401 if (currentDefaultAttribute < 0)
402 return reader.Prefix;
403 if (defaultAttributeConsumed)
405 QName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
406 string prefix = this.ParserContext.NamespaceManager.LookupPrefix (qname.Namespace, false);
414 public override char QuoteChar {
415 get { return reader.QuoteChar; }
418 public override ReadState ReadState {
419 get { return reader.ReadState; }
422 public override string Value {
424 if (currentDefaultAttribute < 0)
426 string value = defaultAttributes [currentDefaultAttribute].ValidatedDefaultValue;
428 value = defaultAttributes [currentDefaultAttribute].ValidatedFixedValue;
433 public override string XmlLang {
435 string xmlLang = reader.XmlLang;
438 int idx = this.FindDefaultAttribute ("lang", XmlNamespaceManager.XmlnsXml);
441 xmlLang = defaultAttributes [idx].ValidatedDefaultValue;
443 xmlLang = defaultAttributes [idx].ValidatedFixedValue;
448 public override XmlSpace XmlSpace {
450 XmlSpace space = reader.XmlSpace;
451 if (space != XmlSpace.None)
453 int idx = this.FindDefaultAttribute ("space", XmlNamespaceManager.XmlnsXml);
455 return XmlSpace.None;
456 string spaceSpec = defaultAttributes [idx].ValidatedDefaultValue;
457 if (spaceSpec == null)
458 spaceSpec = defaultAttributes [idx].ValidatedFixedValue;
459 return (XmlSpace) Enum.Parse (typeof (XmlSpace), spaceSpec, false);
465 private void HandleError (string error)
467 HandleError (error, null);
470 private void HandleError (string error, Exception innerException)
472 HandleError (error, innerException, false);
475 private void HandleError (string error, Exception innerException, bool isWarning)
477 if (ValidationType == ValidationType.None) // extra quick check
480 ValException schemaException = new ValException (error,
481 this, this.BaseURI, null, innerException);
482 HandleError (schemaException, isWarning);
485 private void HandleError (ValException schemaException)
487 HandleError (schemaException, false);
490 private void HandleError (ValException schemaException, bool isWarning)
492 if (ValidationType == ValidationType.None)
495 ValidationEventArgs e = new ValidationEventArgs (schemaException,
496 schemaException.Message, isWarning ? XmlSeverityType.Warning : XmlSeverityType.Error);
498 if (ValidationEventHandler != null)
499 ValidationEventHandler (this, e);
501 else if (e.Severity == XmlSeverityType.Error)
505 private XsElement FindElement (string name, string ns)
507 return (XsElement) schemas.GlobalElements [new QName (name, ns)];
510 private XmlSchemaType FindType (QName qname)
512 return (XmlSchemaType) schemas.GlobalTypes [qname];
515 private void ValidateStartElementParticle ()
517 if (Context.State == null)
519 Context.XsiType = null;
520 state.CurrentElement = null;
521 Context.EvaluateStartElement (reader.LocalName,
522 reader.NamespaceURI);
523 if (Context.IsInvalid)
524 HandleError ("Invalid start element: " + reader.NamespaceURI + ":" + reader.LocalName);
526 Context.SetElement (state.CurrentElement);
529 private void ValidateEndElementParticle ()
531 if (Context.State != null) {
532 if (!Context.EvaluateEndElement ()) {
533 HandleError ("Invalid end element: " + reader.Name);
539 // Utility for missing validation completion related to child items.
540 private void ValidateCharacters ()
542 if (xsiNilDepth >= 0 && xsiNilDepth < reader.Depth)
543 HandleError ("Element item appeared, while current element context is nil.");
545 if (shouldValidateCharacters)
546 storedCharacters.Append (reader.Value);
549 // Utility for missing validation completion related to child items.
550 private void ValidateEndSimpleContent ()
552 if (shouldValidateCharacters)
553 ValidateEndSimpleContentCore ();
554 shouldValidateCharacters = false;
555 storedCharacters.Length = 0;
558 private void ValidateEndSimpleContentCore ()
560 if (Context.ActualType == null)
563 string value = storedCharacters.ToString ();
565 if (value.Length == 0) {
566 // 3.3.4 Element Locally Valid (Element) 5.1.2
567 if (Context.Element != null) {
568 if (Context.Element.ValidatedDefaultValue != null)
569 value = Context.Element.ValidatedDefaultValue;
573 XsDatatype dt = Context.ActualType as XsDatatype;
574 SimpleType st = Context.ActualType as SimpleType;
579 ComplexType ct = Context.ActualType as ComplexType;
581 switch (ct.ContentType) {
582 case XmlSchemaContentType.ElementOnly:
583 case XmlSchemaContentType.Empty:
584 if (value.Length > 0)
585 HandleError ("Character content not allowed.");
591 // 3.3.4 Element Locally Valid (Element) :: 5.2.2.2. Fixed value constraints
592 if (Context.Element != null && Context.Element.ValidatedFixedValue != null)
593 if (value != Context.Element.ValidatedFixedValue)
594 HandleError ("Fixed value constraint was not satisfied.");
595 AssessStringValid (st, dt, value);
598 #region Key Constraints
599 if (checkKeyConstraints)
600 ValidateSimpleContentIdentity (dt, value);
603 shouldValidateCharacters = false;
606 // 3.14.4 String Valid
607 private void AssessStringValid (SimpleType st,
608 XsDatatype dt, string value)
610 XsDatatype validatedDatatype = dt;
612 string normalized = validatedDatatype.Normalize (value);
614 XsDatatype itemDatatype;
615 SimpleType itemSimpleType;
616 switch (st.DerivedBy) {
617 case XmlSchemaDerivationMethod.List:
618 SimpleTypeList listContent = st.Content as SimpleTypeList;
619 values = normalized.Split (XmlChar.WhitespaceChars);
620 itemDatatype = listContent.ValidatedListItemType as XsDatatype;
621 itemSimpleType = listContent.ValidatedListItemType as SimpleType;
622 for (int vi = 0; vi < values.Length; vi++) {
623 string each = values [vi];
624 if (each == String.Empty)
626 // validate against ValidatedItemType
627 if (itemDatatype != null) {
629 itemDatatype.ParseValue (each, NameTable, ParserContext.NamespaceManager);
630 } catch (Exception ex) { // FIXME: (wishlist) better exception handling ;-(
631 HandleError ("List type value contains one or more invalid values.", ex);
636 AssessStringValid (itemSimpleType, itemSimpleType.Datatype, each);
639 case XmlSchemaDerivationMethod.Union:
640 SimpleTypeUnion union = st.Content as SimpleTypeUnion;
642 string each = normalized;
643 // validate against ValidatedItemType
645 foreach (object eachType in union.ValidatedTypes) {
646 itemDatatype = eachType as XsDatatype;
647 itemSimpleType = eachType as SimpleType;
648 if (itemDatatype != null) {
650 itemDatatype.ParseValue (each, NameTable, ParserContext.NamespaceManager);
651 } catch (Exception) { // FIXME: (wishlist) better exception handling ;-(
657 AssessStringValid (itemSimpleType, itemSimpleType.Datatype, each);
658 } catch (ValException) {
666 HandleError ("Union type value contains one or more invalid values.");
671 case XmlSchemaDerivationMethod.Restriction:
672 SimpleTypeRest str = st.Content as SimpleTypeRest;
675 /* Don't forget to validate against inherited type's facets
676 * Could we simplify this by assuming that the basetype will also
679 // mmm, will check later.
680 SimpleType baseType = st.BaseXmlSchemaType as SimpleType;
681 if (baseType != null) {
682 AssessStringValid(baseType, dt, normalized);
684 if (!str.ValidateValueWithFacets (normalized, NameTable)) {
685 HandleError ("Specified value was invalid against the facets.");
689 validatedDatatype = st.Datatype;
693 if (validatedDatatype != null) {
695 validatedDatatype.ParseValue (value, NameTable, ParserContext.NamespaceManager);
696 } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
697 HandleError ("Invalidly typed data was specified.", ex);
702 private object GetXsiType (string name)
704 object xsiType = null;
705 QName typeQName = QName.Parse (name, this);
706 if (typeQName == ComplexType.AnyTypeName)
707 xsiType = ComplexType.AnyType;
708 else if (XmlSchemaUtil.IsBuiltInDatatypeName (typeQName))
709 xsiType = XsDatatype.FromName (typeQName);
711 xsiType = FindType (typeQName);
715 // It is common to ElementLocallyValid::4 and SchemaValidityAssessment::1.2.1.2.4
716 private void AssessLocalTypeDerivationOK (object xsiType, object baseType, XmlSchemaDerivationMethod flag)
718 XmlSchemaType xsiSchemaType = xsiType as XmlSchemaType;
719 ComplexType baseComplexType = baseType as ComplexType;
720 ComplexType xsiComplexType = xsiSchemaType as ComplexType;
721 if (xsiType != baseType) {
722 // Extracted (not extraneous) check for 3.4.6 TypeDerivationOK.
723 if (baseComplexType != null)
724 flag |= baseComplexType.BlockResolved;
725 if (flag == XmlSchemaDerivationMethod.All) {
726 HandleError ("Prohibited element type substitution.");
728 } else if (xsiSchemaType != null && (flag & xsiSchemaType.DerivedBy) != 0) {
729 HandleError ("Prohibited element type substitution.");
734 if (xsiComplexType != null)
736 xsiComplexType.ValidateTypeDerivationOK (baseType, null, null);
737 } catch (ValException ex) {
738 // HandleError ("Locally specified schema complex type derivation failed. " + ex.Message, ex);
742 SimpleType xsiSimpleType = xsiType as SimpleType;
743 if (xsiSimpleType != null) {
745 xsiSimpleType.ValidateTypeDerivationOK (baseType, null, null, true);
746 } catch (ValException ex) {
747 // HandleError ("Locally specified schema simple type derivation failed. " + ex.Message, ex);
751 else if (xsiType is XsDatatype) {
755 HandleError ("Primitive data type cannot be derived type using xsi:type specification.");
759 // Section 3.3.4 of the spec.
760 private void AssessStartElementSchemaValidity ()
762 // If the reader is inside xsi:nil (and failed
763 // on validation), then simply skip its content.
764 if (xsiNilDepth >= 0 && xsiNilDepth < reader.Depth)
765 HandleError ("Element item appeared, while current element context is nil.");
767 ValidateStartElementParticle ();
769 string xsiNilValue = reader.GetAttribute ("nil", XmlSchema.InstanceNamespace);
770 if (xsiNilValue != null)
771 xsiNilValue = xsiNilValue.Trim (XmlChar.WhitespaceChars);
772 bool isXsiNil = xsiNilValue == "true";
773 if (isXsiNil && this.xsiNilDepth < 0)
774 xsiNilDepth = reader.Depth;
776 // [Schema Validity Assessment (Element) 1.2]
777 // Evaluate "local type definition" from xsi:type.
778 // (See spec 3.3.4 Schema Validity Assessment (Element) 1.2.1.2.3.
779 // Note that Schema Validity Assessment(Element) 1.2 takes
780 // precedence than 1.1 of that.
782 string xsiTypeName = reader.GetAttribute ("type", XmlSchema.InstanceNamespace);
783 if (xsiTypeName != null) {
784 xsiTypeName = xsiTypeName.Trim (XmlChar.WhitespaceChars);
785 object xsiType = GetXsiType (xsiTypeName);
787 HandleError ("The instance type was not found: " + xsiTypeName + " .");
789 XmlSchemaType xsiSchemaType = xsiType as XmlSchemaType;
790 if (xsiSchemaType != null && this.Context.Element != null) {
791 XmlSchemaType elemBaseType = Context.Element.ElementType as XmlSchemaType;
792 if (elemBaseType != null && (xsiSchemaType.DerivedBy & elemBaseType.FinalResolved) != 0)
793 HandleError ("The instance type is prohibited by the type of the context element.");
794 if (elemBaseType != xsiType && (xsiSchemaType.DerivedBy & this.Context.Element.BlockResolved) != 0)
795 HandleError ("The instance type is prohibited by the context element.");
797 ComplexType xsiComplexType = xsiType as ComplexType;
798 if (xsiComplexType != null && xsiComplexType.IsAbstract)
799 HandleError ("The instance type is abstract: " + xsiTypeName + " .");
801 // If current schema type exists, then this xsi:type must be
802 // valid extension of that type. See 1.2.1.2.4.
803 if (Context.Element != null) {
804 AssessLocalTypeDerivationOK (xsiType, Context.Element.ElementType, Context.Element.BlockResolved);
806 AssessStartElementLocallyValidType (xsiType); // 1.2.2:
807 Context.XsiType = xsiType;
812 // Create Validation Root, if not exist.
813 // [Schema Validity Assessment (Element) 1.1]
814 if (Context.Element == null) {
815 state.CurrentElement = FindElement (reader.LocalName, reader.NamespaceURI);
816 Context.SetElement (state.CurrentElement);
818 if (Context.Element != null) {
819 if (Context.XsiType == null) {
820 AssessElementLocallyValidElement (xsiNilValue); // 1.1.2
823 switch (state.ProcessContents) {
824 case ContentProc.Skip:
826 case ContentProc.Lax:
829 if (xsiTypeName == null &&
830 (schemas.Contains (reader.NamespaceURI) ||
831 !schemas.MissedSubComponents (reader.NamespaceURI)))
832 HandleError ("Element declaration for " + new QName (reader.LocalName, reader.NamespaceURI) + " is missing.");
837 state.PushContext ();
839 XsdValidationState next = null;
840 if (state.ProcessContents == ContentProc.Skip)
841 skipValidationDepth = reader.Depth;
843 // create child particle state.
844 ComplexType xsComplexType = SchemaType as ComplexType;
845 if (xsComplexType != null)
846 next = state.Create (xsComplexType.ValidatableParticle);
847 else if (state.ProcessContents == ContentProc.Lax)
848 next = state.Create (XmlSchemaAny.AnyTypeContent);
850 next = state.Create (XmlSchemaParticle.Empty);
852 Context.State = next;
854 #region Key Constraints
855 if (checkKeyConstraints) {
856 ValidateKeySelectors ();
857 ValidateKeyFields ();
863 // 3.3.4 Element Locally Valid (Element)
864 private void AssessElementLocallyValidElement (string xsiNilValue)
866 XsElement element = Context.Element;
867 QName qname = new QName (reader.LocalName, reader.NamespaceURI);
870 HandleError ("Element declaration is required for " + qname);
872 if (element.ActualIsAbstract)
873 HandleError ("Abstract element declaration was specified for " + qname);
875 if (!element.ActualIsNillable && xsiNilValue != null)
876 HandleError ("This element declaration is not nillable: " + qname);
878 // Note that 3.2.1 xsi:nil constraints are to be
879 // validated in AssessElementSchemaValidity() and
880 // ValidateCharacters().
881 else if (xsiNilValue == "true") {
882 if (element.ValidatedFixedValue != null)
883 HandleError ("Schema instance nil was specified, where the element declaration for " + qname + "has fixed value constraints.");
885 // 4. xsi:type (it takes precedence than element type)
886 string xsiType = reader.GetAttribute ("type", XmlSchema.InstanceNamespace);
887 if (xsiType != null) {
888 Context.XsiType = GetXsiType (xsiType);
889 AssessLocalTypeDerivationOK (Context.XsiType, element.ElementType, element.BlockResolved);
892 Context.XsiType = null;
894 // 5 Not all things cannot be assessed here.
895 // It is common to 5.1 and 5.2
896 if (element.ElementType != null)
897 AssessStartElementLocallyValidType (SchemaType);
899 // 6. should be out from here.
900 // See invokation of AssessStartIdentityConstraints().
902 // 7 is going to be validated in Read() (in case of xmlreader's EOF).
905 // 3.3.4 Element Locally Valid (Type)
906 private void AssessStartElementLocallyValidType (object schemaType)
908 if (schemaType == null) { // 1.
909 HandleError ("Schema type does not exist.");
912 ComplexType cType = schemaType as ComplexType;
913 SimpleType sType = schemaType as SimpleType;
916 while (reader.MoveToNextAttribute ()) {
917 if (reader.NamespaceURI == XmlNamespaceManager.XmlnsXmlns)
919 if (reader.NamespaceURI != XmlSchema.InstanceNamespace)
920 HandleError ("Current simple type cannot accept attributes other than schema instance namespace.");
921 switch (reader.LocalName) {
924 case "schemaLocation":
925 case "noNamespaceSchemaLocation":
928 HandleError ("Unknown schema instance namespace attribute: " + reader.LocalName);
932 reader.MoveToElement ();
933 // 3.1.2 and 3.1.3 cannot be assessed here.
934 } else if (cType != null) {
935 if (cType.IsAbstract) { // 2.
936 HandleError ("Target complex type is abstract.");
940 AssessElementLocallyValidComplexType (cType);
944 // 3.4.4 Element Locally Valid (Complex Type)
945 private void AssessElementLocallyValidComplexType (ComplexType cType)
948 if (cType.IsAbstract)
949 HandleError ("Target complex type is abstract.");
951 // 2 (xsi:nil and content prohibition)
952 // See AssessStartElementSchemaValidity() and ValidateCharacters()
954 // 3. attribute uses and
956 if (reader.MoveToFirstAttribute ()) {
958 switch (reader.NamespaceURI) {
959 case"http://www.w3.org/2000/xmlns/":
960 case XmlSchema.InstanceNamespace:
963 QName qname = new QName (reader.LocalName, reader.NamespaceURI);
964 // including 3.10.4 Item Valid (Wildcard)
965 XmlSchemaObject attMatch = XmlSchemaUtil.FindAttributeDeclaration (reader.NamespaceURI, schemas, cType, qname);
966 if (attMatch == null)
967 HandleError ("Attribute declaration was not found for " + qname);
968 XsAttribute attdecl = attMatch as XsAttribute;
969 if (attdecl != null) {
970 AssessAttributeLocallyValidUse (attdecl);
971 AssessAttributeLocallyValid (attdecl);
972 } // otherwise anyAttribute or null.
973 } while (reader.MoveToNextAttribute ());
974 reader.MoveToElement ();
977 // Collect default attributes.
979 foreach (DictionaryEntry entry in cType.AttributeUses) {
980 XsAttribute attr = (XsAttribute) entry.Value;
981 if (reader [attr.QualifiedName.Name, attr.QualifiedName.Namespace] == null) {
982 if (attr.ValidatedUse == XmlSchemaUse.Required &&
983 attr.ValidatedFixedValue == null)
984 HandleError ("Required attribute " + attr.QualifiedName + " was not found.");
985 else if (attr.ValidatedDefaultValue != null || attr.ValidatedFixedValue != null)
986 defaultAttributesCache.Add (attr);
989 if (defaultAttributesCache.Count == 0)
990 defaultAttributes = emptyAttributeArray;
992 defaultAttributes = (XsAttribute [])
993 defaultAttributesCache.ToArray (
994 typeof (XsAttribute));
995 defaultAttributesCache.Clear ();
996 // 5. wild IDs was already checked above.
999 // 3.2.4 Attribute Locally Valid and 3.4.4
1000 private void AssessAttributeLocallyValid (XsAttribute attr)
1003 if (attr.AttributeType == null)
1004 HandleError ("Attribute type is missing for " + attr.QualifiedName);
1005 XsDatatype dt = attr.AttributeType as XsDatatype;
1007 dt = ((SimpleType) attr.AttributeType).Datatype;
1008 // It is a bit heavy process, so let's omit as long as possible ;-)
1009 if (dt != SimpleType.AnySimpleType || attr.ValidatedFixedValue != null) {
1010 string normalized = dt.Normalize (reader.Value);
1011 object parsedValue = null;
1013 parsedValue = dt.ParseValue (normalized, reader.NameTable, this.ParserContext.NamespaceManager);
1014 } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
1015 HandleError ("Attribute value is invalid against its data type " + dt.TokenizedType, ex);
1017 if (attr.ValidatedFixedValue != null && attr.ValidatedFixedValue != normalized) {
1018 HandleError ("The value of the attribute " + attr.QualifiedName + " does not match with its fixed value.");
1019 parsedValue = dt.ParseValue (attr.ValidatedFixedValue, reader.NameTable, this.ParserContext.NamespaceManager);
1021 #region ID Constraints
1022 if (this.checkIdentity) {
1023 string error = idManager.AssessEachAttributeIdentityConstraint (dt, parsedValue, ((QName) elementQNameStack [elementQNameStack.Count - 1]).Name);
1025 HandleError (error);
1031 private void AssessAttributeLocallyValidUse (XsAttribute attr)
1033 // This is extra check than spec 3.5.4
1034 if (attr.ValidatedUse == XmlSchemaUse.Prohibited)
1035 HandleError ("Attribute " + attr.QualifiedName + " is prohibited in this context.");
1038 private void AssessEndElementSchemaValidity ()
1040 ValidateEndElementParticle (); // validate against childrens' state.
1042 ValidateEndSimpleContent ();
1044 // 3.3.4 Assess ElementLocallyValidElement 5: value constraints.
1045 // 3.3.4 Assess ElementLocallyValidType 3.1.3. = StringValid(3.14.4)
1046 // => ValidateEndSimpleContent().
1048 #region Key Constraints
1049 if (checkKeyConstraints)
1050 ValidateEndElementKeyConstraints ();
1053 // Reset xsi:nil, if required.
1054 if (xsiNilDepth == reader.Depth)
1058 #region Key Constraints
1059 private void ValidateEndElementKeyConstraints ()
1061 // Reset Identity constraints.
1062 for (int i = 0; i < keyTables.Count; i++) {
1063 XsdKeyTable seq = this.keyTables [i] as XsdKeyTable;
1064 if (seq.StartDepth == reader.Depth) {
1065 EndIdentityValidation (seq);
1067 for (int k = 0; k < seq.Entries.Count; k++) {
1068 XsdKeyEntry entry = seq.Entries [k] as XsdKeyEntry;
1069 // Remove finished (maybe key not found) entries.
1070 if (entry.StartDepth == reader.Depth) {
1072 seq.FinishedEntries.Add (entry);
1073 else if (seq.SourceSchemaIdentity is XmlSchemaKey)
1074 HandleError ("Key sequence is missing.");
1075 seq.Entries.RemoveAt (k);
1078 // Pop validated key depth to find two or more fields.
1080 for (int j = 0; j < entry.KeyFields.Count; j++) {
1081 XsdKeyEntryField kf = entry.KeyFields [j];
1082 if (!kf.FieldFound && kf.FieldFoundDepth == reader.Depth) {
1083 kf.FieldFoundDepth = 0;
1084 kf.FieldFoundPath = null;
1091 for (int i = 0; i < keyTables.Count; i++) {
1092 XsdKeyTable seq = this.keyTables [i] as XsdKeyTable;
1093 if (seq.StartDepth == reader.Depth) {
1094 keyTables.RemoveAt (i);
1100 // 3.11.4 Identity Constraint Satisfied
1101 private void ValidateKeySelectors ()
1103 if (tmpKeyrefPool != null)
1104 tmpKeyrefPool.Clear ();
1105 if (Context.Element != null && Context.Element.Constraints.Count > 0) {
1106 // (a) Create new key sequences, if required.
1107 for (int i = 0; i < Context.Element.Constraints.Count; i++) {
1108 XmlSchemaIdentityConstraint ident = (XmlSchemaIdentityConstraint) Context.Element.Constraints [i];
1109 XsdKeyTable seq = CreateNewKeyTable (ident);
1110 if (ident is XmlSchemaKeyref) {
1111 if (tmpKeyrefPool == null)
1112 tmpKeyrefPool = new ArrayList ();
1113 tmpKeyrefPool.Add (seq);
1118 // (b) Evaluate current key sequences.
1119 for (int i = 0; i < keyTables.Count; i++) {
1120 XsdKeyTable seq = (XsdKeyTable) keyTables [i];
1121 if (seq.SelectorMatches (this.elementQNameStack, reader.Depth) != null) {
1122 // creates and registers new entry.
1123 XsdKeyEntry entry = new XsdKeyEntry (seq, reader.Depth, readerLineInfo);
1124 seq.Entries.Add (entry);
1129 private void ValidateKeyFields ()
1131 // (c) Evaluate field paths.
1132 for (int i = 0; i < keyTables.Count; i++) {
1133 XsdKeyTable seq = (XsdKeyTable) keyTables [i];
1134 // If possible, create new field entry candidates.
1135 for (int j = 0; j < seq.Entries.Count; j++) {
1137 ProcessKeyEntry (seq.Entries [j]);
1138 } catch (ValException ex) {
1145 private void ProcessKeyEntry (XsdKeyEntry entry)
1147 bool isNil = XsiNilDepth == Depth;
1148 entry.ProcessMatch (false, elementQNameStack, this, NameTable, BaseURI, SchemaType, ParserContext.NamespaceManager, readerLineInfo, Depth, null, null, null, isNil, CurrentKeyFieldConsumers);
1149 if (MoveToFirstAttribute ()) {
1152 switch (NamespaceURI) {
1153 case XmlNamespaceManager.XmlnsXmlns:
1154 case XmlSchema.InstanceNamespace:
1157 entry.ProcessMatch (true, elementQNameStack, this, NameTable, BaseURI, SchemaType, ParserContext.NamespaceManager, readerLineInfo, Depth, LocalName, NamespaceURI, Value, false, CurrentKeyFieldConsumers);
1158 } while (MoveToNextAttribute ());
1165 private XsdKeyTable CreateNewKeyTable (XmlSchemaIdentityConstraint ident)
1167 XsdKeyTable seq = new XsdKeyTable (ident);
1168 seq.StartDepth = reader.Depth;
1169 this.keyTables.Add (seq);
1173 private void ValidateSimpleContentIdentity (
1174 XmlSchemaDatatype dt, string value)
1176 // Identity field value
1177 if (currentKeyFieldConsumers != null) {
1178 while (this.currentKeyFieldConsumers.Count > 0) {
1179 XsdKeyEntryField field = this.currentKeyFieldConsumers [0] as XsdKeyEntryField;
1180 if (field.Identity != null)
1181 HandleError ("Two or more identical field was found. Former value is '" + field.Identity + "' .");
1182 object identity = null; // This means empty value
1185 identity = dt.ParseValue (value, NameTable, ParserContext.NamespaceManager);
1186 } catch (Exception ex) { // FIXME: (wishlist) This is bad manner ;-(
1187 HandleError ("Identity value is invalid against its data type " + dt.TokenizedType, ex);
1190 if (identity == null)
1193 if (!field.SetIdentityField (identity, reader.Depth == xsiNilDepth, dt as XsdAnySimpleType, this.Depth, readerLineInfo))
1194 HandleError ("Two or more identical key value was found: '" + value + "' .");
1195 this.currentKeyFieldConsumers.RemoveAt (0);
1200 private void EndIdentityValidation (XsdKeyTable seq)
1202 ArrayList errors = null;
1203 for (int i = 0; i < seq.Entries.Count; i++) {
1204 XsdKeyEntry entry = (XsdKeyEntry) seq.Entries [i];
1207 if (seq.SourceSchemaIdentity is XmlSchemaKey) {
1209 errors = new ArrayList ();
1210 errors.Add ("line " + entry.SelectorLineNumber + "position " + entry.SelectorLinePosition);
1214 HandleError ("Invalid identity constraints were found. Key was not found. "
1215 + String.Join (", ", errors.ToArray (typeof (string)) as string []));
1217 // If it is keyref, then find reference target
1218 XmlSchemaKeyref xsdKeyref = seq.SourceSchemaIdentity as XmlSchemaKeyref;
1219 if (xsdKeyref != null)
1220 EndKeyrefValidation (seq, xsdKeyref.Target);
1223 private void EndKeyrefValidation (XsdKeyTable seq, XmlSchemaIdentityConstraint targetIdent)
1225 for (int i = this.keyTables.Count - 1; i >= 0; i--) {
1226 XsdKeyTable target = this.keyTables [i] as XsdKeyTable;
1227 if (target.SourceSchemaIdentity != targetIdent)
1229 seq.ReferencedKey = target;
1230 for (int j = 0; j < seq.FinishedEntries.Count; j++) {
1231 XsdKeyEntry entry = (XsdKeyEntry) seq.FinishedEntries [j];
1232 for (int k = 0; k < target.FinishedEntries.Count; k++) {
1233 XsdKeyEntry targetEntry = (XsdKeyEntry) target.FinishedEntries [k];
1234 if (entry.CompareIdentity (targetEntry)) {
1235 entry.KeyRefFound = true;
1241 if (seq.ReferencedKey == null)
1242 HandleError ("Target key was not found.");
1243 ArrayList errors = null;
1244 for (int i = 0; i < seq.FinishedEntries.Count; i++) {
1245 XsdKeyEntry entry = (XsdKeyEntry) seq.FinishedEntries [i];
1246 if (!entry.KeyRefFound) {
1248 errors = new ArrayList ();
1249 errors.Add (" line " + entry.SelectorLineNumber + ", position " + entry.SelectorLinePosition);
1253 HandleError ("Invalid identity constraints were found. Referenced key was not found: "
1254 + String.Join (" / ", errors.ToArray (typeof (string)) as string []));
1258 // Overrided Methods
1260 public override void Close ()
1265 public override string GetAttribute (int i)
1267 switch (reader.NodeType) {
1268 case XmlNodeType.XmlDeclaration:
1269 case XmlNodeType.DocumentType:
1270 return reader.GetAttribute (i);
1273 if (reader.AttributeCount > i)
1274 reader.GetAttribute (i);
1275 int defIdx = i - reader.AttributeCount;
1276 if (i < AttributeCount)
1277 return defaultAttributes [defIdx].DefaultValue;
1279 throw new ArgumentOutOfRangeException ("i", i, "Specified attribute index is out of range.");
1282 public override string GetAttribute (string name)
1284 switch (reader.NodeType) {
1285 case XmlNodeType.XmlDeclaration:
1286 case XmlNodeType.DocumentType:
1287 return reader.GetAttribute (name);
1290 string value = reader.GetAttribute (name);
1294 QName qname = SplitQName (name);
1295 return GetDefaultAttribute (qname.Name, qname.Namespace);
1298 private QName SplitQName (string name)
1300 if (!XmlChar.IsName (name))
1301 throw new ArgumentException ("Invalid name was specified.", "name");
1303 Exception ex = null;
1304 QName qname = XmlSchemaUtil.ToQName (reader, name, out ex);
1311 public override string GetAttribute (string localName, string ns)
1313 switch (reader.NodeType) {
1314 case XmlNodeType.XmlDeclaration:
1315 case XmlNodeType.DocumentType:
1316 return reader.GetAttribute (localName, ns);
1319 string value = reader.GetAttribute (localName, ns);
1323 return GetDefaultAttribute (localName, ns);
1326 private string GetDefaultAttribute (string localName, string ns)
1328 int idx = this.FindDefaultAttribute (localName, ns);
1331 string value = defaultAttributes [idx].ValidatedDefaultValue;
1333 value = defaultAttributes [idx].ValidatedFixedValue;
1337 private int FindDefaultAttribute (string localName, string ns)
1339 for (int i = 0; i < this.defaultAttributes.Length; i++) {
1340 XsAttribute attr = defaultAttributes [i];
1341 if (attr.QualifiedName.Name == localName &&
1342 (ns == null || attr.QualifiedName.Namespace == ns))
1348 public bool HasLineInfo ()
1350 return readerLineInfo != null && readerLineInfo.HasLineInfo ();
1353 public override string LookupNamespace (string prefix)
1355 return reader.LookupNamespace (prefix);
1358 string IXmlNamespaceResolver.LookupNamespace (string prefix, bool atomizedNames)
1360 IXmlNamespaceResolver res = reader as IXmlNamespaceResolver;
1362 return res.LookupNamespace (prefix, atomizedNames);
1364 return reader.LookupNamespace (prefix);
1367 public override void MoveToAttribute (int i)
1369 switch (reader.NodeType) {
1370 case XmlNodeType.XmlDeclaration:
1371 case XmlNodeType.DocumentType:
1372 reader.MoveToAttribute (i);
1376 currentAttrType = null;
1377 if (i < reader.AttributeCount) {
1378 reader.MoveToAttribute (i);
1379 this.currentDefaultAttribute = -1;
1380 this.defaultAttributeConsumed = false;
1383 if (i < AttributeCount) {
1384 this.currentDefaultAttribute = i - reader.AttributeCount;
1385 this.defaultAttributeConsumed = false;
1388 throw new ArgumentOutOfRangeException ("i", i, "Attribute index is out of range.");
1391 public override bool MoveToAttribute (string name)
1393 switch (reader.NodeType) {
1394 case XmlNodeType.XmlDeclaration:
1395 case XmlNodeType.DocumentType:
1396 return reader.MoveToAttribute (name);
1399 currentAttrType = null;
1400 bool b = reader.MoveToAttribute (name);
1402 this.currentDefaultAttribute = -1;
1403 this.defaultAttributeConsumed = false;
1407 return MoveToDefaultAttribute (name, null);
1410 public override bool MoveToAttribute (string localName, string ns)
1412 switch (reader.NodeType) {
1413 case XmlNodeType.XmlDeclaration:
1414 case XmlNodeType.DocumentType:
1415 return reader.MoveToAttribute (localName, ns);
1418 currentAttrType = null;
1419 bool b = reader.MoveToAttribute (localName, ns);
1421 this.currentDefaultAttribute = -1;
1422 this.defaultAttributeConsumed = false;
1426 return MoveToDefaultAttribute (localName, ns);
1429 private bool MoveToDefaultAttribute (string localName, string ns)
1431 int idx = this.FindDefaultAttribute (localName, ns);
1434 currentDefaultAttribute = idx;
1435 defaultAttributeConsumed = false;
1439 public override bool MoveToElement ()
1441 currentDefaultAttribute = -1;
1442 defaultAttributeConsumed = false;
1443 currentAttrType = null;
1444 return reader.MoveToElement ();
1447 public override bool MoveToFirstAttribute ()
1449 switch (reader.NodeType) {
1450 case XmlNodeType.XmlDeclaration:
1451 case XmlNodeType.DocumentType:
1452 return reader.MoveToFirstAttribute ();
1455 currentAttrType = null;
1456 if (reader.AttributeCount > 0) {
1457 bool b = reader.MoveToFirstAttribute ();
1459 currentDefaultAttribute = -1;
1460 defaultAttributeConsumed = false;
1465 if (this.defaultAttributes.Length > 0) {
1466 currentDefaultAttribute = 0;
1467 defaultAttributeConsumed = false;
1474 public override bool MoveToNextAttribute ()
1476 switch (reader.NodeType) {
1477 case XmlNodeType.XmlDeclaration:
1478 case XmlNodeType.DocumentType:
1479 return reader.MoveToNextAttribute ();
1482 currentAttrType = null;
1483 if (currentDefaultAttribute >= 0) {
1484 if (defaultAttributes.Length == currentDefaultAttribute + 1)
1486 currentDefaultAttribute++;
1487 defaultAttributeConsumed = false;
1491 bool b = reader.MoveToNextAttribute ();
1493 currentDefaultAttribute = -1;
1494 defaultAttributeConsumed = false;
1498 if (defaultAttributes.Length > 0) {
1499 currentDefaultAttribute = 0;
1500 defaultAttributeConsumed = false;
1507 private XmlSchema ReadExternalSchema (string uri)
1509 Uri absUri = resolver.ResolveUri ((BaseURI != "" ? new Uri (BaseURI) : null), uri);
1510 XmlTextReader xtr = null;
1512 xtr = new XmlTextReader (absUri.ToString (),
1513 (Stream) resolver.GetEntity (
1514 absUri, null, typeof (Stream)),
1516 return XmlSchema.Read (
1517 xtr, ValidationEventHandler);
1524 private void ExamineAdditionalSchema ()
1526 if (resolver == null)
1528 XmlSchema schema = null;
1529 string schemaLocation = reader.GetAttribute ("schemaLocation", XmlSchema.InstanceNamespace);
1530 bool schemaAdded = false;
1531 if (schemaLocation != null) {
1532 string [] tmp = null;
1534 schemaLocation = XsDatatype.FromName ("token", XmlSchema.Namespace).Normalize (schemaLocation);
1535 tmp = schemaLocation.Split (XmlChar.WhitespaceChars);
1536 } catch (Exception ex) {
1537 HandleError ("Invalid schemaLocation attribute format.", ex, true);
1538 tmp = new string [0];
1540 if (tmp.Length % 2 != 0)
1541 HandleError ("Invalid schemaLocation attribute format.");
1542 for (int i = 0; i < tmp.Length; i += 2) {
1544 schema = ReadExternalSchema (tmp [i + 1]);
1545 } catch (Exception) { // FIXME: (wishlist) It is bad manner ;-(
1546 HandleError ("Could not resolve schema location URI: " + tmp [i + 1], null, true);
1549 if (schema.TargetNamespace == null)
1550 schema.TargetNamespace = tmp [i];
1551 else if (schema.TargetNamespace != tmp [i])
1552 HandleError ("Specified schema has different target namespace.");
1555 if (schema != null) {
1556 if (!schemas.Contains (schema.TargetNamespace)) {
1558 schemas.Add (schema);
1562 string noNsSchemaLocation = reader.GetAttribute ("noNamespaceSchemaLocation", XmlSchema.InstanceNamespace);
1563 if (noNsSchemaLocation != null) {
1565 schema = ReadExternalSchema (noNsSchemaLocation);
1566 } catch (Exception) { // FIXME: (wishlist) It is bad manner ;-(
1567 HandleError ("Could not resolve schema location URI: " + noNsSchemaLocation, null, true);
1569 if (schema != null && schema.TargetNamespace != null)
1570 HandleError ("Specified schema has different target namespace.");
1572 if (schema != null) {
1573 if (!schemas.Contains (schema.TargetNamespace)) {
1575 schemas.Add (schema);
1578 // FIXME: should call Reprocess()?
1583 public override bool Read ()
1585 currentDefaultAttribute = -1;
1586 defaultAttributeConsumed = false;
1587 currentAttrType = null;
1588 #region ID Constraints
1589 if (this.checkIdentity)
1590 idManager.OnStartElement ();
1592 defaultAttributes = emptyAttributeArray;
1594 bool result = reader.Read ();
1595 #region ID Constraints
1596 // 3.3.4 ElementLocallyValidElement 7 = Root Valid.
1597 if (!result && this.checkIdentity &&
1598 idManager.HasMissingIDReferences ())
1599 HandleError ("There are missing ID references: " + idManager.GetMissingIDString ());
1602 // FIXME: schemaLocation could be specified
1604 if (reader.Depth == 0 &&
1605 reader.NodeType == XmlNodeType.Element)
1606 ExamineAdditionalSchema ();
1607 if (schemas.Count == 0)
1609 if (!schemas.IsCompiled)
1612 switch (reader.NodeType) {
1613 case XmlNodeType.Element:
1614 #region Key Constraints
1615 if (checkKeyConstraints)
1616 this.elementQNameStack.Add (new QName (reader.LocalName, reader.NamespaceURI));
1619 // If there is no schema information, then no validation is performed.
1620 if (skipValidationDepth < 0 || reader.Depth <= skipValidationDepth) {
1621 ValidateEndSimpleContent ();
1622 AssessStartElementSchemaValidity ();
1625 if (reader.IsEmptyElement)
1626 goto case XmlNodeType.EndElement;
1628 shouldValidateCharacters = true;
1630 case XmlNodeType.EndElement:
1631 if (reader.Depth == skipValidationDepth)
1632 skipValidationDepth = -1;
1633 else if (skipValidationDepth < 0 || reader.Depth <= skipValidationDepth)
1634 AssessEndElementSchemaValidity ();
1636 if (checkKeyConstraints)
1637 elementQNameStack.RemoveAt (elementQNameStack.Count - 1);
1640 case XmlNodeType.CDATA:
1641 case XmlNodeType.SignificantWhitespace:
1642 case XmlNodeType.Text:
1643 // FIXME: does this check make sense?
1644 ComplexType ct = Context.ActualType as ComplexType;
1645 if (ct != null && storedCharacters.Length > 0) {
1646 switch (ct.ContentType) {
1647 case XmlSchemaContentType.ElementOnly:
1648 case XmlSchemaContentType.Empty:
1649 HandleError ("Not allowed character content was found.");
1654 ValidateCharacters ();
1661 public override bool ReadAttributeValue ()
1663 if (currentDefaultAttribute < 0)
1664 return reader.ReadAttributeValue ();
1666 if (this.defaultAttributeConsumed)
1669 defaultAttributeConsumed = true;
1674 public override string ReadInnerXml ()
1676 // MS.NET 1.0 has a serious bug here. It skips validation.
1677 return reader.ReadInnerXml ();
1680 public override string ReadOuterXml ()
1682 // MS.NET 1.0 has a serious bug here. It skips validation.
1683 return reader.ReadOuterXml ();
1687 // XmlReader.ReadString() should call derived this.Read().
1688 public override string ReadString ()
1691 return reader.ReadString ();
1693 return base.ReadString ();
1697 // This class itself does not have this feature.
1698 public override void ResolveEntity ()
1700 reader.ResolveEntity ();
1704 internal class XsdValidationContext
1706 public XsdValidationContext ()
1710 // Some of them might be missing (See the spec section 5.3, and also 3.3.4).
1711 public XsElement Element;
1712 public object XsiType; // xsi:type
1713 internal XsdValidationState State;
1715 // Note that it represents current element's type.
1716 public object ActualType {
1718 if (XsiType != null)
1721 return Element != null ? Element.ElementType : null;
1726 public XmlSchemaType ActualSchemaType {
1728 object at = ActualType;
1731 XmlSchemaType st = at as XmlSchemaType;
1733 st = XmlSchemaType.GetBuiltInSimpleType (
1734 ((XmlSchemaDatatype) at).TypeCode);
1740 public bool IsInvalid {
1741 get { return State == XsdValidationState.Invalid; }
1744 public object Clone ()
1746 return MemberwiseClone ();
1749 public void EvaluateStartElement (
1750 string localName, string ns)
1752 State = State.EvaluateStartElement (localName, ns);
1755 public bool EvaluateEndElement ()
1757 return State.EvaluateEndElement ();
1760 public void SetElement (XsElement element)
1766 internal class XsdIDManager
1768 public XsdIDManager ()
1772 Hashtable idList = new Hashtable ();
1773 ArrayList missingIDReferences;
1774 string thisElementId;
1776 private ArrayList MissingIDReferences {
1778 if (missingIDReferences == null)
1779 missingIDReferences = new ArrayList ();
1780 return missingIDReferences;
1784 public void OnStartElement ()
1786 thisElementId = null;
1790 public string AssessEachAttributeIdentityConstraint (
1791 XsDatatype dt, object parsedValue, string elementName)
1793 // Validate identity constraints.
1794 string str = parsedValue as string;
1795 switch (dt.TokenizedType) {
1796 case XmlTokenizedType.ID:
1797 if (thisElementId != null)
1798 return "ID type attribute was already assigned in the containing element.";
1800 thisElementId = str;
1801 if (idList.ContainsKey (str))
1802 return "Duplicate ID value was found.";
1804 idList.Add (str, elementName);
1805 if (MissingIDReferences.Contains (str))
1806 MissingIDReferences.Remove (str);
1808 case XmlTokenizedType.IDREF:
1809 if (!idList.Contains (str))
1810 MissingIDReferences.Add (str);
1812 case XmlTokenizedType.IDREFS:
1813 string [] idrefs = (string []) parsedValue;
1814 for (int i = 0; i < idrefs.Length; i++) {
1815 string id = idrefs [i];
1816 if (!idList.Contains (id))
1817 MissingIDReferences.Add (id);
1824 public object FindID (string name)
1826 return idList [name];
1829 public bool HasMissingIDReferences ()
1831 return missingIDReferences != null
1832 && missingIDReferences.Count > 0;
1835 public string GetMissingIDString ()
1837 return String.Join (" ",
1838 MissingIDReferences.ToArray (typeof (string))