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
63 static readonly XsAttribute [] emptyAttributeArray =
68 IHasXmlSchemaInfo sourceReaderSchemaInfo;
69 IXmlLineInfo readerLineInfo;
70 ValidationType validationType;
71 XmlSchemaSet schemas = new XmlSchemaSet ();
72 bool namespaces = true;
73 bool validationStarted;
75 #region ID Constraints
76 bool checkIdentity = true;
77 XsdIDManager idManager = new XsdIDManager ();
80 #region Key Constraints
81 bool checkKeyConstraints = true;
82 ArrayList keyTables = new ArrayList ();
83 ArrayList currentKeyFieldConsumers;
84 ArrayList tmpKeyrefPool;
86 ArrayList elementQNameStack = new ArrayList ();
88 XsdParticleStateManager state = new XsdParticleStateManager ();
90 int skipValidationDepth = -1;
92 StringBuilder storedCharacters = new StringBuilder ();
93 bool shouldValidateCharacters;
95 XsAttribute [] defaultAttributes = emptyAttributeArray;
96 int currentDefaultAttribute = -1;
97 ArrayList defaultAttributesCache = new ArrayList ();
98 bool defaultAttributeConsumed;
99 object currentAttrType;
102 public XsdValidatingReader (XmlReader reader)
104 this.reader = reader;
105 readerLineInfo = reader as IXmlLineInfo;
106 sourceReaderSchemaInfo = reader as IHasXmlSchemaInfo;
107 schemas.ValidationEventHandler += ValidationEventHandler;
111 public ValidationEventHandler ValidationEventHandler;
113 // Private Properties
115 private XsdValidationContext Context {
116 get { return state.Context; }
119 #region Key Constraints
120 internal ArrayList CurrentKeyFieldConsumers {
122 if (currentKeyFieldConsumers == null)
123 currentKeyFieldConsumers = new ArrayList ();
124 return currentKeyFieldConsumers;
129 // Public Non-overrides
131 public int XsiNilDepth {
132 get { return xsiNilDepth; }
135 public bool Namespaces {
136 get { return namespaces; }
137 set { namespaces = value; }
140 // This is required to resolve xsi:schemaLocation
141 public XmlResolver XmlResolver {
147 // This should be changed before the first Read() call.
148 public XmlSchemaSet Schemas {
149 get { return schemas; }
151 if (validationStarted)
152 throw new InvalidOperationException ("Schemas must be set before the first call to Read().");
157 public object SchemaType {
159 if (ReadState != ReadState.Interactive)
163 case XmlNodeType.Element:
164 if (Context.ActualType != null)
165 return Context.ActualType;
167 return SourceReaderSchemaType;
168 case XmlNodeType.Attribute:
169 if (currentAttrType == null) {
170 ComplexType ct = Context.ActualType as ComplexType;
172 XsAttribute attdef = ct.AttributeUses [new QName (LocalName, NamespaceURI)] as XsAttribute;
174 currentAttrType = attdef.AttributeType;
175 return currentAttrType;
177 currentAttrType = SourceReaderSchemaType;
179 return currentAttrType;
181 return SourceReaderSchemaType;
186 private object SourceReaderSchemaType {
187 get { return this.sourceReaderSchemaInfo != null ? sourceReaderSchemaInfo.SchemaType : null; }
190 public ValidationType ValidationType {
191 get { return validationType; }
193 if (validationStarted)
194 throw new InvalidOperationException ("ValidationType must be set before reading.");
195 validationType = value;
199 // It is used only for independent XmlReader use, not for XmlValidatingReader.
200 public object ReadTypedValue ()
202 object o = XmlSchemaUtil.ReadTypedValue (this,
203 SchemaType, NamespaceManager,
205 storedCharacters.Length = 0;
209 // Public Overriden Properties
211 public override int AttributeCount {
213 return reader.AttributeCount + defaultAttributes.Length;
217 public override string BaseURI {
218 get { return reader.BaseURI; }
221 // If this class is used to implement XmlValidatingReader,
222 // it should be left to DTDValidatingReader. In other cases,
223 // it depends on the reader's ability.
224 public override bool CanResolveEntity {
225 get { return reader.CanResolveEntity; }
228 public override int Depth {
230 if (currentDefaultAttribute < 0)
232 if (this.defaultAttributeConsumed)
233 return reader.Depth + 2;
234 return reader.Depth + 1;
238 public override bool EOF {
239 get { return reader.EOF; }
242 public override bool HasValue {
244 if (currentDefaultAttribute < 0)
245 return reader.HasValue;
250 public override bool IsDefault {
252 if (currentDefaultAttribute < 0)
253 return reader.IsDefault;
258 public override bool IsEmptyElement {
260 if (currentDefaultAttribute < 0)
261 return reader.IsEmptyElement;
266 public override string this [int i] {
267 get { return GetAttribute (i); }
270 public override string this [string name] {
271 get { return GetAttribute (name); }
274 public override string this [string localName, string ns] {
275 get { return GetAttribute (localName, ns); }
278 public int LineNumber {
279 get { return readerLineInfo != null ? readerLineInfo.LineNumber : 0; }
282 public int LinePosition {
283 get { return readerLineInfo != null ? readerLineInfo.LinePosition : 0; }
286 public override string LocalName {
288 if (currentDefaultAttribute < 0)
289 return reader.LocalName;
290 if (defaultAttributeConsumed)
292 return defaultAttributes [currentDefaultAttribute].QualifiedName.Name;
296 public override string Name {
298 if (currentDefaultAttribute < 0)
300 if (defaultAttributeConsumed)
303 QName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
304 string prefix = Prefix;
305 if (prefix == String.Empty)
308 return String.Concat (prefix, ":", qname.Name);
312 public override string NamespaceURI {
314 if (currentDefaultAttribute < 0)
315 return reader.NamespaceURI;
316 if (defaultAttributeConsumed)
318 return defaultAttributes [currentDefaultAttribute].QualifiedName.Namespace;
322 public override XmlNameTable NameTable {
323 get { return reader.NameTable; }
326 public override XmlNodeType NodeType {
328 if (currentDefaultAttribute < 0)
329 return reader.NodeType;
330 if (defaultAttributeConsumed)
331 return XmlNodeType.Text;
332 return XmlNodeType.Attribute;
336 public XmlParserContext ParserContext {
337 get { return XmlSchemaUtil.GetParserContext (reader); }
340 internal XmlNamespaceManager NamespaceManager {
341 get { return ParserContext != null ? ParserContext.NamespaceManager : null; }
344 public override string Prefix {
346 if (currentDefaultAttribute < 0)
347 return reader.Prefix;
348 if (defaultAttributeConsumed)
350 QName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
351 string prefix = NamespaceManager != null ? NamespaceManager.LookupPrefix (qname.Namespace, false) : null;
359 public override char QuoteChar {
360 get { return reader.QuoteChar; }
363 public override ReadState ReadState {
364 get { return reader.ReadState; }
367 public override string Value {
369 if (currentDefaultAttribute < 0)
371 string value = defaultAttributes [currentDefaultAttribute].ValidatedDefaultValue;
373 value = defaultAttributes [currentDefaultAttribute].ValidatedFixedValue;
378 public override string XmlLang {
380 string xmlLang = reader.XmlLang;
383 int idx = this.FindDefaultAttribute ("lang", XmlNamespaceManager.XmlnsXml);
386 xmlLang = defaultAttributes [idx].ValidatedDefaultValue;
388 xmlLang = defaultAttributes [idx].ValidatedFixedValue;
393 public override XmlSpace XmlSpace {
395 XmlSpace space = reader.XmlSpace;
396 if (space != XmlSpace.None)
398 int idx = this.FindDefaultAttribute ("space", XmlNamespaceManager.XmlnsXml);
400 return XmlSpace.None;
401 string spaceSpec = defaultAttributes [idx].ValidatedDefaultValue;
402 if (spaceSpec == null)
403 spaceSpec = defaultAttributes [idx].ValidatedFixedValue;
404 return (XmlSpace) Enum.Parse (typeof (XmlSpace), spaceSpec, false);
410 private void HandleError (string error)
412 HandleError (error, null);
415 private void HandleError (string error, Exception innerException)
417 HandleError (error, innerException, false);
420 private void HandleError (string error, Exception innerException, bool isWarning)
422 if (ValidationType == ValidationType.None) // extra quick check
425 ValException schemaException = new ValException (error,
426 this, this.BaseURI, null, innerException);
427 HandleError (schemaException, isWarning);
430 private void HandleError (ValException schemaException)
432 HandleError (schemaException, false);
435 private void HandleError (ValException schemaException, bool isWarning)
437 if (ValidationType == ValidationType.None)
440 ValidationEventArgs e = new ValidationEventArgs (schemaException,
441 schemaException.Message, isWarning ? XmlSeverityType.Warning : XmlSeverityType.Error);
443 if (ValidationEventHandler != null)
444 ValidationEventHandler (this, e);
446 else if (e.Severity == XmlSeverityType.Error)
450 private XsElement FindElement (string name, string ns)
452 return (XsElement) schemas.GlobalElements [new QName (name, ns)];
455 private XmlSchemaType FindType (QName qname)
457 return (XmlSchemaType) schemas.GlobalTypes [qname];
460 private void ValidateStartElementParticle ()
462 if (Context.State == null)
464 Context.XsiType = null;
465 state.CurrentElement = null;
466 Context.EvaluateStartElement (reader.LocalName,
467 reader.NamespaceURI);
468 if (Context.IsInvalid)
469 HandleError ("Invalid start element: " + reader.NamespaceURI + ":" + reader.LocalName);
471 Context.SetElement (state.CurrentElement);
474 private void ValidateEndElementParticle ()
476 if (Context.State != null) {
477 if (!Context.EvaluateEndElement ()) {
478 HandleError ("Invalid end element: " + reader.Name);
484 // Utility for missing validation completion related to child items.
485 private void ValidateCharacters ()
487 if (xsiNilDepth >= 0 && xsiNilDepth < reader.Depth)
488 HandleError ("Element item appeared, while current element context is nil.");
490 if (shouldValidateCharacters)
491 storedCharacters.Append (reader.Value);
494 // Utility for missing validation completion related to child items.
495 private void ValidateEndSimpleContent ()
497 if (shouldValidateCharacters)
498 ValidateEndSimpleContentCore ();
499 shouldValidateCharacters = false;
500 storedCharacters.Length = 0;
503 private void ValidateEndSimpleContentCore ()
505 if (Context.ActualType == null)
508 string value = storedCharacters.ToString ();
510 if (value.Length == 0) {
511 // 3.3.4 Element Locally Valid (Element) 5.1.2
512 if (Context.Element != null) {
513 if (Context.Element.ValidatedDefaultValue != null)
514 value = Context.Element.ValidatedDefaultValue;
518 XsDatatype dt = Context.ActualType as XsDatatype;
519 SimpleType st = Context.ActualType as SimpleType;
524 ComplexType ct = Context.ActualType as ComplexType;
526 switch (ct.ContentType) {
527 case XmlSchemaContentType.ElementOnly:
528 case XmlSchemaContentType.Empty:
529 if (value.Length > 0 && !XmlChar.IsWhitespace (value))
530 HandleError ("Character content not allowed.");
536 // 3.3.4 Element Locally Valid (Element) :: 5.2.2.2. Fixed value constraints
537 if (Context.Element != null && Context.Element.ValidatedFixedValue != null)
538 if (value != Context.Element.ValidatedFixedValue)
539 HandleError ("Fixed value constraint was not satisfied.");
540 AssessStringValid (st, dt, value);
543 #region Key Constraints
544 if (checkKeyConstraints)
545 ValidateSimpleContentIdentity (dt, value);
548 shouldValidateCharacters = false;
551 // 3.14.4 String Valid
552 private void AssessStringValid (SimpleType st,
553 XsDatatype dt, string value)
555 XsDatatype validatedDatatype = dt;
557 string normalized = validatedDatatype.Normalize (value);
559 XsDatatype itemDatatype;
560 SimpleType itemSimpleType;
561 switch (st.DerivedBy) {
562 case XmlSchemaDerivationMethod.List:
563 SimpleTypeList listContent = st.Content as SimpleTypeList;
564 values = normalized.Split (XmlChar.WhitespaceChars);
565 itemDatatype = listContent.ValidatedListItemType as XsDatatype;
566 itemSimpleType = listContent.ValidatedListItemType as SimpleType;
567 for (int vi = 0; vi < values.Length; vi++) {
568 string each = values [vi];
569 if (each == String.Empty)
571 // validate against ValidatedItemType
572 if (itemDatatype != null) {
574 itemDatatype.ParseValue (each, NameTable, NamespaceManager);
575 } catch (Exception ex) { // FIXME: (wishlist) better exception handling ;-(
576 HandleError ("List type value contains one or more invalid values.", ex);
581 AssessStringValid (itemSimpleType, itemSimpleType.Datatype, each);
584 case XmlSchemaDerivationMethod.Union:
585 SimpleTypeUnion union = st.Content as SimpleTypeUnion;
587 string each = normalized;
588 // validate against ValidatedItemType
590 foreach (object eachType in union.ValidatedTypes) {
591 itemDatatype = eachType as XsDatatype;
592 itemSimpleType = eachType as SimpleType;
593 if (itemDatatype != null) {
595 itemDatatype.ParseValue (each, NameTable, NamespaceManager);
596 } catch (Exception) { // FIXME: (wishlist) better exception handling ;-(
602 AssessStringValid (itemSimpleType, itemSimpleType.Datatype, each);
603 } catch (ValException) {
611 HandleError ("Union type value contains one or more invalid values.");
616 case XmlSchemaDerivationMethod.Restriction:
617 SimpleTypeRest str = st.Content as SimpleTypeRest;
620 /* Don't forget to validate against inherited type's facets
621 * Could we simplify this by assuming that the basetype will also
624 // mmm, will check later.
625 SimpleType baseType = st.BaseXmlSchemaType as SimpleType;
626 if (baseType != null) {
627 AssessStringValid(baseType, dt, value);
629 if (!str.ValidateValueWithFacets (value, NameTable)) {
630 HandleError ("Specified value was invalid against the facets.");
634 validatedDatatype = st.Datatype;
638 if (validatedDatatype != null) {
640 validatedDatatype.ParseValue (value, NameTable, NamespaceManager);
641 } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
642 HandleError ("Invalidly typed data was specified.", ex);
647 private object GetXsiType (string name)
649 object xsiType = null;
650 QName typeQName = QName.Parse (name, this);
651 if (typeQName == ComplexType.AnyTypeName)
652 xsiType = ComplexType.AnyType;
653 else if (XmlSchemaUtil.IsBuiltInDatatypeName (typeQName))
654 xsiType = XsDatatype.FromName (typeQName);
656 xsiType = FindType (typeQName);
660 // It is common to ElementLocallyValid::4 and SchemaValidityAssessment::1.2.1.2.4
661 private void AssessLocalTypeDerivationOK (object xsiType, object baseType, XmlSchemaDerivationMethod flag)
663 XmlSchemaType xsiSchemaType = xsiType as XmlSchemaType;
664 ComplexType baseComplexType = baseType as ComplexType;
665 ComplexType xsiComplexType = xsiSchemaType as ComplexType;
666 if (xsiType != baseType) {
667 // Extracted (not extraneous) check for 3.4.6 TypeDerivationOK.
668 if (baseComplexType != null)
669 flag |= baseComplexType.BlockResolved;
670 if (flag == XmlSchemaDerivationMethod.All) {
671 HandleError ("Prohibited element type substitution.");
673 } else if (xsiSchemaType != null && (flag & xsiSchemaType.DerivedBy) != 0) {
674 HandleError ("Prohibited element type substitution.");
679 if (xsiComplexType != null)
681 xsiComplexType.ValidateTypeDerivationOK (baseType, null, null);
682 } catch (ValException ex) {
683 // HandleError ("Locally specified schema complex type derivation failed. " + ex.Message, ex);
687 SimpleType xsiSimpleType = xsiType as SimpleType;
688 if (xsiSimpleType != null) {
690 xsiSimpleType.ValidateTypeDerivationOK (baseType, null, null, true);
691 } catch (ValException ex) {
692 // HandleError ("Locally specified schema simple type derivation failed. " + ex.Message, ex);
696 else if (xsiType is XsDatatype) {
700 HandleError ("Primitive data type cannot be derived type using xsi:type specification.");
704 // Section 3.3.4 of the spec.
705 private void AssessStartElementSchemaValidity ()
707 // If the reader is inside xsi:nil (and failed
708 // on validation), then simply skip its content.
709 if (xsiNilDepth >= 0 && xsiNilDepth < reader.Depth)
710 HandleError ("Element item appeared, while current element context is nil.");
712 ValidateStartElementParticle ();
714 string xsiNilValue = reader.GetAttribute ("nil", XmlSchema.InstanceNamespace);
715 if (xsiNilValue != null)
716 xsiNilValue = xsiNilValue.Trim (XmlChar.WhitespaceChars);
717 bool isXsiNil = xsiNilValue == "true";
718 if (isXsiNil && this.xsiNilDepth < 0)
719 xsiNilDepth = reader.Depth;
721 // [Schema Validity Assessment (Element) 1.2]
722 // Evaluate "local type definition" from xsi:type.
723 // (See spec 3.3.4 Schema Validity Assessment (Element) 1.2.1.2.3.
724 // Note that Schema Validity Assessment(Element) 1.2 takes
725 // precedence than 1.1 of that.
727 string xsiTypeName = reader.GetAttribute ("type", XmlSchema.InstanceNamespace);
728 if (xsiTypeName != null) {
729 xsiTypeName = xsiTypeName.Trim (XmlChar.WhitespaceChars);
730 object xsiType = GetXsiType (xsiTypeName);
732 HandleError ("The instance type was not found: " + xsiTypeName + " .");
734 XmlSchemaType xsiSchemaType = xsiType as XmlSchemaType;
735 if (xsiSchemaType != null && this.Context.Element != null) {
736 XmlSchemaType elemBaseType = Context.Element.ElementType as XmlSchemaType;
737 if (elemBaseType != null && (xsiSchemaType.DerivedBy & elemBaseType.FinalResolved) != 0)
738 HandleError ("The instance type is prohibited by the type of the context element.");
739 if (elemBaseType != xsiType && (xsiSchemaType.DerivedBy & this.Context.Element.BlockResolved) != 0)
740 HandleError ("The instance type is prohibited by the context element.");
742 ComplexType xsiComplexType = xsiType as ComplexType;
743 if (xsiComplexType != null && xsiComplexType.IsAbstract)
744 HandleError ("The instance type is abstract: " + xsiTypeName + " .");
746 // If current schema type exists, then this xsi:type must be
747 // valid extension of that type. See 1.2.1.2.4.
748 if (Context.Element != null) {
749 AssessLocalTypeDerivationOK (xsiType, Context.Element.ElementType, Context.Element.BlockResolved);
751 AssessStartElementLocallyValidType (xsiType); // 1.2.2:
752 Context.XsiType = xsiType;
757 // Create Validation Root, if not exist.
758 // [Schema Validity Assessment (Element) 1.1]
759 if (Context.Element == null) {
760 state.CurrentElement = FindElement (reader.LocalName, reader.NamespaceURI);
761 Context.SetElement (state.CurrentElement);
763 if (Context.Element != null) {
764 if (Context.XsiType == null) {
765 AssessElementLocallyValidElement (xsiNilValue); // 1.1.2
768 switch (state.ProcessContents) {
769 case ContentProc.Skip:
771 case ContentProc.Lax:
774 if (xsiTypeName == null &&
775 (schemas.Contains (reader.NamespaceURI) ||
776 !schemas.MissedSubComponents (reader.NamespaceURI)))
777 HandleError ("Element declaration for " + new QName (reader.LocalName, reader.NamespaceURI) + " is missing.");
782 state.PushContext ();
784 XsdValidationState next = null;
785 if (state.ProcessContents == ContentProc.Skip)
786 skipValidationDepth = reader.Depth;
788 // create child particle state.
789 ComplexType xsComplexType = SchemaType as ComplexType;
790 if (xsComplexType != null)
791 next = state.Create (xsComplexType.ValidatableParticle);
792 else if (state.ProcessContents == ContentProc.Lax)
793 next = state.Create (XmlSchemaAny.AnyTypeContent);
795 next = state.Create (XmlSchemaParticle.Empty);
797 Context.State = next;
799 #region Key Constraints
800 if (checkKeyConstraints) {
801 ValidateKeySelectors ();
802 ValidateKeyFields ();
808 // 3.3.4 Element Locally Valid (Element)
809 private void AssessElementLocallyValidElement (string xsiNilValue)
811 XsElement element = Context.Element;
812 QName qname = new QName (reader.LocalName, reader.NamespaceURI);
815 HandleError ("Element declaration is required for " + qname);
817 if (element.ActualIsAbstract)
818 HandleError ("Abstract element declaration was specified for " + qname);
820 if (!element.ActualIsNillable && xsiNilValue != null)
821 HandleError ("This element declaration is not nillable: " + qname);
823 // Note that 3.2.1 xsi:nil constraints are to be
824 // validated in AssessElementSchemaValidity() and
825 // ValidateCharacters().
826 else if (xsiNilValue == "true") {
827 if (element.ValidatedFixedValue != null)
828 HandleError ("Schema instance nil was specified, where the element declaration for " + qname + "has fixed value constraints.");
830 // 4. xsi:type (it takes precedence than element type)
831 string xsiType = reader.GetAttribute ("type", XmlSchema.InstanceNamespace);
832 if (xsiType != null) {
833 Context.XsiType = GetXsiType (xsiType);
834 AssessLocalTypeDerivationOK (Context.XsiType, element.ElementType, element.BlockResolved);
837 Context.XsiType = null;
839 // 5 Not all things cannot be assessed here.
840 // It is common to 5.1 and 5.2
841 if (element.ElementType != null)
842 AssessStartElementLocallyValidType (SchemaType);
844 // 6. should be out from here.
845 // See invokation of AssessStartIdentityConstraints().
847 // 7 is going to be validated in Read() (in case of xmlreader's EOF).
850 // 3.3.4 Element Locally Valid (Type)
851 private void AssessStartElementLocallyValidType (object schemaType)
853 if (schemaType == null) { // 1.
854 HandleError ("Schema type does not exist.");
857 ComplexType cType = schemaType as ComplexType;
858 SimpleType sType = schemaType as SimpleType;
861 while (reader.MoveToNextAttribute ()) {
862 if (reader.NamespaceURI == XmlNamespaceManager.XmlnsXmlns)
864 if (reader.NamespaceURI != XmlSchema.InstanceNamespace)
865 HandleError ("Current simple type cannot accept attributes other than schema instance namespace.");
866 switch (reader.LocalName) {
869 case "schemaLocation":
870 case "noNamespaceSchemaLocation":
873 HandleError ("Unknown schema instance namespace attribute: " + reader.LocalName);
877 reader.MoveToElement ();
878 // 3.1.2 and 3.1.3 cannot be assessed here.
879 } else if (cType != null) {
880 if (cType.IsAbstract) { // 2.
881 HandleError ("Target complex type is abstract.");
885 AssessElementLocallyValidComplexType (cType);
889 // 3.4.4 Element Locally Valid (Complex Type)
890 private void AssessElementLocallyValidComplexType (ComplexType cType)
893 if (cType.IsAbstract)
894 HandleError ("Target complex type is abstract.");
896 // 2 (xsi:nil and content prohibition)
897 // See AssessStartElementSchemaValidity() and ValidateCharacters()
899 // 3. attribute uses and
901 if (reader.MoveToFirstAttribute ()) {
903 switch (reader.NamespaceURI) {
904 case"http://www.w3.org/2000/xmlns/":
905 case XmlSchema.InstanceNamespace:
908 QName qname = new QName (reader.LocalName, reader.NamespaceURI);
909 // including 3.10.4 Item Valid (Wildcard)
910 XmlSchemaObject attMatch = XmlSchemaUtil.FindAttributeDeclaration (reader.NamespaceURI, schemas, cType, qname);
911 if (attMatch == null)
912 HandleError ("Attribute declaration was not found for " + qname);
913 XsAttribute attdecl = attMatch as XsAttribute;
914 if (attdecl != null) {
915 AssessAttributeLocallyValidUse (attdecl);
916 AssessAttributeLocallyValid (attdecl);
917 } // otherwise anyAttribute or null.
918 } while (reader.MoveToNextAttribute ());
919 reader.MoveToElement ();
922 // Collect default attributes.
924 foreach (DictionaryEntry entry in cType.AttributeUses) {
925 XsAttribute attr = (XsAttribute) entry.Value;
926 if (reader [attr.QualifiedName.Name, attr.QualifiedName.Namespace] == null) {
927 if (attr.ValidatedUse == XmlSchemaUse.Required &&
928 attr.ValidatedFixedValue == null)
929 HandleError ("Required attribute " + attr.QualifiedName + " was not found.");
930 else if (attr.ValidatedDefaultValue != null || attr.ValidatedFixedValue != null)
931 defaultAttributesCache.Add (attr);
934 if (defaultAttributesCache.Count == 0)
935 defaultAttributes = emptyAttributeArray;
937 defaultAttributes = (XsAttribute [])
938 defaultAttributesCache.ToArray (
939 typeof (XsAttribute));
940 defaultAttributesCache.Clear ();
941 // 5. wild IDs was already checked above.
944 // 3.2.4 Attribute Locally Valid and 3.4.4
945 private void AssessAttributeLocallyValid (XsAttribute attr)
948 if (attr.AttributeType == null)
949 HandleError ("Attribute type is missing for " + attr.QualifiedName);
950 XsDatatype dt = attr.AttributeType as XsDatatype;
952 dt = ((SimpleType) attr.AttributeType).Datatype;
953 // It is a bit heavy process, so let's omit as long as possible ;-)
954 if (dt != SimpleType.AnySimpleType || attr.ValidatedFixedValue != null) {
955 string normalized = dt.Normalize (reader.Value);
956 object parsedValue = null;
958 parsedValue = dt.ParseValue (normalized, reader.NameTable, NamespaceManager);
959 } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
960 HandleError ("Attribute value is invalid against its data type " + dt.TokenizedType, ex);
962 if (attr.ValidatedFixedValue != null && attr.ValidatedFixedValue != normalized) {
963 HandleError ("The value of the attribute " + attr.QualifiedName + " does not match with its fixed value.");
964 parsedValue = dt.ParseValue (attr.ValidatedFixedValue, reader.NameTable, NamespaceManager);
966 #region ID Constraints
967 if (this.checkIdentity) {
968 string error = idManager.AssessEachAttributeIdentityConstraint (dt, parsedValue, ((QName) elementQNameStack [elementQNameStack.Count - 1]).Name);
976 private void AssessAttributeLocallyValidUse (XsAttribute attr)
978 // This is extra check than spec 3.5.4
979 if (attr.ValidatedUse == XmlSchemaUse.Prohibited)
980 HandleError ("Attribute " + attr.QualifiedName + " is prohibited in this context.");
983 private void AssessEndElementSchemaValidity ()
985 ValidateEndElementParticle (); // validate against childrens' state.
987 ValidateEndSimpleContent ();
989 // 3.3.4 Assess ElementLocallyValidElement 5: value constraints.
990 // 3.3.4 Assess ElementLocallyValidType 3.1.3. = StringValid(3.14.4)
991 // => ValidateEndSimpleContent().
993 #region Key Constraints
994 if (checkKeyConstraints)
995 ValidateEndElementKeyConstraints ();
998 // Reset xsi:nil, if required.
999 if (xsiNilDepth == reader.Depth)
1003 #region Key Constraints
1004 private void ValidateEndElementKeyConstraints ()
1006 // Reset Identity constraints.
1007 for (int i = 0; i < keyTables.Count; i++) {
1008 XsdKeyTable seq = this.keyTables [i] as XsdKeyTable;
1009 if (seq.StartDepth == reader.Depth) {
1010 EndIdentityValidation (seq);
1012 for (int k = 0; k < seq.Entries.Count; k++) {
1013 XsdKeyEntry entry = seq.Entries [k] as XsdKeyEntry;
1014 // Remove finished (maybe key not found) entries.
1015 if (entry.StartDepth == reader.Depth) {
1017 seq.FinishedEntries.Add (entry);
1018 else if (seq.SourceSchemaIdentity is XmlSchemaKey)
1019 HandleError ("Key sequence is missing.");
1020 seq.Entries.RemoveAt (k);
1023 // Pop validated key depth to find two or more fields.
1025 for (int j = 0; j < entry.KeyFields.Count; j++) {
1026 XsdKeyEntryField kf = entry.KeyFields [j];
1027 if (!kf.FieldFound && kf.FieldFoundDepth == reader.Depth) {
1028 kf.FieldFoundDepth = 0;
1029 kf.FieldFoundPath = null;
1036 for (int i = 0; i < keyTables.Count; i++) {
1037 XsdKeyTable seq = this.keyTables [i] as XsdKeyTable;
1038 if (seq.StartDepth == reader.Depth) {
1039 keyTables.RemoveAt (i);
1045 // 3.11.4 Identity Constraint Satisfied
1046 private void ValidateKeySelectors ()
1048 if (tmpKeyrefPool != null)
1049 tmpKeyrefPool.Clear ();
1050 if (Context.Element != null && Context.Element.Constraints.Count > 0) {
1051 // (a) Create new key sequences, if required.
1052 for (int i = 0; i < Context.Element.Constraints.Count; i++) {
1053 XmlSchemaIdentityConstraint ident = (XmlSchemaIdentityConstraint) Context.Element.Constraints [i];
1054 XsdKeyTable seq = CreateNewKeyTable (ident);
1055 if (ident is XmlSchemaKeyref) {
1056 if (tmpKeyrefPool == null)
1057 tmpKeyrefPool = new ArrayList ();
1058 tmpKeyrefPool.Add (seq);
1063 // (b) Evaluate current key sequences.
1064 for (int i = 0; i < keyTables.Count; i++) {
1065 XsdKeyTable seq = (XsdKeyTable) keyTables [i];
1066 if (seq.SelectorMatches (this.elementQNameStack, reader.Depth) != null) {
1067 // creates and registers new entry.
1068 XsdKeyEntry entry = new XsdKeyEntry (seq, reader.Depth, readerLineInfo);
1069 seq.Entries.Add (entry);
1074 private void ValidateKeyFields ()
1076 // (c) Evaluate field paths.
1077 for (int i = 0; i < keyTables.Count; i++) {
1078 XsdKeyTable seq = (XsdKeyTable) keyTables [i];
1079 // If possible, create new field entry candidates.
1080 for (int j = 0; j < seq.Entries.Count; j++) {
1082 ProcessKeyEntry (seq.Entries [j]);
1083 } catch (ValException ex) {
1090 private void ProcessKeyEntry (XsdKeyEntry entry)
1092 bool isNil = XsiNilDepth == Depth;
1093 entry.ProcessMatch (false, elementQNameStack, this, NameTable, BaseURI, SchemaType, NamespaceManager, readerLineInfo, Depth, null, null, null, isNil, CurrentKeyFieldConsumers);
1094 if (MoveToFirstAttribute ()) {
1097 switch (NamespaceURI) {
1098 case XmlNamespaceManager.XmlnsXmlns:
1099 case XmlSchema.InstanceNamespace:
1102 XmlSchemaDatatype dt = SchemaType as XmlSchemaDatatype;
1103 XmlSchemaSimpleType st = SchemaType as XmlSchemaSimpleType;
1104 if (dt == null && st != null)
1106 object identity = null;
1108 identity = dt.ParseValue (Value, NameTable, NamespaceManager);
1109 if (identity == null)
1111 entry.ProcessMatch (true, elementQNameStack, this, NameTable, BaseURI, SchemaType, NamespaceManager, readerLineInfo, Depth, LocalName, NamespaceURI, identity, false, CurrentKeyFieldConsumers);
1112 } while (MoveToNextAttribute ());
1119 private XsdKeyTable CreateNewKeyTable (XmlSchemaIdentityConstraint ident)
1121 XsdKeyTable seq = new XsdKeyTable (ident);
1122 seq.StartDepth = reader.Depth;
1123 this.keyTables.Add (seq);
1127 private void ValidateSimpleContentIdentity (
1128 XmlSchemaDatatype dt, string value)
1130 // Identity field value
1131 if (currentKeyFieldConsumers != null) {
1132 while (this.currentKeyFieldConsumers.Count > 0) {
1133 XsdKeyEntryField field = this.currentKeyFieldConsumers [0] as XsdKeyEntryField;
1134 if (field.Identity != null)
1135 HandleError ("Two or more identical field was found. Former value is '" + field.Identity + "' .");
1136 object identity = null; // This means empty value
1139 identity = dt.ParseValue (value, NameTable, NamespaceManager);
1140 } catch (Exception ex) { // FIXME: (wishlist) This is bad manner ;-(
1141 HandleError ("Identity value is invalid against its data type " + dt.TokenizedType, ex);
1144 if (identity == null)
1147 if (!field.SetIdentityField (identity, reader.Depth == xsiNilDepth, dt as XsdAnySimpleType, this.Depth, readerLineInfo))
1148 HandleError ("Two or more identical key value was found: '" + value + "' .");
1149 this.currentKeyFieldConsumers.RemoveAt (0);
1154 private void EndIdentityValidation (XsdKeyTable seq)
1156 ArrayList errors = null;
1157 for (int i = 0; i < seq.Entries.Count; i++) {
1158 XsdKeyEntry entry = (XsdKeyEntry) seq.Entries [i];
1161 if (seq.SourceSchemaIdentity is XmlSchemaKey) {
1163 errors = new ArrayList ();
1164 errors.Add ("line " + entry.SelectorLineNumber + "position " + entry.SelectorLinePosition);
1168 HandleError ("Invalid identity constraints were found. Key was not found. "
1169 + String.Join (", ", errors.ToArray (typeof (string)) as string []));
1171 // If it is keyref, then find reference target
1172 XmlSchemaKeyref xsdKeyref = seq.SourceSchemaIdentity as XmlSchemaKeyref;
1173 if (xsdKeyref != null)
1174 EndKeyrefValidation (seq, xsdKeyref.Target);
1177 private void EndKeyrefValidation (XsdKeyTable seq, XmlSchemaIdentityConstraint targetIdent)
1179 for (int i = this.keyTables.Count - 1; i >= 0; i--) {
1180 XsdKeyTable target = this.keyTables [i] as XsdKeyTable;
1181 if (target.SourceSchemaIdentity != targetIdent)
1183 seq.ReferencedKey = target;
1184 for (int j = 0; j < seq.FinishedEntries.Count; j++) {
1185 XsdKeyEntry entry = (XsdKeyEntry) seq.FinishedEntries [j];
1186 for (int k = 0; k < target.FinishedEntries.Count; k++) {
1187 XsdKeyEntry targetEntry = (XsdKeyEntry) target.FinishedEntries [k];
1188 if (entry.CompareIdentity (targetEntry)) {
1189 entry.KeyRefFound = true;
1195 if (seq.ReferencedKey == null)
1196 HandleError ("Target key was not found.");
1197 ArrayList errors = null;
1198 for (int i = 0; i < seq.FinishedEntries.Count; i++) {
1199 XsdKeyEntry entry = (XsdKeyEntry) seq.FinishedEntries [i];
1200 if (!entry.KeyRefFound) {
1202 errors = new ArrayList ();
1203 errors.Add (" line " + entry.SelectorLineNumber + ", position " + entry.SelectorLinePosition);
1207 HandleError ("Invalid identity constraints were found. Referenced key was not found: "
1208 + String.Join (" / ", errors.ToArray (typeof (string)) as string []));
1212 // Overrided Methods
1214 public override void Close ()
1219 public override string GetAttribute (int i)
1221 switch (reader.NodeType) {
1222 case XmlNodeType.XmlDeclaration:
1223 case XmlNodeType.DocumentType:
1224 return reader.GetAttribute (i);
1227 if (reader.AttributeCount > i)
1228 reader.GetAttribute (i);
1229 int defIdx = i - reader.AttributeCount;
1230 if (i < AttributeCount)
1231 return defaultAttributes [defIdx].DefaultValue;
1233 throw new ArgumentOutOfRangeException ("i", i, "Specified attribute index is out of range.");
1236 public override string GetAttribute (string name)
1238 switch (reader.NodeType) {
1239 case XmlNodeType.XmlDeclaration:
1240 case XmlNodeType.DocumentType:
1241 return reader.GetAttribute (name);
1244 string value = reader.GetAttribute (name);
1248 QName qname = SplitQName (name);
1249 return GetDefaultAttribute (qname.Name, qname.Namespace);
1252 private QName SplitQName (string name)
1254 if (!XmlChar.IsName (name))
1255 throw new ArgumentException ("Invalid name was specified.", "name");
1257 Exception ex = null;
1258 QName qname = XmlSchemaUtil.ToQName (reader, name, out ex);
1265 public override string GetAttribute (string localName, string ns)
1267 switch (reader.NodeType) {
1268 case XmlNodeType.XmlDeclaration:
1269 case XmlNodeType.DocumentType:
1270 return reader.GetAttribute (localName, ns);
1273 string value = reader.GetAttribute (localName, ns);
1277 return GetDefaultAttribute (localName, ns);
1280 private string GetDefaultAttribute (string localName, string ns)
1282 int idx = this.FindDefaultAttribute (localName, ns);
1285 string value = defaultAttributes [idx].ValidatedDefaultValue;
1287 value = defaultAttributes [idx].ValidatedFixedValue;
1291 private int FindDefaultAttribute (string localName, string ns)
1293 for (int i = 0; i < this.defaultAttributes.Length; i++) {
1294 XsAttribute attr = defaultAttributes [i];
1295 if (attr.QualifiedName.Name == localName &&
1296 (ns == null || attr.QualifiedName.Namespace == ns))
1302 public bool HasLineInfo ()
1304 return readerLineInfo != null && readerLineInfo.HasLineInfo ();
1307 public override string LookupNamespace (string prefix)
1309 return reader.LookupNamespace (prefix);
1312 public override void MoveToAttribute (int i)
1314 switch (reader.NodeType) {
1315 case XmlNodeType.XmlDeclaration:
1316 case XmlNodeType.DocumentType:
1317 reader.MoveToAttribute (i);
1321 currentAttrType = null;
1322 if (i < reader.AttributeCount) {
1323 reader.MoveToAttribute (i);
1324 this.currentDefaultAttribute = -1;
1325 this.defaultAttributeConsumed = false;
1328 if (i < AttributeCount) {
1329 this.currentDefaultAttribute = i - reader.AttributeCount;
1330 this.defaultAttributeConsumed = false;
1333 throw new ArgumentOutOfRangeException ("i", i, "Attribute index is out of range.");
1336 public override bool MoveToAttribute (string name)
1338 switch (reader.NodeType) {
1339 case XmlNodeType.XmlDeclaration:
1340 case XmlNodeType.DocumentType:
1341 return reader.MoveToAttribute (name);
1344 currentAttrType = null;
1345 bool b = reader.MoveToAttribute (name);
1347 this.currentDefaultAttribute = -1;
1348 this.defaultAttributeConsumed = false;
1352 return MoveToDefaultAttribute (name, null);
1355 public override bool MoveToAttribute (string localName, string ns)
1357 switch (reader.NodeType) {
1358 case XmlNodeType.XmlDeclaration:
1359 case XmlNodeType.DocumentType:
1360 return reader.MoveToAttribute (localName, ns);
1363 currentAttrType = null;
1364 bool b = reader.MoveToAttribute (localName, ns);
1366 this.currentDefaultAttribute = -1;
1367 this.defaultAttributeConsumed = false;
1371 return MoveToDefaultAttribute (localName, ns);
1374 private bool MoveToDefaultAttribute (string localName, string ns)
1376 int idx = this.FindDefaultAttribute (localName, ns);
1379 currentDefaultAttribute = idx;
1380 defaultAttributeConsumed = false;
1384 public override bool MoveToElement ()
1386 currentDefaultAttribute = -1;
1387 defaultAttributeConsumed = false;
1388 currentAttrType = null;
1389 return reader.MoveToElement ();
1392 public override bool MoveToFirstAttribute ()
1394 switch (reader.NodeType) {
1395 case XmlNodeType.XmlDeclaration:
1396 case XmlNodeType.DocumentType:
1397 return reader.MoveToFirstAttribute ();
1400 currentAttrType = null;
1401 if (reader.AttributeCount > 0) {
1402 bool b = reader.MoveToFirstAttribute ();
1404 currentDefaultAttribute = -1;
1405 defaultAttributeConsumed = false;
1410 if (this.defaultAttributes.Length > 0) {
1411 currentDefaultAttribute = 0;
1412 defaultAttributeConsumed = false;
1419 public override bool MoveToNextAttribute ()
1421 switch (reader.NodeType) {
1422 case XmlNodeType.XmlDeclaration:
1423 case XmlNodeType.DocumentType:
1424 return reader.MoveToNextAttribute ();
1427 currentAttrType = null;
1428 if (currentDefaultAttribute >= 0) {
1429 if (defaultAttributes.Length == currentDefaultAttribute + 1)
1431 currentDefaultAttribute++;
1432 defaultAttributeConsumed = false;
1436 bool b = reader.MoveToNextAttribute ();
1438 currentDefaultAttribute = -1;
1439 defaultAttributeConsumed = false;
1443 if (defaultAttributes.Length > 0) {
1444 currentDefaultAttribute = 0;
1445 defaultAttributeConsumed = false;
1452 private XmlSchema ReadExternalSchema (string uri)
1454 Uri absUri = resolver.ResolveUri ((BaseURI != "" ? new Uri (BaseURI) : null), uri);
1455 string absUriString = absUri != null ? absUri.ToString () : String.Empty;
1456 XmlTextReader xtr = null;
1458 xtr = new XmlTextReader (absUriString,
1459 (Stream) resolver.GetEntity (
1460 absUri, null, typeof (Stream)),
1462 return XmlSchema.Read (
1463 xtr, ValidationEventHandler);
1470 private void ExamineAdditionalSchema ()
1472 if (resolver == null)
1474 XmlSchema schema = null;
1475 string schemaLocation = reader.GetAttribute ("schemaLocation", XmlSchema.InstanceNamespace);
1476 bool schemaAdded = false;
1477 if (schemaLocation != null) {
1478 string [] tmp = null;
1480 schemaLocation = XsDatatype.FromName ("token", XmlSchema.Namespace).Normalize (schemaLocation);
1481 tmp = schemaLocation.Split (XmlChar.WhitespaceChars);
1482 } catch (Exception ex) {
1483 if (schemas.Count == 0)
1484 HandleError ("Invalid schemaLocation attribute format.", ex, true);
1485 tmp = new string [0];
1487 if (tmp.Length % 2 != 0)
1488 if (schemas.Count == 0)
1489 HandleError ("Invalid schemaLocation attribute format.");
1493 for (; i < tmp.Length; i += 2) {
1494 schema = ReadExternalSchema (tmp [i + 1]);
1495 if (schema.TargetNamespace == null)
1496 schema.TargetNamespace = tmp [i];
1497 else if (schema.TargetNamespace != tmp [i])
1498 HandleError ("Specified schema has different target namespace.");
1499 if (schema != null) {
1500 if (!schemas.Contains (schema.TargetNamespace)) {
1502 schemas.Add (schema);
1507 } catch (Exception) {
1508 if (!schemas.Contains (tmp [i]))
1509 HandleError (String.Format ("Could not resolve schema location URI: {0}",
1510 i + 1 < tmp.Length ? tmp [i + 1] : String.Empty), null, true);
1514 } while (i < tmp.Length);
1516 string noNsSchemaLocation = reader.GetAttribute ("noNamespaceSchemaLocation", XmlSchema.InstanceNamespace);
1517 if (noNsSchemaLocation != null) {
1519 schema = ReadExternalSchema (noNsSchemaLocation);
1520 } catch (Exception) { // FIXME: (wishlist) It is bad manner ;-(
1521 if (schemas.Count != 0)
1522 HandleError ("Could not resolve schema location URI: " + noNsSchemaLocation, null, true);
1524 if (schema != null && schema.TargetNamespace != null)
1525 HandleError ("Specified schema has different target namespace.");
1527 if (schema != null) {
1528 if (!schemas.Contains (schema.TargetNamespace)) {
1530 schemas.Add (schema);
1533 // FIXME: should call Reprocess()?
1538 public override bool Read ()
1540 validationStarted = true;
1541 currentDefaultAttribute = -1;
1542 defaultAttributeConsumed = false;
1543 currentAttrType = null;
1544 defaultAttributes = emptyAttributeArray;
1546 bool result = reader.Read ();
1548 // FIXME: schemaLocation could be specified
1550 if (reader.Depth == 0 &&
1551 reader.NodeType == XmlNodeType.Element) {
1552 // If the reader is DTDValidatingReader (it
1553 // is the default behavior of
1554 // XmlValidatingReader) and DTD didn't appear,
1555 // we could just use its source XmlReader.
1556 DTDValidatingReader dtdr = reader as DTDValidatingReader;
1557 if (dtdr != null && dtdr.DTD == null)
1558 reader = dtdr.Source;
1560 ExamineAdditionalSchema ();
1562 if (schemas.Count == 0)
1564 if (!schemas.IsCompiled)
1567 #region ID Constraints
1568 if (this.checkIdentity)
1569 idManager.OnStartElement ();
1571 // 3.3.4 ElementLocallyValidElement 7 = Root Valid.
1572 if (!result && this.checkIdentity &&
1573 idManager.HasMissingIDReferences ())
1574 HandleError ("There are missing ID references: " + idManager.GetMissingIDString ());
1577 switch (reader.NodeType) {
1578 case XmlNodeType.Element:
1579 #region Key Constraints
1580 if (checkKeyConstraints)
1581 this.elementQNameStack.Add (new QName (reader.LocalName, reader.NamespaceURI));
1584 // If there is no schema information, then no validation is performed.
1585 if (skipValidationDepth < 0 || reader.Depth <= skipValidationDepth) {
1586 ValidateEndSimpleContent ();
1587 AssessStartElementSchemaValidity ();
1590 if (reader.IsEmptyElement)
1591 goto case XmlNodeType.EndElement;
1593 shouldValidateCharacters = true;
1595 case XmlNodeType.EndElement:
1596 if (reader.Depth == skipValidationDepth)
1597 skipValidationDepth = -1;
1598 else if (skipValidationDepth < 0 || reader.Depth <= skipValidationDepth)
1599 AssessEndElementSchemaValidity ();
1601 if (checkKeyConstraints)
1602 elementQNameStack.RemoveAt (elementQNameStack.Count - 1);
1605 case XmlNodeType.CDATA:
1606 case XmlNodeType.SignificantWhitespace:
1607 case XmlNodeType.Whitespace:
1608 case XmlNodeType.Text:
1609 // FIXME: does this check make sense?
1610 ComplexType ct = Context.ActualType as ComplexType;
1611 if (ct != null && storedCharacters.Length > 0) {
1612 switch (ct.ContentType) {
1613 case XmlSchemaContentType.ElementOnly:
1614 case XmlSchemaContentType.Empty:
1615 if (reader.NodeType != XmlNodeType.Whitespace)
1616 HandleError ("Not allowed character content was found.");
1621 ValidateCharacters ();
1628 public override bool ReadAttributeValue ()
1630 if (currentDefaultAttribute < 0)
1631 return reader.ReadAttributeValue ();
1633 if (this.defaultAttributeConsumed)
1636 defaultAttributeConsumed = true;
1641 public override string ReadInnerXml ()
1643 // MS.NET 1.0 has a serious bug here. It skips validation.
1644 return reader.ReadInnerXml ();
1647 public override string ReadOuterXml ()
1649 // MS.NET 1.0 has a serious bug here. It skips validation.
1650 return reader.ReadOuterXml ();
1654 // XmlReader.ReadString() should call derived this.Read().
1655 public override string ReadString ()
1658 return reader.ReadString ();
1660 return base.ReadString ();
1664 // This class itself does not have this feature.
1665 public override void ResolveEntity ()
1667 reader.ResolveEntity ();
1671 internal class XsdValidationContext
1673 public XsdValidationContext ()
1677 // Some of them might be missing (See the spec section 5.3, and also 3.3.4).
1678 public XsElement Element;
1679 public object XsiType; // xsi:type
1680 internal XsdValidationState State;
1682 // Note that it represents current element's type.
1683 public object ActualType {
1685 if (XsiType != null)
1688 return Element != null ? Element.ElementType : null;
1693 public XmlSchemaType ActualSchemaType {
1695 object at = ActualType;
1698 XmlSchemaType st = at as XmlSchemaType;
1700 st = XmlSchemaType.GetBuiltInSimpleType (
1701 ((XmlSchemaDatatype) at).TypeCode);
1707 public bool IsInvalid {
1708 get { return State == XsdValidationState.Invalid; }
1711 public object Clone ()
1713 return MemberwiseClone ();
1716 public void EvaluateStartElement (
1717 string localName, string ns)
1719 State = State.EvaluateStartElement (localName, ns);
1722 public bool EvaluateEndElement ()
1724 return State.EvaluateEndElement ();
1727 public void SetElement (XsElement element)
1733 internal class XsdIDManager
1735 public XsdIDManager ()
1739 Hashtable idList = new Hashtable ();
1740 ArrayList missingIDReferences;
1741 string thisElementId;
1743 private ArrayList MissingIDReferences {
1745 if (missingIDReferences == null)
1746 missingIDReferences = new ArrayList ();
1747 return missingIDReferences;
1751 public void OnStartElement ()
1753 thisElementId = null;
1757 public string AssessEachAttributeIdentityConstraint (
1758 XsDatatype dt, object parsedValue, string elementName)
1760 // Validate identity constraints.
1761 string str = parsedValue as string;
1762 switch (dt.TokenizedType) {
1763 case XmlTokenizedType.ID:
1764 if (thisElementId != null)
1765 return "ID type attribute was already assigned in the containing element.";
1767 thisElementId = str;
1768 if (idList.ContainsKey (str))
1769 return "Duplicate ID value was found.";
1771 idList.Add (str, elementName);
1772 if (MissingIDReferences.Contains (str))
1773 MissingIDReferences.Remove (str);
1775 case XmlTokenizedType.IDREF:
1776 if (!idList.Contains (str))
1777 MissingIDReferences.Add (str);
1779 case XmlTokenizedType.IDREFS:
1780 string [] idrefs = (string []) parsedValue;
1781 for (int i = 0; i < idrefs.Length; i++) {
1782 string id = idrefs [i];
1783 if (!idList.Contains (id))
1784 MissingIDReferences.Add (id);
1791 public bool HasMissingIDReferences ()
1793 return missingIDReferences != null
1794 && missingIDReferences.Count > 0;
1797 public string GetMissingIDString ()
1799 return String.Join (" ",
1800 MissingIDReferences.ToArray (typeof (string))