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;
33 using System.Collections.Generic;
35 using System.Collections.Specialized;
39 using System.Xml.Schema;
43 using ValException = System.Xml.Schema.XmlSchemaValidationException;
45 using ValException = System.Xml.Schema.XmlSchemaException;
48 using QName = System.Xml.XmlQualifiedName;
49 using ContentProc = System.Xml.Schema.XmlSchemaContentProcessing;
50 using XsElement = System.Xml.Schema.XmlSchemaElement;
51 using XsAttribute = System.Xml.Schema.XmlSchemaAttribute;
52 using ComplexType = System.Xml.Schema.XmlSchemaComplexType;
53 using SimpleType = System.Xml.Schema.XmlSchemaSimpleType;
54 using SimpleTypeRest = System.Xml.Schema.XmlSchemaSimpleTypeRestriction;
55 using SimpleTypeList = System.Xml.Schema.XmlSchemaSimpleTypeList;
56 using SimpleTypeUnion = System.Xml.Schema.XmlSchemaSimpleTypeUnion;
57 using XsDatatype = System.Xml.Schema.XmlSchemaDatatype;
59 namespace Mono.Xml.Schema
61 internal class XsdValidatingReader : XmlReader, IXmlLineInfo, IHasXmlSchemaInfo, IHasXmlParserContext, IXmlNamespaceResolver
63 static readonly XsAttribute [] emptyAttributeArray =
68 IHasXmlSchemaInfo sourceReaderSchemaInfo;
69 IXmlLineInfo readerLineInfo;
70 ValidationType validationType;
71 XmlSchemaSet schemas = new XmlSchemaSet ();
72 bool namespaces = true;
74 #region ID Constraints
75 bool checkIdentity = true;
76 XsdIDManager idManager = new XsdIDManager ();
79 #region Key Constraints
80 bool checkKeyConstraints = true;
81 ArrayList keyTables = new ArrayList ();
82 ArrayList currentKeyFieldConsumers;
83 ArrayList tmpKeyrefPool;
85 ArrayList elementQNameStack = new ArrayList ();
87 XsdParticleStateManager state = new XsdParticleStateManager ();
89 int skipValidationDepth = -1;
91 StringBuilder storedCharacters = new StringBuilder ();
92 bool shouldValidateCharacters;
94 XsAttribute [] defaultAttributes = emptyAttributeArray;
95 int currentDefaultAttribute = -1;
96 ArrayList defaultAttributesCache = new ArrayList ();
97 bool defaultAttributeConsumed;
98 object currentAttrType;
101 public XsdValidatingReader (XmlReader reader)
103 this.reader = reader;
104 readerLineInfo = reader as IXmlLineInfo;
105 sourceReaderSchemaInfo = reader as IHasXmlSchemaInfo;
106 schemas.ValidationEventHandler += ValidationEventHandler;
110 public ValidationEventHandler ValidationEventHandler;
112 // Private Properties
114 private XsdValidationContext Context {
115 get { return state.Context; }
118 #region Key Constraints
119 internal ArrayList CurrentKeyFieldConsumers {
121 if (currentKeyFieldConsumers == null)
122 currentKeyFieldConsumers = new ArrayList ();
123 return currentKeyFieldConsumers;
128 // Public Non-overrides
130 public int XsiNilDepth {
131 get { return xsiNilDepth; }
134 public bool Namespaces {
135 get { return namespaces; }
136 set { namespaces = value; }
139 // This is required to resolve xsi:schemaLocation
140 public XmlResolver XmlResolver {
146 // This should be changed before the first Read() call.
147 public XmlSchemaSet Schemas {
148 get { return schemas; }
150 if (ReadState != ReadState.Initial)
151 throw new InvalidOperationException ("Schemas must be set before the first call to Read().");
156 public object SchemaType {
158 if (ReadState != ReadState.Interactive)
162 case XmlNodeType.Element:
163 if (Context.ActualType != null)
164 return Context.ActualType;
166 return SourceReaderSchemaType;
167 case XmlNodeType.Attribute:
168 if (currentAttrType == null) {
169 ComplexType ct = Context.ActualType as ComplexType;
171 XsAttribute attdef = ct.AttributeUses [new QName (LocalName, NamespaceURI)] as XsAttribute;
173 currentAttrType = attdef.AttributeType;
174 return currentAttrType;
176 currentAttrType = SourceReaderSchemaType;
178 return currentAttrType;
180 return SourceReaderSchemaType;
185 private object SourceReaderSchemaType {
186 get { return this.sourceReaderSchemaInfo != null ? sourceReaderSchemaInfo.SchemaType : null; }
189 public ValidationType ValidationType {
190 get { return validationType; }
192 if (ReadState != ReadState.Initial)
193 throw new InvalidOperationException ("ValidationType must be set before reading.");
194 validationType = value;
199 IDictionary<string, string>
203 IXmlNamespaceResolver.GetNamespacesInScope (XmlNamespaceScope scope)
205 IXmlNamespaceResolver resolver = reader as IXmlNamespaceResolver;
206 if (resolver == null)
207 throw new NotSupportedException ("The input XmlReader does not implement IXmlNamespaceResolver and thus this validating reader cannot collect in-scope namespaces.");
208 return resolver.GetNamespacesInScope (scope);
211 string IXmlNamespaceResolver.LookupPrefix (string ns)
213 IXmlNamespaceResolver resolver = reader as IXmlNamespaceResolver;
214 if (resolver == null)
215 throw new NotSupportedException ("The input XmlReader does not implement IXmlNamespaceResolver and thus this validating reader cannot execute namespace prefix lookup.");
216 return resolver.LookupPrefix (ns);
219 // It is used only for independent XmlReader use, not for XmlValidatingReader.
222 public override object ReadTypedValue ()
224 public object ReadTypedValue ()
227 object o = XmlSchemaUtil.ReadTypedValue (this,
228 SchemaType, ParserContext.NamespaceManager,
230 storedCharacters.Length = 0;
234 // Public Overriden Properties
236 public override int AttributeCount {
238 return reader.AttributeCount + defaultAttributes.Length;
242 public override string BaseURI {
243 get { return reader.BaseURI; }
246 // If this class is used to implement XmlValidatingReader,
247 // it should be left to DTDValidatingReader. In other cases,
248 // it depends on the reader's ability.
249 public override bool CanResolveEntity {
250 get { return reader.CanResolveEntity; }
253 public override int Depth {
255 if (currentDefaultAttribute < 0)
257 if (this.defaultAttributeConsumed)
258 return reader.Depth + 2;
259 return reader.Depth + 1;
263 public override bool EOF {
264 get { return reader.EOF; }
267 public override bool HasValue {
269 if (currentDefaultAttribute < 0)
270 return reader.HasValue;
275 public override bool IsDefault {
277 if (currentDefaultAttribute < 0)
278 return reader.IsDefault;
283 public override bool IsEmptyElement {
285 if (currentDefaultAttribute < 0)
286 return reader.IsEmptyElement;
291 public override string this [int i] {
292 get { return GetAttribute (i); }
295 public override string this [string name] {
296 get { return GetAttribute (name); }
299 public override string this [string localName, string ns] {
300 get { return GetAttribute (localName, ns); }
303 public int LineNumber {
304 get { return readerLineInfo != null ? readerLineInfo.LineNumber : 0; }
307 public int LinePosition {
308 get { return readerLineInfo != null ? readerLineInfo.LinePosition : 0; }
311 public override string LocalName {
313 if (currentDefaultAttribute < 0)
314 return reader.LocalName;
315 if (defaultAttributeConsumed)
317 return defaultAttributes [currentDefaultAttribute].QualifiedName.Name;
321 public override string Name {
323 if (currentDefaultAttribute < 0)
325 if (defaultAttributeConsumed)
328 QName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
329 string prefix = Prefix;
330 if (prefix == String.Empty)
333 return String.Concat (prefix, ":", qname.Name);
337 public override string NamespaceURI {
339 if (currentDefaultAttribute < 0)
340 return reader.NamespaceURI;
341 if (defaultAttributeConsumed)
343 return defaultAttributes [currentDefaultAttribute].QualifiedName.Namespace;
347 public override XmlNameTable NameTable {
348 get { return reader.NameTable; }
351 public override XmlNodeType NodeType {
353 if (currentDefaultAttribute < 0)
354 return reader.NodeType;
355 if (defaultAttributeConsumed)
356 return XmlNodeType.Text;
357 return XmlNodeType.Attribute;
361 public XmlParserContext ParserContext {
362 get { return XmlSchemaUtil.GetParserContext (reader); }
365 public override string Prefix {
367 if (currentDefaultAttribute < 0)
368 return reader.Prefix;
369 if (defaultAttributeConsumed)
371 QName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
372 string prefix = this.ParserContext.NamespaceManager.LookupPrefix (qname.Namespace, false);
380 public override char QuoteChar {
381 get { return reader.QuoteChar; }
384 public override ReadState ReadState {
385 get { return reader.ReadState; }
388 public override string Value {
390 if (currentDefaultAttribute < 0)
392 string value = defaultAttributes [currentDefaultAttribute].ValidatedDefaultValue;
394 value = defaultAttributes [currentDefaultAttribute].ValidatedFixedValue;
399 public override string XmlLang {
401 string xmlLang = reader.XmlLang;
404 int idx = this.FindDefaultAttribute ("lang", XmlNamespaceManager.XmlnsXml);
407 xmlLang = defaultAttributes [idx].ValidatedDefaultValue;
409 xmlLang = defaultAttributes [idx].ValidatedFixedValue;
414 public override XmlSpace XmlSpace {
416 XmlSpace space = reader.XmlSpace;
417 if (space != XmlSpace.None)
419 int idx = this.FindDefaultAttribute ("space", XmlNamespaceManager.XmlnsXml);
421 return XmlSpace.None;
422 string spaceSpec = defaultAttributes [idx].ValidatedDefaultValue;
423 if (spaceSpec == null)
424 spaceSpec = defaultAttributes [idx].ValidatedFixedValue;
425 return (XmlSpace) Enum.Parse (typeof (XmlSpace), spaceSpec, false);
431 private void HandleError (string error)
433 HandleError (error, null);
436 private void HandleError (string error, Exception innerException)
438 HandleError (error, innerException, false);
441 private void HandleError (string error, Exception innerException, bool isWarning)
443 if (ValidationType == ValidationType.None) // extra quick check
446 ValException schemaException = new ValException (error,
447 this, this.BaseURI, null, innerException);
448 HandleError (schemaException, isWarning);
451 private void HandleError (ValException schemaException)
453 HandleError (schemaException, false);
456 private void HandleError (ValException schemaException, bool isWarning)
458 if (ValidationType == ValidationType.None)
461 ValidationEventArgs e = new ValidationEventArgs (schemaException,
462 schemaException.Message, isWarning ? XmlSeverityType.Warning : XmlSeverityType.Error);
464 if (ValidationEventHandler != null)
465 ValidationEventHandler (this, e);
467 else if (e.Severity == XmlSeverityType.Error)
471 private XsElement FindElement (string name, string ns)
473 return (XsElement) schemas.GlobalElements [new QName (name, ns)];
476 private XmlSchemaType FindType (QName qname)
478 return (XmlSchemaType) schemas.GlobalTypes [qname];
481 private void ValidateStartElementParticle ()
483 if (Context.State == null)
485 Context.XsiType = null;
486 state.CurrentElement = null;
487 Context.EvaluateStartElement (reader.LocalName,
488 reader.NamespaceURI);
489 if (Context.IsInvalid)
490 HandleError ("Invalid start element: " + reader.NamespaceURI + ":" + reader.LocalName);
492 Context.SetElement (state.CurrentElement);
495 private void ValidateEndElementParticle ()
497 if (Context.State != null) {
498 if (!Context.EvaluateEndElement ()) {
499 HandleError ("Invalid end element: " + reader.Name);
505 // Utility for missing validation completion related to child items.
506 private void ValidateCharacters ()
508 if (xsiNilDepth >= 0 && xsiNilDepth < reader.Depth)
509 HandleError ("Element item appeared, while current element context is nil.");
511 if (shouldValidateCharacters)
512 storedCharacters.Append (reader.Value);
515 // Utility for missing validation completion related to child items.
516 private void ValidateEndSimpleContent ()
518 if (shouldValidateCharacters)
519 ValidateEndSimpleContentCore ();
520 shouldValidateCharacters = false;
521 storedCharacters.Length = 0;
524 private void ValidateEndSimpleContentCore ()
526 if (Context.ActualType == null)
529 string value = storedCharacters.ToString ();
531 if (value.Length == 0) {
532 // 3.3.4 Element Locally Valid (Element) 5.1.2
533 if (Context.Element != null) {
534 if (Context.Element.ValidatedDefaultValue != null)
535 value = Context.Element.ValidatedDefaultValue;
539 XsDatatype dt = Context.ActualType as XsDatatype;
540 SimpleType st = Context.ActualType as SimpleType;
545 ComplexType ct = Context.ActualType as ComplexType;
547 switch (ct.ContentType) {
548 case XmlSchemaContentType.ElementOnly:
549 case XmlSchemaContentType.Empty:
550 if (value.Length > 0)
551 HandleError ("Character content not allowed.");
557 // 3.3.4 Element Locally Valid (Element) :: 5.2.2.2. Fixed value constraints
558 if (Context.Element != null && Context.Element.ValidatedFixedValue != null)
559 if (value != Context.Element.ValidatedFixedValue)
560 HandleError ("Fixed value constraint was not satisfied.");
561 AssessStringValid (st, dt, value);
564 #region Key Constraints
565 if (checkKeyConstraints)
566 ValidateSimpleContentIdentity (dt, value);
569 shouldValidateCharacters = false;
572 // 3.14.4 String Valid
573 private void AssessStringValid (SimpleType st,
574 XsDatatype dt, string value)
576 XsDatatype validatedDatatype = dt;
578 string normalized = validatedDatatype.Normalize (value);
580 XsDatatype itemDatatype;
581 SimpleType itemSimpleType;
582 switch (st.DerivedBy) {
583 case XmlSchemaDerivationMethod.List:
584 SimpleTypeList listContent = st.Content as SimpleTypeList;
585 values = normalized.Split (XmlChar.WhitespaceChars);
586 itemDatatype = listContent.ValidatedListItemType as XsDatatype;
587 itemSimpleType = listContent.ValidatedListItemType as SimpleType;
588 for (int vi = 0; vi < values.Length; vi++) {
589 string each = values [vi];
590 if (each == String.Empty)
592 // validate against ValidatedItemType
593 if (itemDatatype != null) {
595 itemDatatype.ParseValue (each, NameTable, ParserContext.NamespaceManager);
596 } catch (Exception ex) { // FIXME: (wishlist) better exception handling ;-(
597 HandleError ("List type value contains one or more invalid values.", ex);
602 AssessStringValid (itemSimpleType, itemSimpleType.Datatype, each);
605 case XmlSchemaDerivationMethod.Union:
606 SimpleTypeUnion union = st.Content as SimpleTypeUnion;
608 string each = normalized;
609 // validate against ValidatedItemType
611 foreach (object eachType in union.ValidatedTypes) {
612 itemDatatype = eachType as XsDatatype;
613 itemSimpleType = eachType as SimpleType;
614 if (itemDatatype != null) {
616 itemDatatype.ParseValue (each, NameTable, ParserContext.NamespaceManager);
617 } catch (Exception) { // FIXME: (wishlist) better exception handling ;-(
623 AssessStringValid (itemSimpleType, itemSimpleType.Datatype, each);
624 } catch (ValException) {
632 HandleError ("Union type value contains one or more invalid values.");
637 case XmlSchemaDerivationMethod.Restriction:
638 SimpleTypeRest str = st.Content as SimpleTypeRest;
641 /* Don't forget to validate against inherited type's facets
642 * Could we simplify this by assuming that the basetype will also
645 // mmm, will check later.
646 SimpleType baseType = st.BaseXmlSchemaType as SimpleType;
647 if (baseType != null) {
648 AssessStringValid(baseType, dt, normalized);
650 if (!str.ValidateValueWithFacets (normalized, NameTable)) {
651 HandleError ("Specified value was invalid against the facets.");
655 validatedDatatype = st.Datatype;
659 if (validatedDatatype != null) {
661 validatedDatatype.ParseValue (value, NameTable, ParserContext.NamespaceManager);
662 } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
663 HandleError ("Invalidly typed data was specified.", ex);
668 private object GetXsiType (string name)
670 object xsiType = null;
671 QName typeQName = QName.Parse (name, this);
672 if (typeQName == ComplexType.AnyTypeName)
673 xsiType = ComplexType.AnyType;
674 else if (XmlSchemaUtil.IsBuiltInDatatypeName (typeQName))
675 xsiType = XsDatatype.FromName (typeQName);
677 xsiType = FindType (typeQName);
681 // It is common to ElementLocallyValid::4 and SchemaValidityAssessment::1.2.1.2.4
682 private void AssessLocalTypeDerivationOK (object xsiType, object baseType, XmlSchemaDerivationMethod flag)
684 XmlSchemaType xsiSchemaType = xsiType as XmlSchemaType;
685 ComplexType baseComplexType = baseType as ComplexType;
686 ComplexType xsiComplexType = xsiSchemaType as ComplexType;
687 if (xsiType != baseType) {
688 // Extracted (not extraneous) check for 3.4.6 TypeDerivationOK.
689 if (baseComplexType != null)
690 flag |= baseComplexType.BlockResolved;
691 if (flag == XmlSchemaDerivationMethod.All) {
692 HandleError ("Prohibited element type substitution.");
694 } else if (xsiSchemaType != null && (flag & xsiSchemaType.DerivedBy) != 0) {
695 HandleError ("Prohibited element type substitution.");
700 if (xsiComplexType != null)
702 xsiComplexType.ValidateTypeDerivationOK (baseType, null, null);
703 } catch (ValException ex) {
704 // HandleError ("Locally specified schema complex type derivation failed. " + ex.Message, ex);
708 SimpleType xsiSimpleType = xsiType as SimpleType;
709 if (xsiSimpleType != null) {
711 xsiSimpleType.ValidateTypeDerivationOK (baseType, null, null, true);
712 } catch (ValException ex) {
713 // HandleError ("Locally specified schema simple type derivation failed. " + ex.Message, ex);
717 else if (xsiType is XsDatatype) {
721 HandleError ("Primitive data type cannot be derived type using xsi:type specification.");
725 // Section 3.3.4 of the spec.
726 private void AssessStartElementSchemaValidity ()
728 // If the reader is inside xsi:nil (and failed
729 // on validation), then simply skip its content.
730 if (xsiNilDepth >= 0 && xsiNilDepth < reader.Depth)
731 HandleError ("Element item appeared, while current element context is nil.");
733 ValidateStartElementParticle ();
735 string xsiNilValue = reader.GetAttribute ("nil", XmlSchema.InstanceNamespace);
736 if (xsiNilValue != null)
737 xsiNilValue = xsiNilValue.Trim (XmlChar.WhitespaceChars);
738 bool isXsiNil = xsiNilValue == "true";
739 if (isXsiNil && this.xsiNilDepth < 0)
740 xsiNilDepth = reader.Depth;
742 // [Schema Validity Assessment (Element) 1.2]
743 // Evaluate "local type definition" from xsi:type.
744 // (See spec 3.3.4 Schema Validity Assessment (Element) 1.2.1.2.3.
745 // Note that Schema Validity Assessment(Element) 1.2 takes
746 // precedence than 1.1 of that.
748 string xsiTypeName = reader.GetAttribute ("type", XmlSchema.InstanceNamespace);
749 if (xsiTypeName != null) {
750 xsiTypeName = xsiTypeName.Trim (XmlChar.WhitespaceChars);
751 object xsiType = GetXsiType (xsiTypeName);
753 HandleError ("The instance type was not found: " + xsiTypeName + " .");
755 XmlSchemaType xsiSchemaType = xsiType as XmlSchemaType;
756 if (xsiSchemaType != null && this.Context.Element != null) {
757 XmlSchemaType elemBaseType = Context.Element.ElementType as XmlSchemaType;
758 if (elemBaseType != null && (xsiSchemaType.DerivedBy & elemBaseType.FinalResolved) != 0)
759 HandleError ("The instance type is prohibited by the type of the context element.");
760 if (elemBaseType != xsiType && (xsiSchemaType.DerivedBy & this.Context.Element.BlockResolved) != 0)
761 HandleError ("The instance type is prohibited by the context element.");
763 ComplexType xsiComplexType = xsiType as ComplexType;
764 if (xsiComplexType != null && xsiComplexType.IsAbstract)
765 HandleError ("The instance type is abstract: " + xsiTypeName + " .");
767 // If current schema type exists, then this xsi:type must be
768 // valid extension of that type. See 1.2.1.2.4.
769 if (Context.Element != null) {
770 AssessLocalTypeDerivationOK (xsiType, Context.Element.ElementType, Context.Element.BlockResolved);
772 AssessStartElementLocallyValidType (xsiType); // 1.2.2:
773 Context.XsiType = xsiType;
778 // Create Validation Root, if not exist.
779 // [Schema Validity Assessment (Element) 1.1]
780 if (Context.Element == null) {
781 state.CurrentElement = FindElement (reader.LocalName, reader.NamespaceURI);
782 Context.SetElement (state.CurrentElement);
784 if (Context.Element != null) {
785 if (Context.XsiType == null) {
786 AssessElementLocallyValidElement (xsiNilValue); // 1.1.2
789 switch (state.ProcessContents) {
790 case ContentProc.Skip:
792 case ContentProc.Lax:
795 if (xsiTypeName == null &&
796 (schemas.Contains (reader.NamespaceURI) ||
797 !schemas.MissedSubComponents (reader.NamespaceURI)))
798 HandleError ("Element declaration for " + new QName (reader.LocalName, reader.NamespaceURI) + " is missing.");
803 state.PushContext ();
805 XsdValidationState next = null;
806 if (state.ProcessContents == ContentProc.Skip)
807 skipValidationDepth = reader.Depth;
809 // create child particle state.
810 ComplexType xsComplexType = SchemaType as ComplexType;
811 if (xsComplexType != null)
812 next = state.Create (xsComplexType.ValidatableParticle);
813 else if (state.ProcessContents == ContentProc.Lax)
814 next = state.Create (XmlSchemaAny.AnyTypeContent);
816 next = state.Create (XmlSchemaParticle.Empty);
818 Context.State = next;
820 #region Key Constraints
821 if (checkKeyConstraints) {
822 ValidateKeySelectors ();
823 ValidateKeyFields ();
829 // 3.3.4 Element Locally Valid (Element)
830 private void AssessElementLocallyValidElement (string xsiNilValue)
832 XsElement element = Context.Element;
833 QName qname = new QName (reader.LocalName, reader.NamespaceURI);
836 HandleError ("Element declaration is required for " + qname);
838 if (element.ActualIsAbstract)
839 HandleError ("Abstract element declaration was specified for " + qname);
841 if (!element.ActualIsNillable && xsiNilValue != null)
842 HandleError ("This element declaration is not nillable: " + qname);
844 // Note that 3.2.1 xsi:nil constraints are to be
845 // validated in AssessElementSchemaValidity() and
846 // ValidateCharacters().
847 else if (xsiNilValue == "true") {
848 if (element.ValidatedFixedValue != null)
849 HandleError ("Schema instance nil was specified, where the element declaration for " + qname + "has fixed value constraints.");
851 // 4. xsi:type (it takes precedence than element type)
852 string xsiType = reader.GetAttribute ("type", XmlSchema.InstanceNamespace);
853 if (xsiType != null) {
854 Context.XsiType = GetXsiType (xsiType);
855 AssessLocalTypeDerivationOK (Context.XsiType, element.ElementType, element.BlockResolved);
858 Context.XsiType = null;
860 // 5 Not all things cannot be assessed here.
861 // It is common to 5.1 and 5.2
862 if (element.ElementType != null)
863 AssessStartElementLocallyValidType (SchemaType);
865 // 6. should be out from here.
866 // See invokation of AssessStartIdentityConstraints().
868 // 7 is going to be validated in Read() (in case of xmlreader's EOF).
871 // 3.3.4 Element Locally Valid (Type)
872 private void AssessStartElementLocallyValidType (object schemaType)
874 if (schemaType == null) { // 1.
875 HandleError ("Schema type does not exist.");
878 ComplexType cType = schemaType as ComplexType;
879 SimpleType sType = schemaType as SimpleType;
882 while (reader.MoveToNextAttribute ()) {
883 if (reader.NamespaceURI == XmlNamespaceManager.XmlnsXmlns)
885 if (reader.NamespaceURI != XmlSchema.InstanceNamespace)
886 HandleError ("Current simple type cannot accept attributes other than schema instance namespace.");
887 switch (reader.LocalName) {
890 case "schemaLocation":
891 case "noNamespaceSchemaLocation":
894 HandleError ("Unknown schema instance namespace attribute: " + reader.LocalName);
898 reader.MoveToElement ();
899 // 3.1.2 and 3.1.3 cannot be assessed here.
900 } else if (cType != null) {
901 if (cType.IsAbstract) { // 2.
902 HandleError ("Target complex type is abstract.");
906 AssessElementLocallyValidComplexType (cType);
910 // 3.4.4 Element Locally Valid (Complex Type)
911 private void AssessElementLocallyValidComplexType (ComplexType cType)
914 if (cType.IsAbstract)
915 HandleError ("Target complex type is abstract.");
917 // 2 (xsi:nil and content prohibition)
918 // See AssessStartElementSchemaValidity() and ValidateCharacters()
920 // 3. attribute uses and
922 if (reader.MoveToFirstAttribute ()) {
924 switch (reader.NamespaceURI) {
925 case"http://www.w3.org/2000/xmlns/":
926 case XmlSchema.InstanceNamespace:
929 QName qname = new QName (reader.LocalName, reader.NamespaceURI);
930 // including 3.10.4 Item Valid (Wildcard)
931 XmlSchemaObject attMatch = XmlSchemaUtil.FindAttributeDeclaration (reader.NamespaceURI, schemas, cType, qname);
932 if (attMatch == null)
933 HandleError ("Attribute declaration was not found for " + qname);
934 XsAttribute attdecl = attMatch as XsAttribute;
935 if (attdecl != null) {
936 AssessAttributeLocallyValidUse (attdecl);
937 AssessAttributeLocallyValid (attdecl);
938 } // otherwise anyAttribute or null.
939 } while (reader.MoveToNextAttribute ());
940 reader.MoveToElement ();
943 // Collect default attributes.
945 foreach (DictionaryEntry entry in cType.AttributeUses) {
946 XsAttribute attr = (XsAttribute) entry.Value;
947 if (reader [attr.QualifiedName.Name, attr.QualifiedName.Namespace] == null) {
948 if (attr.ValidatedUse == XmlSchemaUse.Required &&
949 attr.ValidatedFixedValue == null)
950 HandleError ("Required attribute " + attr.QualifiedName + " was not found.");
951 else if (attr.ValidatedDefaultValue != null || attr.ValidatedFixedValue != null)
952 defaultAttributesCache.Add (attr);
955 if (defaultAttributesCache.Count == 0)
956 defaultAttributes = emptyAttributeArray;
958 defaultAttributes = (XsAttribute [])
959 defaultAttributesCache.ToArray (
960 typeof (XsAttribute));
961 defaultAttributesCache.Clear ();
962 // 5. wild IDs was already checked above.
965 // 3.2.4 Attribute Locally Valid and 3.4.4
966 private void AssessAttributeLocallyValid (XsAttribute attr)
969 if (attr.AttributeType == null)
970 HandleError ("Attribute type is missing for " + attr.QualifiedName);
971 XsDatatype dt = attr.AttributeType as XsDatatype;
973 dt = ((SimpleType) attr.AttributeType).Datatype;
974 // It is a bit heavy process, so let's omit as long as possible ;-)
975 if (dt != SimpleType.AnySimpleType || attr.ValidatedFixedValue != null) {
976 string normalized = dt.Normalize (reader.Value);
977 object parsedValue = null;
979 parsedValue = dt.ParseValue (normalized, reader.NameTable, this.ParserContext.NamespaceManager);
980 } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
981 HandleError ("Attribute value is invalid against its data type " + dt.TokenizedType, ex);
983 if (attr.ValidatedFixedValue != null && attr.ValidatedFixedValue != normalized) {
984 HandleError ("The value of the attribute " + attr.QualifiedName + " does not match with its fixed value.");
985 parsedValue = dt.ParseValue (attr.ValidatedFixedValue, reader.NameTable, this.ParserContext.NamespaceManager);
987 #region ID Constraints
988 if (this.checkIdentity) {
989 string error = idManager.AssessEachAttributeIdentityConstraint (dt, parsedValue, ((QName) elementQNameStack [elementQNameStack.Count - 1]).Name);
997 private void AssessAttributeLocallyValidUse (XsAttribute attr)
999 // This is extra check than spec 3.5.4
1000 if (attr.ValidatedUse == XmlSchemaUse.Prohibited)
1001 HandleError ("Attribute " + attr.QualifiedName + " is prohibited in this context.");
1004 private void AssessEndElementSchemaValidity ()
1006 ValidateEndElementParticle (); // validate against childrens' state.
1008 ValidateEndSimpleContent ();
1010 // 3.3.4 Assess ElementLocallyValidElement 5: value constraints.
1011 // 3.3.4 Assess ElementLocallyValidType 3.1.3. = StringValid(3.14.4)
1012 // => ValidateEndSimpleContent().
1014 #region Key Constraints
1015 if (checkKeyConstraints)
1016 ValidateEndElementKeyConstraints ();
1019 // Reset xsi:nil, if required.
1020 if (xsiNilDepth == reader.Depth)
1024 #region Key Constraints
1025 private void ValidateEndElementKeyConstraints ()
1027 // Reset Identity constraints.
1028 for (int i = 0; i < keyTables.Count; i++) {
1029 XsdKeyTable seq = this.keyTables [i] as XsdKeyTable;
1030 if (seq.StartDepth == reader.Depth) {
1031 EndIdentityValidation (seq);
1033 for (int k = 0; k < seq.Entries.Count; k++) {
1034 XsdKeyEntry entry = seq.Entries [k] as XsdKeyEntry;
1035 // Remove finished (maybe key not found) entries.
1036 if (entry.StartDepth == reader.Depth) {
1038 seq.FinishedEntries.Add (entry);
1039 else if (seq.SourceSchemaIdentity is XmlSchemaKey)
1040 HandleError ("Key sequence is missing.");
1041 seq.Entries.RemoveAt (k);
1044 // Pop validated key depth to find two or more fields.
1046 for (int j = 0; j < entry.KeyFields.Count; j++) {
1047 XsdKeyEntryField kf = entry.KeyFields [j];
1048 if (!kf.FieldFound && kf.FieldFoundDepth == reader.Depth) {
1049 kf.FieldFoundDepth = 0;
1050 kf.FieldFoundPath = null;
1057 for (int i = 0; i < keyTables.Count; i++) {
1058 XsdKeyTable seq = this.keyTables [i] as XsdKeyTable;
1059 if (seq.StartDepth == reader.Depth) {
1060 keyTables.RemoveAt (i);
1066 // 3.11.4 Identity Constraint Satisfied
1067 private void ValidateKeySelectors ()
1069 if (tmpKeyrefPool != null)
1070 tmpKeyrefPool.Clear ();
1071 if (Context.Element != null && Context.Element.Constraints.Count > 0) {
1072 // (a) Create new key sequences, if required.
1073 for (int i = 0; i < Context.Element.Constraints.Count; i++) {
1074 XmlSchemaIdentityConstraint ident = (XmlSchemaIdentityConstraint) Context.Element.Constraints [i];
1075 XsdKeyTable seq = CreateNewKeyTable (ident);
1076 if (ident is XmlSchemaKeyref) {
1077 if (tmpKeyrefPool == null)
1078 tmpKeyrefPool = new ArrayList ();
1079 tmpKeyrefPool.Add (seq);
1084 // (b) Evaluate current key sequences.
1085 for (int i = 0; i < keyTables.Count; i++) {
1086 XsdKeyTable seq = (XsdKeyTable) keyTables [i];
1087 if (seq.SelectorMatches (this.elementQNameStack, reader.Depth) != null) {
1088 // creates and registers new entry.
1089 XsdKeyEntry entry = new XsdKeyEntry (seq, reader.Depth, readerLineInfo);
1090 seq.Entries.Add (entry);
1095 private void ValidateKeyFields ()
1097 // (c) Evaluate field paths.
1098 for (int i = 0; i < keyTables.Count; i++) {
1099 XsdKeyTable seq = (XsdKeyTable) keyTables [i];
1100 // If possible, create new field entry candidates.
1101 for (int j = 0; j < seq.Entries.Count; j++) {
1103 ProcessKeyEntry (seq.Entries [j]);
1104 } catch (ValException ex) {
1111 private void ProcessKeyEntry (XsdKeyEntry entry)
1113 bool isNil = XsiNilDepth == Depth;
1114 entry.ProcessMatch (false, elementQNameStack, this, NameTable, BaseURI, SchemaType, ParserContext.NamespaceManager, readerLineInfo, Depth, null, null, null, isNil, CurrentKeyFieldConsumers);
1115 if (MoveToFirstAttribute ()) {
1118 switch (NamespaceURI) {
1119 case XmlNamespaceManager.XmlnsXmlns:
1120 case XmlSchema.InstanceNamespace:
1123 entry.ProcessMatch (true, elementQNameStack, this, NameTable, BaseURI, SchemaType, ParserContext.NamespaceManager, readerLineInfo, Depth, LocalName, NamespaceURI, Value, false, CurrentKeyFieldConsumers);
1124 } while (MoveToNextAttribute ());
1131 private XsdKeyTable CreateNewKeyTable (XmlSchemaIdentityConstraint ident)
1133 XsdKeyTable seq = new XsdKeyTable (ident);
1134 seq.StartDepth = reader.Depth;
1135 this.keyTables.Add (seq);
1139 private void ValidateSimpleContentIdentity (
1140 XmlSchemaDatatype dt, string value)
1142 // Identity field value
1143 if (currentKeyFieldConsumers != null) {
1144 while (this.currentKeyFieldConsumers.Count > 0) {
1145 XsdKeyEntryField field = this.currentKeyFieldConsumers [0] as XsdKeyEntryField;
1146 if (field.Identity != null)
1147 HandleError ("Two or more identical field was found. Former value is '" + field.Identity + "' .");
1148 object identity = null; // This means empty value
1151 identity = dt.ParseValue (value, NameTable, ParserContext.NamespaceManager);
1152 } catch (Exception ex) { // FIXME: (wishlist) This is bad manner ;-(
1153 HandleError ("Identity value is invalid against its data type " + dt.TokenizedType, ex);
1156 if (identity == null)
1159 if (!field.SetIdentityField (identity, reader.Depth == xsiNilDepth, dt as XsdAnySimpleType, this.Depth, readerLineInfo))
1160 HandleError ("Two or more identical key value was found: '" + value + "' .");
1161 this.currentKeyFieldConsumers.RemoveAt (0);
1166 private void EndIdentityValidation (XsdKeyTable seq)
1168 ArrayList errors = null;
1169 for (int i = 0; i < seq.Entries.Count; i++) {
1170 XsdKeyEntry entry = (XsdKeyEntry) seq.Entries [i];
1173 if (seq.SourceSchemaIdentity is XmlSchemaKey) {
1175 errors = new ArrayList ();
1176 errors.Add ("line " + entry.SelectorLineNumber + "position " + entry.SelectorLinePosition);
1180 HandleError ("Invalid identity constraints were found. Key was not found. "
1181 + String.Join (", ", errors.ToArray (typeof (string)) as string []));
1183 // If it is keyref, then find reference target
1184 XmlSchemaKeyref xsdKeyref = seq.SourceSchemaIdentity as XmlSchemaKeyref;
1185 if (xsdKeyref != null)
1186 EndKeyrefValidation (seq, xsdKeyref.Target);
1189 private void EndKeyrefValidation (XsdKeyTable seq, XmlSchemaIdentityConstraint targetIdent)
1191 for (int i = this.keyTables.Count - 1; i >= 0; i--) {
1192 XsdKeyTable target = this.keyTables [i] as XsdKeyTable;
1193 if (target.SourceSchemaIdentity != targetIdent)
1195 seq.ReferencedKey = target;
1196 for (int j = 0; j < seq.FinishedEntries.Count; j++) {
1197 XsdKeyEntry entry = (XsdKeyEntry) seq.FinishedEntries [j];
1198 for (int k = 0; k < target.FinishedEntries.Count; k++) {
1199 XsdKeyEntry targetEntry = (XsdKeyEntry) target.FinishedEntries [k];
1200 if (entry.CompareIdentity (targetEntry)) {
1201 entry.KeyRefFound = true;
1207 if (seq.ReferencedKey == null)
1208 HandleError ("Target key was not found.");
1209 ArrayList errors = null;
1210 for (int i = 0; i < seq.FinishedEntries.Count; i++) {
1211 XsdKeyEntry entry = (XsdKeyEntry) seq.FinishedEntries [i];
1212 if (!entry.KeyRefFound) {
1214 errors = new ArrayList ();
1215 errors.Add (" line " + entry.SelectorLineNumber + ", position " + entry.SelectorLinePosition);
1219 HandleError ("Invalid identity constraints were found. Referenced key was not found: "
1220 + String.Join (" / ", errors.ToArray (typeof (string)) as string []));
1224 // Overrided Methods
1226 public override void Close ()
1231 public override string GetAttribute (int i)
1233 switch (reader.NodeType) {
1234 case XmlNodeType.XmlDeclaration:
1235 case XmlNodeType.DocumentType:
1236 return reader.GetAttribute (i);
1239 if (reader.AttributeCount > i)
1240 reader.GetAttribute (i);
1241 int defIdx = i - reader.AttributeCount;
1242 if (i < AttributeCount)
1243 return defaultAttributes [defIdx].DefaultValue;
1245 throw new ArgumentOutOfRangeException ("i", i, "Specified attribute index is out of range.");
1248 public override string GetAttribute (string name)
1250 switch (reader.NodeType) {
1251 case XmlNodeType.XmlDeclaration:
1252 case XmlNodeType.DocumentType:
1253 return reader.GetAttribute (name);
1256 string value = reader.GetAttribute (name);
1260 QName qname = SplitQName (name);
1261 return GetDefaultAttribute (qname.Name, qname.Namespace);
1264 private QName SplitQName (string name)
1266 if (!XmlChar.IsName (name))
1267 throw new ArgumentException ("Invalid name was specified.", "name");
1269 Exception ex = null;
1270 QName qname = XmlSchemaUtil.ToQName (reader, name, out ex);
1277 public override string GetAttribute (string localName, string ns)
1279 switch (reader.NodeType) {
1280 case XmlNodeType.XmlDeclaration:
1281 case XmlNodeType.DocumentType:
1282 return reader.GetAttribute (localName, ns);
1285 string value = reader.GetAttribute (localName, ns);
1289 return GetDefaultAttribute (localName, ns);
1292 private string GetDefaultAttribute (string localName, string ns)
1294 int idx = this.FindDefaultAttribute (localName, ns);
1297 string value = defaultAttributes [idx].ValidatedDefaultValue;
1299 value = defaultAttributes [idx].ValidatedFixedValue;
1303 private int FindDefaultAttribute (string localName, string ns)
1305 for (int i = 0; i < this.defaultAttributes.Length; i++) {
1306 XsAttribute attr = defaultAttributes [i];
1307 if (attr.QualifiedName.Name == localName &&
1308 (ns == null || attr.QualifiedName.Namespace == ns))
1314 public bool HasLineInfo ()
1316 return readerLineInfo != null && readerLineInfo.HasLineInfo ();
1319 public override string LookupNamespace (string prefix)
1321 return reader.LookupNamespace (prefix);
1324 public override void MoveToAttribute (int i)
1326 switch (reader.NodeType) {
1327 case XmlNodeType.XmlDeclaration:
1328 case XmlNodeType.DocumentType:
1329 reader.MoveToAttribute (i);
1333 currentAttrType = null;
1334 if (i < reader.AttributeCount) {
1335 reader.MoveToAttribute (i);
1336 this.currentDefaultAttribute = -1;
1337 this.defaultAttributeConsumed = false;
1340 if (i < AttributeCount) {
1341 this.currentDefaultAttribute = i - reader.AttributeCount;
1342 this.defaultAttributeConsumed = false;
1345 throw new ArgumentOutOfRangeException ("i", i, "Attribute index is out of range.");
1348 public override bool MoveToAttribute (string name)
1350 switch (reader.NodeType) {
1351 case XmlNodeType.XmlDeclaration:
1352 case XmlNodeType.DocumentType:
1353 return reader.MoveToAttribute (name);
1356 currentAttrType = null;
1357 bool b = reader.MoveToAttribute (name);
1359 this.currentDefaultAttribute = -1;
1360 this.defaultAttributeConsumed = false;
1364 return MoveToDefaultAttribute (name, null);
1367 public override bool MoveToAttribute (string localName, string ns)
1369 switch (reader.NodeType) {
1370 case XmlNodeType.XmlDeclaration:
1371 case XmlNodeType.DocumentType:
1372 return reader.MoveToAttribute (localName, ns);
1375 currentAttrType = null;
1376 bool b = reader.MoveToAttribute (localName, ns);
1378 this.currentDefaultAttribute = -1;
1379 this.defaultAttributeConsumed = false;
1383 return MoveToDefaultAttribute (localName, ns);
1386 private bool MoveToDefaultAttribute (string localName, string ns)
1388 int idx = this.FindDefaultAttribute (localName, ns);
1391 currentDefaultAttribute = idx;
1392 defaultAttributeConsumed = false;
1396 public override bool MoveToElement ()
1398 currentDefaultAttribute = -1;
1399 defaultAttributeConsumed = false;
1400 currentAttrType = null;
1401 return reader.MoveToElement ();
1404 public override bool MoveToFirstAttribute ()
1406 switch (reader.NodeType) {
1407 case XmlNodeType.XmlDeclaration:
1408 case XmlNodeType.DocumentType:
1409 return reader.MoveToFirstAttribute ();
1412 currentAttrType = null;
1413 if (reader.AttributeCount > 0) {
1414 bool b = reader.MoveToFirstAttribute ();
1416 currentDefaultAttribute = -1;
1417 defaultAttributeConsumed = false;
1422 if (this.defaultAttributes.Length > 0) {
1423 currentDefaultAttribute = 0;
1424 defaultAttributeConsumed = false;
1431 public override bool MoveToNextAttribute ()
1433 switch (reader.NodeType) {
1434 case XmlNodeType.XmlDeclaration:
1435 case XmlNodeType.DocumentType:
1436 return reader.MoveToNextAttribute ();
1439 currentAttrType = null;
1440 if (currentDefaultAttribute >= 0) {
1441 if (defaultAttributes.Length == currentDefaultAttribute + 1)
1443 currentDefaultAttribute++;
1444 defaultAttributeConsumed = false;
1448 bool b = reader.MoveToNextAttribute ();
1450 currentDefaultAttribute = -1;
1451 defaultAttributeConsumed = false;
1455 if (defaultAttributes.Length > 0) {
1456 currentDefaultAttribute = 0;
1457 defaultAttributeConsumed = false;
1464 private XmlSchema ReadExternalSchema (string uri)
1466 Uri absUri = resolver.ResolveUri ((BaseURI != "" ? new Uri (BaseURI) : null), uri);
1467 string absUriString = absUri != null ? absUri.ToString () : String.Empty;
1468 XmlTextReader xtr = null;
1470 xtr = new XmlTextReader (absUriString,
1471 (Stream) resolver.GetEntity (
1472 absUri, null, typeof (Stream)),
1474 return XmlSchema.Read (
1475 xtr, ValidationEventHandler);
1482 private void ExamineAdditionalSchema ()
1484 if (resolver == null)
1486 XmlSchema schema = null;
1487 string schemaLocation = reader.GetAttribute ("schemaLocation", XmlSchema.InstanceNamespace);
1488 bool schemaAdded = false;
1489 if (schemaLocation != null) {
1490 string [] tmp = null;
1492 schemaLocation = XsDatatype.FromName ("token", XmlSchema.Namespace).Normalize (schemaLocation);
1493 tmp = schemaLocation.Split (XmlChar.WhitespaceChars);
1494 } catch (Exception ex) {
1495 if (schemas.Count == 0)
1496 HandleError ("Invalid schemaLocation attribute format.", ex, true);
1497 tmp = new string [0];
1499 if (tmp.Length % 2 != 0)
1500 if (schemas.Count == 0)
1501 HandleError ("Invalid schemaLocation attribute format.");
1502 for (int i = 0; i < tmp.Length; i += 2) {
1504 schema = ReadExternalSchema (tmp [i + 1]);
1505 } catch (Exception) { // FIXME: (wishlist) It is bad manner ;-(
1506 if (!schemas.Contains (tmp [i]))
1507 HandleError (String.Format ("Could not resolve schema location URI: {0}",
1508 i + 1 < tmp.Length ? tmp [i + 1] : String.Empty), null, true);
1511 if (schema.TargetNamespace == null)
1512 schema.TargetNamespace = tmp [i];
1513 else if (schema.TargetNamespace != tmp [i])
1514 HandleError ("Specified schema has different target namespace.");
1517 if (schema != null) {
1518 if (!schemas.Contains (schema.TargetNamespace)) {
1520 schemas.Add (schema);
1524 string noNsSchemaLocation = reader.GetAttribute ("noNamespaceSchemaLocation", XmlSchema.InstanceNamespace);
1525 if (noNsSchemaLocation != null) {
1527 schema = ReadExternalSchema (noNsSchemaLocation);
1528 } catch (Exception) { // FIXME: (wishlist) It is bad manner ;-(
1529 if (schemas.Count != 0)
1530 HandleError ("Could not resolve schema location URI: " + noNsSchemaLocation, null, true);
1532 if (schema != null && schema.TargetNamespace != null)
1533 HandleError ("Specified schema has different target namespace.");
1535 if (schema != null) {
1536 if (!schemas.Contains (schema.TargetNamespace)) {
1538 schemas.Add (schema);
1541 // FIXME: should call Reprocess()?
1546 public override bool Read ()
1548 currentDefaultAttribute = -1;
1549 defaultAttributeConsumed = false;
1550 currentAttrType = null;
1551 #region ID Constraints
1552 if (this.checkIdentity)
1553 idManager.OnStartElement ();
1555 defaultAttributes = emptyAttributeArray;
1557 bool result = reader.Read ();
1558 #region ID Constraints
1559 // 3.3.4 ElementLocallyValidElement 7 = Root Valid.
1560 if (!result && this.checkIdentity &&
1561 idManager.HasMissingIDReferences ())
1562 HandleError ("There are missing ID references: " + idManager.GetMissingIDString ());
1565 // FIXME: schemaLocation could be specified
1567 if (reader.Depth == 0 &&
1568 reader.NodeType == XmlNodeType.Element)
1569 ExamineAdditionalSchema ();
1570 if (schemas.Count == 0)
1572 if (!schemas.IsCompiled)
1575 switch (reader.NodeType) {
1576 case XmlNodeType.Element:
1577 #region Key Constraints
1578 if (checkKeyConstraints)
1579 this.elementQNameStack.Add (new QName (reader.LocalName, reader.NamespaceURI));
1582 // If there is no schema information, then no validation is performed.
1583 if (skipValidationDepth < 0 || reader.Depth <= skipValidationDepth) {
1584 ValidateEndSimpleContent ();
1585 AssessStartElementSchemaValidity ();
1588 if (reader.IsEmptyElement)
1589 goto case XmlNodeType.EndElement;
1591 shouldValidateCharacters = true;
1593 case XmlNodeType.EndElement:
1594 if (reader.Depth == skipValidationDepth)
1595 skipValidationDepth = -1;
1596 else if (skipValidationDepth < 0 || reader.Depth <= skipValidationDepth)
1597 AssessEndElementSchemaValidity ();
1599 if (checkKeyConstraints)
1600 elementQNameStack.RemoveAt (elementQNameStack.Count - 1);
1603 case XmlNodeType.CDATA:
1604 case XmlNodeType.SignificantWhitespace:
1605 case XmlNodeType.Text:
1606 // FIXME: does this check make sense?
1607 ComplexType ct = Context.ActualType as ComplexType;
1608 if (ct != null && storedCharacters.Length > 0) {
1609 switch (ct.ContentType) {
1610 case XmlSchemaContentType.ElementOnly:
1611 case XmlSchemaContentType.Empty:
1612 HandleError ("Not allowed character content was found.");
1617 ValidateCharacters ();
1624 public override bool ReadAttributeValue ()
1626 if (currentDefaultAttribute < 0)
1627 return reader.ReadAttributeValue ();
1629 if (this.defaultAttributeConsumed)
1632 defaultAttributeConsumed = true;
1637 public override string ReadInnerXml ()
1639 // MS.NET 1.0 has a serious bug here. It skips validation.
1640 return reader.ReadInnerXml ();
1643 public override string ReadOuterXml ()
1645 // MS.NET 1.0 has a serious bug here. It skips validation.
1646 return reader.ReadOuterXml ();
1650 // XmlReader.ReadString() should call derived this.Read().
1651 public override string ReadString ()
1654 return reader.ReadString ();
1656 return base.ReadString ();
1660 // This class itself does not have this feature.
1661 public override void ResolveEntity ()
1663 reader.ResolveEntity ();
1667 internal class XsdValidationContext
1669 public XsdValidationContext ()
1673 // Some of them might be missing (See the spec section 5.3, and also 3.3.4).
1674 public XsElement Element;
1675 public object XsiType; // xsi:type
1676 internal XsdValidationState State;
1678 // Note that it represents current element's type.
1679 public object ActualType {
1681 if (XsiType != null)
1684 return Element != null ? Element.ElementType : null;
1689 public XmlSchemaType ActualSchemaType {
1691 object at = ActualType;
1694 XmlSchemaType st = at as XmlSchemaType;
1696 st = XmlSchemaType.GetBuiltInSimpleType (
1697 ((XmlSchemaDatatype) at).TypeCode);
1703 public bool IsInvalid {
1704 get { return State == XsdValidationState.Invalid; }
1707 public object Clone ()
1709 return MemberwiseClone ();
1712 public void EvaluateStartElement (
1713 string localName, string ns)
1715 State = State.EvaluateStartElement (localName, ns);
1718 public bool EvaluateEndElement ()
1720 return State.EvaluateEndElement ();
1723 public void SetElement (XsElement element)
1729 internal class XsdIDManager
1731 public XsdIDManager ()
1735 Hashtable idList = new Hashtable ();
1736 ArrayList missingIDReferences;
1737 string thisElementId;
1739 private ArrayList MissingIDReferences {
1741 if (missingIDReferences == null)
1742 missingIDReferences = new ArrayList ();
1743 return missingIDReferences;
1747 public void OnStartElement ()
1749 thisElementId = null;
1753 public string AssessEachAttributeIdentityConstraint (
1754 XsDatatype dt, object parsedValue, string elementName)
1756 // Validate identity constraints.
1757 string str = parsedValue as string;
1758 switch (dt.TokenizedType) {
1759 case XmlTokenizedType.ID:
1760 if (thisElementId != null)
1761 return "ID type attribute was already assigned in the containing element.";
1763 thisElementId = str;
1764 if (idList.ContainsKey (str))
1765 return "Duplicate ID value was found.";
1767 idList.Add (str, elementName);
1768 if (MissingIDReferences.Contains (str))
1769 MissingIDReferences.Remove (str);
1771 case XmlTokenizedType.IDREF:
1772 if (!idList.Contains (str))
1773 MissingIDReferences.Add (str);
1775 case XmlTokenizedType.IDREFS:
1776 string [] idrefs = (string []) parsedValue;
1777 for (int i = 0; i < idrefs.Length; i++) {
1778 string id = idrefs [i];
1779 if (!idList.Contains (id))
1780 MissingIDReferences.Add (id);
1787 public object FindID (string name)
1789 return idList [name];
1792 public bool HasMissingIDReferences ()
1794 return missingIDReferences != null
1795 && missingIDReferences.Count > 0;
1798 public string GetMissingIDString ()
1800 return String.Join (" ",
1801 MissingIDReferences.ToArray (typeof (string))