(DISTFILES): Comment out a few missing files.
[mono-project.git] / mcs / class / System.XML / Mono.Xml.Schema / XsdValidatingReader.cs
blobae919147d47782ab5abfd69eb5900e8c553f3d42
1 //
2 // Mono.Xml.Schema.XsdValidatingReader.cs
3 //
4 // Author:
5 // Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
6 //
7 // (C)2003 Atsushi Enomoto
8 //
9 // Note:
11 // This class doesn't support set_XmlResolver, since it isn't common to XmlReader interface.
12 // Try to set that of xml reader which is used to construct this object.
16 // Permission is hereby granted, free of charge, to any person obtaining
17 // a copy of this software and associated documentation files (the
18 // "Software"), to deal in the Software without restriction, including
19 // without limitation the rights to use, copy, modify, merge, publish,
20 // distribute, sublicense, and/or sell copies of the Software, and to
21 // permit persons to whom the Software is furnished to do so, subject to
22 // the following conditions:
23 //
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
26 //
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 using System;
36 using System.Collections;
37 using System.Collections.Specialized;
38 using System.Text;
39 using System.Xml;
40 using System.Xml.Schema;
41 using Mono.Xml;
43 namespace Mono.Xml.Schema
45 internal class XsdValidatingReader : XmlReader, IXmlLineInfo, IHasXmlSchemaInfo, IHasXmlParserContext, IXmlNamespaceResolver
47 static char [] wsChars = new char [] {' ', '\t', '\n', '\r'};
49 XmlReader reader;
50 XmlValidatingReader xvReader;
51 XmlResolver resolver;
52 IHasXmlSchemaInfo sourceReaderSchemaInfo;
53 IXmlLineInfo readerLineInfo;
54 bool laxElementValidation = true;
55 bool reportNoValidationError;
56 XmlSchemaSet schemas = new XmlSchemaSet ();
57 bool namespaces = true;
59 Hashtable idList = new Hashtable ();
60 ArrayList missingIDReferences;
61 string thisElementId;
63 ArrayList keyTables = new ArrayList ();
64 ArrayList currentKeyFieldConsumers;
66 XsdValidationStateManager stateManager = new XsdValidationStateManager ();
67 XsdValidationContext context = new XsdValidationContext ();
68 XsdValidationState childParticleState;
70 int xsiNilDepth = -1;
71 StringBuilder storedCharacters = new StringBuilder ();
72 bool shouldValidateCharacters;
73 int skipValidationDepth = -1;
75 XmlSchemaAttribute [] defaultAttributes = new XmlSchemaAttribute [0];
76 int currentDefaultAttribute = -1;
77 XmlQualifiedName currentQName;
79 ArrayList elementQNameStack = new ArrayList ();
80 bool popContext;
82 // Property Cache.
83 int nonDefaultAttributeCount;
84 bool defaultAttributeConsumed;
86 // Validation engine cached object
87 ArrayList defaultAttributesCache;
88 ArrayList tmpKeyrefPool;
90 #region .ctor
91 public XsdValidatingReader (XmlReader reader)
92 : this (reader, null)
96 public XsdValidatingReader (XmlReader reader, XmlReader validatingReader)
98 this.reader = reader;
99 xvReader = validatingReader as XmlValidatingReader;
100 if (xvReader != null) {
101 if (xvReader.ValidationType == ValidationType.None)
102 reportNoValidationError = true;
104 readerLineInfo = reader as IXmlLineInfo;
105 sourceReaderSchemaInfo = reader as IHasXmlSchemaInfo;
107 #endregion
108 // Provate Properties
109 private XmlQualifiedName CurrentQName {
110 get {
111 if (currentQName == null)
112 currentQName = new XmlQualifiedName (LocalName, NamespaceURI);
113 return currentQName;
117 internal ArrayList CurrentKeyFieldConsumers {
118 get {
119 if (currentKeyFieldConsumers == null)
120 currentKeyFieldConsumers = new ArrayList ();
121 return currentKeyFieldConsumers;
125 private ArrayList DefaultAttributesCache {
126 get {
127 if (defaultAttributesCache == null)
128 defaultAttributesCache = new ArrayList ();
129 return defaultAttributesCache;
133 private ArrayList MissingIDReferences {
134 get {
135 if (missingIDReferences == null)
136 missingIDReferences = new ArrayList ();
137 return missingIDReferences;
141 // Public Non-overrides
143 public int XsiNilDepth {
144 get { return xsiNilDepth; }
147 public bool Namespaces {
148 get { return namespaces; }
149 set { namespaces = value; }
152 public XmlReader Reader {
153 get { return reader; }
156 // This is required to resolve xsi:schemaLocation
157 public XmlResolver XmlResolver {
158 set {
159 resolver = value;
163 // This should be changed before the first Read() call.
164 public XmlSchemaSet Schemas {
165 get { return schemas; }
166 set {
167 if (ReadState != ReadState.Initial)
168 throw new InvalidOperationException ("Schemas must be set before the first call to Read().");
169 schemas = value;
173 public object SchemaType {
174 get {
175 if (ReadState != ReadState.Interactive)
176 return null;
178 switch (NodeType) {
179 case XmlNodeType.Element:
180 if (context.ActualType != null)
181 return context.ActualType;
182 else if (context.Element != null)
183 return context.Element.ElementType;
184 else
185 return SourceReaderSchemaType;
186 case XmlNodeType.Attribute:
187 XmlSchemaComplexType ct = context.ActualType as XmlSchemaComplexType;
188 if (ct != null) {
189 XmlSchemaAttribute attdef = ct.AttributeUses [CurrentQName] as XmlSchemaAttribute;
190 if (attdef != null)
191 return attdef.AttributeType;
193 return SourceReaderSchemaType;
194 default:
195 return SourceReaderSchemaType;
200 private object SourceReaderSchemaType {
201 get { return this.sourceReaderSchemaInfo != null ? sourceReaderSchemaInfo.SchemaType : null; }
204 // This property is never used in Mono.
205 public ValidationType ValidationType {
206 get {
207 if (reportNoValidationError)
208 return ValidationType.None;
209 else
210 return ValidationType.Schema;
214 IDictionary IXmlNamespaceResolver.GetNamespacesInScope (XmlNamespaceScope scope)
216 IXmlNamespaceResolver resolver = reader as IXmlNamespaceResolver;
217 if (resolver == null)
218 throw new NotSupportedException ("The input XmlReader does not implement IXmlNamespaceResolver and thus this validating reader cannot collect in-scope namespaces.");
219 return resolver.GetNamespacesInScope (scope);
222 string IXmlNamespaceResolver.LookupPrefix (string ns)
224 return ((IXmlNamespaceResolver) this).LookupPrefix (ns, false);
227 string IXmlNamespaceResolver.LookupPrefix (string ns, bool atomizedNames)
229 IXmlNamespaceResolver resolver = reader as IXmlNamespaceResolver;
230 if (resolver == null)
231 throw new NotSupportedException ("The input XmlReader does not implement IXmlNamespaceResolver and thus this validating reader cannot execute namespace prefix lookup.");
232 return resolver.LookupPrefix (ns, atomizedNames);
235 // It is used only for independent XmlReader use, not for XmlValidatingReader.
236 #if NET_2_0
237 public override object ReadTypedValue ()
238 #else
239 public object ReadTypedValue ()
240 #endif
242 XmlSchemaDatatype dt = SchemaType as XmlSchemaDatatype;
243 XmlSchemaSimpleType st = SchemaType as XmlSchemaSimpleType;
244 if (st != null)
245 dt = st.Datatype;
246 if (dt == null)
247 return null;
249 switch (NodeType) {
250 case XmlNodeType.Element:
251 if (IsEmptyElement)
252 return null;
254 storedCharacters.Length = 0;
255 bool loop = true;
256 do {
257 Read ();
258 switch (NodeType) {
259 case XmlNodeType.SignificantWhitespace:
260 case XmlNodeType.Text:
261 case XmlNodeType.CDATA:
262 storedCharacters.Append (Value);
263 break;
264 case XmlNodeType.Comment:
265 break;
266 default:
267 loop = false;
268 break;
270 } while (loop && !EOF && ReadState == ReadState.Interactive);
271 return dt.ParseValue (storedCharacters.ToString (), NameTable, ParserContext.NamespaceManager);
272 case XmlNodeType.Attribute:
273 return dt.ParseValue (Value, NameTable, ParserContext.NamespaceManager);
275 return null;
278 public ValidationEventHandler ValidationEventHandler;
280 // Public Overrided Properties
282 public override int AttributeCount {
283 get {
284 return nonDefaultAttributeCount + defaultAttributes.Length;
288 public override string BaseURI {
289 get { return reader.BaseURI; }
292 // If this class is used to implement XmlValidatingReader,
293 // it should be left to DTDValidatingReader. In other cases,
294 // it depends on the reader's ability.
295 public override bool CanResolveEntity {
296 get { return reader.CanResolveEntity; }
299 public override int Depth {
300 get {
301 if (currentDefaultAttribute < 0)
302 return reader.Depth;
303 if (this.defaultAttributeConsumed)
304 return reader.Depth + 2;
305 return reader.Depth + 1;
309 public override bool EOF {
310 get { return reader.EOF; }
313 public override bool HasValue {
314 get {
315 if (currentDefaultAttribute < 0)
316 return reader.HasValue;
317 return true;
321 public override bool IsDefault {
322 get {
323 if (currentDefaultAttribute < 0)
324 return reader.IsDefault;
325 return true;
329 public override bool IsEmptyElement {
330 get {
331 if (currentDefaultAttribute < 0)
332 return reader.IsEmptyElement;
333 return false;
337 public override string this [int i] {
338 get { return GetAttribute (i); }
341 public override string this [string name] {
342 get { return GetAttribute (name); }
345 public override string this [string localName, string ns] {
346 get { return GetAttribute (localName, ns); }
349 int IXmlLineInfo.LineNumber {
350 get { return readerLineInfo != null ? readerLineInfo.LineNumber : 0; }
353 int IXmlLineInfo.LinePosition {
354 get { return readerLineInfo != null ? readerLineInfo.LinePosition : 0; }
357 public override string LocalName {
358 get {
359 if (currentDefaultAttribute < 0)
360 return reader.LocalName;
361 if (defaultAttributeConsumed)
362 return String.Empty;
363 return defaultAttributes [currentDefaultAttribute].QualifiedName.Name;
367 public override string Name {
368 get {
369 if (currentDefaultAttribute < 0)
370 return reader.Name;
371 if (defaultAttributeConsumed)
372 return String.Empty;
374 XmlQualifiedName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
375 string prefix = Prefix;
376 if (prefix == String.Empty)
377 return qname.Name;
378 else
379 return String.Concat (prefix, ":", qname.Name);
383 public override string NamespaceURI {
384 get {
385 if (currentDefaultAttribute < 0)
386 return reader.NamespaceURI;
387 if (defaultAttributeConsumed)
388 return String.Empty;
389 return defaultAttributes [currentDefaultAttribute].QualifiedName.Namespace;
393 public override XmlNameTable NameTable {
394 get { return reader.NameTable; }
397 public override XmlNodeType NodeType {
398 get {
399 if (currentDefaultAttribute < 0)
400 return reader.NodeType;
401 if (defaultAttributeConsumed)
402 return XmlNodeType.Text;
403 return XmlNodeType.Attribute;
407 public XmlParserContext ParserContext {
408 get { return XmlSchemaUtil.GetParserContext (reader); }
411 public override string Prefix {
412 get {
413 if (currentDefaultAttribute < 0)
414 return reader.Prefix;
415 if (defaultAttributeConsumed)
416 return String.Empty;
417 XmlQualifiedName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
418 string prefix = this.ParserContext.NamespaceManager.LookupPrefix (qname.Namespace, false);
419 if (prefix == null)
420 return String.Empty;
421 else
422 return prefix;
426 public override char QuoteChar {
427 get { return reader.QuoteChar; }
430 public override ReadState ReadState {
431 get { return reader.ReadState; }
434 public override string Value {
435 get {
436 if (currentDefaultAttribute < 0)
437 return reader.Value;
438 string value = defaultAttributes [currentDefaultAttribute].ValidatedDefaultValue;
439 if (value == null)
440 value = defaultAttributes [currentDefaultAttribute].ValidatedFixedValue;
441 return value;
445 XmlQualifiedName qnameXmlLang = new XmlQualifiedName ("lang", XmlNamespaceManager.XmlnsXml);
447 public override string XmlLang {
448 get {
449 string xmlLang = reader.XmlLang;
450 if (xmlLang != null)
451 return xmlLang;
452 int idx = this.FindDefaultAttribute ("lang", XmlNamespaceManager.XmlnsXml);
453 if (idx < 0)
454 return null;
455 xmlLang = defaultAttributes [idx].ValidatedDefaultValue;
456 if (xmlLang == null)
457 xmlLang = defaultAttributes [idx].ValidatedFixedValue;
458 return xmlLang;
462 public override XmlSpace XmlSpace {
463 get {
464 XmlSpace space = reader.XmlSpace;
465 if (space != XmlSpace.None)
466 return space;
467 int idx = this.FindDefaultAttribute ("space", XmlNamespaceManager.XmlnsXml);
468 if (idx < 0)
469 return XmlSpace.None;
470 string spaceSpec = defaultAttributes [idx].ValidatedDefaultValue;
471 if (spaceSpec == null)
472 spaceSpec = defaultAttributes [idx].ValidatedFixedValue;
473 return (XmlSpace) Enum.Parse (typeof (XmlSpace), spaceSpec, false);
477 // Private Methods
479 private XmlQualifiedName QualifyName (string name)
481 return XmlQualifiedName.Parse (name, this);
484 private void HandleError (string error)
486 HandleError (error, null);
489 private void HandleError (string error, Exception innerException)
491 HandleError (error, innerException, false);
494 private void HandleError (string error, Exception innerException, bool isWarning)
496 if (reportNoValidationError) // extra quick check
497 return;
499 XmlSchemaException schemaException = new XmlSchemaException (error,
500 this, this.BaseURI, null, innerException);
501 HandleError (schemaException, isWarning);
504 private void HandleError (XmlSchemaException schemaException)
506 HandleError (schemaException, false);
509 private void HandleError (XmlSchemaException schemaException, bool isWarning)
511 if (reportNoValidationError)
512 return;
514 ValidationEventArgs e = new ValidationEventArgs (schemaException,
515 schemaException.Message, isWarning ? XmlSeverityType.Warning : XmlSeverityType.Error);
517 if (this.ValidationEventHandler != null)
518 this.ValidationEventHandler (this, e);
519 else if (xvReader != null)
520 xvReader.OnValidationEvent (this, e);
521 else if (e.Severity == XmlSeverityType.Error)
522 #if NON_MONO_ENV
523 this.xvReader.OnValidationEvent (this, e);
524 #else
525 throw e.Exception;
526 #endif
529 private XmlSchemaElement FindElement (string name, string ns)
531 return (XmlSchemaElement) schemas.GlobalElements [new XmlQualifiedName (name, ns)];
534 private XmlSchemaType FindType (XmlQualifiedName qname)
536 return (XmlSchemaType) schemas.GlobalTypes [qname];
539 private void ValidateStartElementParticle ()
541 stateManager.CurrentElement = null;
542 context.ParticleState = context.ParticleState.EvaluateStartElement (reader.LocalName, reader.NamespaceURI);
543 if (context.ParticleState == XsdValidationState.Invalid)
544 HandleError ("Invalid start element: " + reader.NamespaceURI + ":" + reader.LocalName);
546 context.Element = stateManager.CurrentElement;
547 if (context.Element != null)
548 context.SchemaType = context.Element.ElementType;
551 private void ValidateEndElementParticle ()
553 if (childParticleState != null) {
554 if (!childParticleState.EvaluateEndElement ()) {
555 HandleError ("Invalid end element: " + reader.Name);
558 context.PopScope (reader.Depth);
561 // Utility for missing validation completion related to child items.
562 private void ValidateCharacters ()
564 if (xsiNilDepth >= 0 && xsiNilDepth < reader.Depth)
565 HandleError ("Element item appeared, while current element context is nil.");
567 storedCharacters.Append (reader.Value);
570 // Utility for missing validation completion related to child items.
571 private void ValidateEndCharacters ()
573 if (context.ActualType == null)
574 return;
576 string value = storedCharacters.ToString ();
578 if (storedCharacters.Length == 0) {
579 // 3.3.4 Element Locally Valid (Element) 5.1.2
580 if (context.Element != null) {
581 if (context.Element.ValidatedDefaultValue != null)
582 value = context.Element.ValidatedDefaultValue;
586 XmlSchemaDatatype dt = context.ActualType as XmlSchemaDatatype;
587 XmlSchemaSimpleType st = context.ActualType as XmlSchemaSimpleType;
588 if (dt == null) {
589 if (st != null) {
590 dt = st.Datatype;
591 } else {
592 XmlSchemaComplexType ct = context.ActualType as XmlSchemaComplexType;
593 dt = ct.Datatype;
594 switch (ct.ContentType) {
595 case XmlSchemaContentType.ElementOnly:
596 case XmlSchemaContentType.Empty:
597 if (storedCharacters.Length > 0)
598 HandleError ("Character content not allowed.");
599 break;
603 if (dt != null) {
604 // 3.3.4 Element Locally Valid (Element) :: 5.2.2.2. Fixed value constraints
605 if (context.Element != null && context.Element.ValidatedFixedValue != null)
606 if (value != context.Element.ValidatedFixedValue)
607 HandleError ("Fixed value constraint was not satisfied.");
608 AssessStringValid (st, dt, value);
611 // Identity field value
612 if (currentKeyFieldConsumers != null) {
613 while (this.currentKeyFieldConsumers.Count > 0) {
614 XsdKeyEntryField field = this.currentKeyFieldConsumers [0] as XsdKeyEntryField;
615 if (field.Identity != null)
616 HandleError ("Two or more identical field was found. Former value is '" + field.Identity + "' .");
617 object identity = null; // This means empty value
618 if (dt != null) {
619 try {
620 identity = dt.ParseValue (value, NameTable, ParserContext.NamespaceManager);
621 } catch (Exception ex) { // FIXME: (wishlist) This is bad manner ;-(
622 HandleError ("Identity value is invalid against its data type " + dt.TokenizedType, ex);
625 if (identity == null)
626 identity = value;
628 if (!field.SetIdentityField (identity, reader.Depth == xsiNilDepth, dt as XsdAnySimpleType, this))
629 HandleError ("Two or more identical key value was found: '" + value + "' .");
630 this.currentKeyFieldConsumers.RemoveAt (0);
634 shouldValidateCharacters = false;
637 // 3.14.4 String Valid
638 private void AssessStringValid (XmlSchemaSimpleType st,
639 XmlSchemaDatatype dt, string value)
641 XmlSchemaDatatype validatedDatatype = dt;
642 if (st != null) {
643 string normalized = validatedDatatype.Normalize (value);
644 string [] values;
645 XmlSchemaDatatype itemDatatype;
646 XmlSchemaSimpleType itemSimpleType;
647 switch (st.DerivedBy) {
648 case XmlSchemaDerivationMethod.List:
649 XmlSchemaSimpleTypeList listContent = st.Content as XmlSchemaSimpleTypeList;
650 values = normalized.Split (wsChars);
651 itemDatatype = listContent.ValidatedListItemType as XmlSchemaDatatype;
652 itemSimpleType = listContent.ValidatedListItemType as XmlSchemaSimpleType;
653 for (int vi = 0; vi < values.Length; vi++) {
654 string each = values [vi];
655 if (each == String.Empty)
656 continue;
657 // validate against ValidatedItemType
658 if (itemDatatype != null) {
659 try {
660 itemDatatype.ParseValue (each, NameTable, ParserContext.NamespaceManager);
661 } catch (Exception ex) { // FIXME: (wishlist) better exception handling ;-(
662 HandleError ("List type value contains one or more invalid values.", ex);
663 break;
666 else
667 AssessStringValid (itemSimpleType, itemSimpleType.Datatype, each);
669 break;
670 case XmlSchemaDerivationMethod.Union:
671 XmlSchemaSimpleTypeUnion union = st.Content as XmlSchemaSimpleTypeUnion;
673 string each = normalized;
674 // validate against ValidatedItemType
675 bool passed = false;
676 foreach (object eachType in union.ValidatedTypes) {
677 itemDatatype = eachType as XmlSchemaDatatype;
678 itemSimpleType = eachType as XmlSchemaSimpleType;
679 if (itemDatatype != null) {
680 try {
681 itemDatatype.ParseValue (each, NameTable, ParserContext.NamespaceManager);
682 } catch (Exception) { // FIXME: (wishlist) better exception handling ;-(
683 continue;
686 else {
687 try {
688 AssessStringValid (itemSimpleType, itemSimpleType.Datatype, each);
689 } catch (XmlSchemaException) {
690 continue;
693 passed = true;
694 break;
696 if (!passed) {
697 HandleError ("Union type value contains one or more invalid values.");
698 break;
701 break;
702 case XmlSchemaDerivationMethod.Restriction:
703 XmlSchemaSimpleTypeRestriction str = st.Content as XmlSchemaSimpleTypeRestriction;
704 // facet validation
705 if (str != null) {
706 /* Don't forget to validate against inherited type's facets
707 * Could we simplify this by assuming that the basetype will also
708 * be restriction?
709 * */
710 // mmm, will check later.
711 XmlSchemaSimpleType baseType = st.BaseXmlSchemaType as XmlSchemaSimpleType;
712 if (baseType != null) {
713 AssessStringValid(baseType, dt, normalized);
715 if (!str.ValidateValueWithFacets (normalized, NameTable)) {
716 HandleError ("Specified value was invalid against the facets.");
717 break;
720 validatedDatatype = st.Datatype;
721 break;
724 if (validatedDatatype != null) {
725 try {
726 validatedDatatype.ParseValue (value, NameTable, ParserContext.NamespaceManager);
727 } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
728 HandleError ("Invalidly typed data was specified.", ex);
733 private object GetLocalTypeDefinition (string name)
735 object xsiType = null;
736 XmlQualifiedName typeQName = QualifyName (name);
737 if (typeQName == XmlSchemaComplexType.AnyTypeName)
738 xsiType = XmlSchemaComplexType.AnyType;
739 else if (XmlSchemaUtil.IsBuiltInDatatypeName (typeQName))
740 xsiType = XmlSchemaDatatype.FromName (typeQName);
741 else
742 xsiType = FindType (typeQName);
743 return xsiType;
746 // It is common to ElementLocallyValid::4 and SchemaValidityAssessment::1.2.1.2.4
747 private void AssessLocalTypeDerivationOK (object xsiType, object baseType, XmlSchemaDerivationMethod flag)
749 XmlSchemaType xsiSchemaType = xsiType as XmlSchemaType;
750 XmlSchemaComplexType baseComplexType = baseType as XmlSchemaComplexType;
751 XmlSchemaComplexType xsiComplexType = xsiSchemaType as XmlSchemaComplexType;
752 if (xsiType != baseType) {
753 // Extracted (not extraneous) check for 3.4.6 TypeDerivationOK.
754 if (baseComplexType != null)
755 flag |= baseComplexType.BlockResolved;
756 if (flag == XmlSchemaDerivationMethod.All) {
757 HandleError ("Prohibited element type substitution.");
758 return;
759 } else if (xsiSchemaType != null && (flag & xsiSchemaType.DerivedBy) != 0) {
760 HandleError ("Prohibited element type substitution.");
761 return;
765 if (xsiComplexType != null)
766 try {
767 xsiComplexType.ValidateTypeDerivationOK (baseType, null, null);
768 } catch (XmlSchemaException ex) {
769 // HandleError ("Locally specified schema complex type derivation failed. " + ex.Message, ex);
770 HandleError (ex);
772 else {
773 XmlSchemaSimpleType xsiSimpleType = xsiType as XmlSchemaSimpleType;
774 if (xsiSimpleType != null) {
775 try {
776 xsiSimpleType.ValidateTypeDerivationOK (baseType, null, null, true);
777 } catch (XmlSchemaException ex) {
778 // HandleError ("Locally specified schema simple type derivation failed. " + ex.Message, ex);
779 HandleError (ex);
782 else if (xsiType is XmlSchemaDatatype) {
783 // do nothing
785 else
786 HandleError ("Primitive data type cannot be derived type using xsi:type specification.");
790 // Section 3.3.4 of the spec.
791 private void AssessStartElementSchemaValidity ()
793 // If the reader is inside xsi:nil (and failed on validation),
794 // then simply skip its content.
795 if (xsiNilDepth >= 0 && xsiNilDepth < reader.Depth)
796 HandleError ("Element item appeared, while current element context is nil.");
798 context.Load (reader.Depth);
799 if (childParticleState != null) {
800 context.ParticleState = childParticleState;
801 childParticleState = null;
804 // If validation state exists, then first assess particle validity.
805 context.SchemaType = null;
806 if (context.ParticleState != null) {
807 ValidateStartElementParticle ();
810 string xsiNilValue = reader.GetAttribute ("nil", XmlSchema.InstanceNamespace);
811 if (xsiNilValue != null)
812 xsiNilValue = xsiNilValue.Trim (XmlChar.WhitespaceChars);
813 bool isXsiNil = xsiNilValue == "true";
814 if (isXsiNil && this.xsiNilDepth < 0)
815 xsiNilDepth = reader.Depth;
817 // [Schema Validity Assessment (Element) 1.2]
818 // Evaluate "local type definition" from xsi:type.
819 // (See spec 3.3.4 Schema Validity Assessment (Element) 1.2.1.2.3.
820 // Note that Schema Validity Assessment(Element) 1.2 takes
821 // precedence than 1.1 of that.
823 string xsiTypeName = reader.GetAttribute ("type", XmlSchema.InstanceNamespace);
824 if (xsiTypeName != null) {
825 xsiTypeName = xsiTypeName.Trim (XmlChar.WhitespaceChars);
826 object xsiType = GetLocalTypeDefinition (xsiTypeName);
827 if (xsiType == null)
828 HandleError ("The instance type was not found: " + xsiTypeName + " .");
829 else {
830 XmlSchemaType xsiSchemaType = xsiType as XmlSchemaType;
831 if (xsiSchemaType != null && this.context.Element != null) {
832 XmlSchemaType elemBaseType = context.Element.ElementType as XmlSchemaType;
833 if (elemBaseType != null && (xsiSchemaType.DerivedBy & elemBaseType.FinalResolved) != 0)
834 HandleError ("The instance type is prohibited by the type of the context element.");
835 if (elemBaseType != xsiType && (xsiSchemaType.DerivedBy & this.context.Element.BlockResolved) != 0)
836 HandleError ("The instance type is prohibited by the context element.");
838 XmlSchemaComplexType xsiComplexType = xsiType as XmlSchemaComplexType;
839 if (xsiComplexType != null && xsiComplexType.IsAbstract)
840 HandleError ("The instance type is abstract: " + xsiTypeName + " .");
841 else {
842 // If current schema type exists, then this xsi:type must be
843 // valid extension of that type. See 1.2.1.2.4.
844 if (context.Element != null) {
845 AssessLocalTypeDerivationOK (xsiType, context.Element.ElementType, context.Element.BlockResolved);
847 AssessStartElementLocallyValidType (xsiType); // 1.2.2:
848 context.LocalTypeDefinition = xsiType;
852 else
853 context.LocalTypeDefinition = null;
855 // Create Validation Root, if not exist.
856 // [Schema Validity Assessment (Element) 1.1]
857 if (context.Element == null)
858 context.Element = FindElement (reader.LocalName, reader.NamespaceURI);
859 if (context.Element != null) {
860 if (xsiTypeName == null) {
861 context.SchemaType = context.Element.ElementType;
862 AssessElementLocallyValidElement (context.Element, xsiNilValue); // 1.1.2
864 } else {
865 XmlSchema schema;
866 switch (stateManager.ProcessContents) {
867 case XmlSchemaContentProcessing.Skip:
868 break;
869 case XmlSchemaContentProcessing.Lax:
871 schema = schemas [reader.NamespaceURI];
872 if (schema != null && !schema.missedSubComponents)
873 HandleError ("Element declaration for " + reader.LocalName + " is missing.");
875 break;
876 default:
877 if (xsiTypeName == null &&
878 (schemas.Contains (reader.NamespaceURI) ||
879 !schemas.MissedSubComponents (reader.NamespaceURI)))
880 HandleError ("Element declaration for " + reader.LocalName + " is missing.");
881 break;
885 if (stateManager.ProcessContents == XmlSchemaContentProcessing.Skip)
886 skipValidationDepth = reader.Depth;
888 // Finally, create child particle state.
889 XmlSchemaComplexType xsComplexType = SchemaType as XmlSchemaComplexType;
890 if (xsComplexType != null)
891 childParticleState = stateManager.Create (xsComplexType.ValidatableParticle);
892 else if (stateManager.ProcessContents == XmlSchemaContentProcessing.Lax)
893 childParticleState = stateManager.Create (XmlSchemaAny.AnyTypeContent);
894 else
895 childParticleState = stateManager.Create (XmlSchemaParticle.Empty);
897 AssessStartIdentityConstraints ();
899 context.PushScope (reader.Depth);
902 // 3.3.4 Element Locally Valid (Element)
903 private void AssessElementLocallyValidElement (XmlSchemaElement element, string xsiNilValue)
905 XmlQualifiedName qname = new XmlQualifiedName (reader.LocalName, reader.NamespaceURI);
906 // 1.
907 if (element == null)
908 HandleError ("Element declaration is required for " + qname);
909 // 2.
910 if (element.ActualIsAbstract)
911 HandleError ("Abstract element declaration was specified for " + qname);
912 // 3.1.
913 if (!element.ActualIsNillable && xsiNilValue != null)
914 HandleError ("This element declaration is not nillable: " + qname);
915 // 3.2.
916 // Note that 3.2.1 xsi:nil constraints are to be validated in
917 else if (xsiNilValue == "true") {
918 // AssessElementSchemaValidity() and ValidateCharacters()
920 if (element.ValidatedFixedValue != null)
921 HandleError ("Schema instance nil was specified, where the element declaration for " + qname + "has fixed value constraints.");
923 // 4.
924 string xsiType = reader.GetAttribute ("type", XmlSchema.InstanceNamespace);
925 if (xsiType != null) {
926 context.LocalTypeDefinition = GetLocalTypeDefinition (xsiType);
927 AssessLocalTypeDerivationOK (context.LocalTypeDefinition, element.ElementType, element.BlockResolved);
929 else
930 context.LocalTypeDefinition = null;
932 // 5 Not all things cannot be assessed here.
933 // It is common to 5.1 and 5.2
934 if (element.ElementType != null)
935 AssessStartElementLocallyValidType (SchemaType);
937 // 6. should be out from here.
938 // See invokation of AssessStartIdentityConstraints().
940 // 7 is going to be validated in Read() (in case of xmlreader's EOF).
943 // 3.3.4 Element Locally Valid (Type)
944 private void AssessStartElementLocallyValidType (object schemaType)
946 if (schemaType == null) { // 1.
947 HandleError ("Schema type does not exist.");
948 return;
950 XmlSchemaComplexType cType = schemaType as XmlSchemaComplexType;
951 XmlSchemaSimpleType sType = schemaType as XmlSchemaSimpleType;
952 if (sType != null) {
953 // 3.1.1.
954 while (reader.MoveToNextAttribute ()) {
955 if (reader.NamespaceURI == XmlNamespaceManager.XmlnsXmlns)
956 continue;
957 if (reader.NamespaceURI != XmlSchema.InstanceNamespace)
958 HandleError ("Current simple type cannot accept attributes other than schema instance namespace.");
959 switch (reader.LocalName) {
960 case "type":
961 case "nil":
962 case "schemaLocation":
963 case "noNamespaceSchemaLocation":
964 break;
965 default:
966 HandleError ("Unknown schema instance namespace attribute: " + reader.LocalName);
967 break;
970 reader.MoveToElement ();
971 // 3.1.2 and 3.1.3 cannot be assessed here.
972 } else if (cType != null) {
973 if (cType.IsAbstract) { // 2.
974 HandleError ("Target complex type is abstract.");
975 return;
977 // 3.2
978 AssessElementLocallyValidComplexType (cType);
982 // 3.4.4 Element Locally Valid (Complex Type)
983 private void AssessElementLocallyValidComplexType (XmlSchemaComplexType cType)
985 // 1.
986 if (cType.IsAbstract)
987 HandleError ("Target complex type is abstract.");
989 // 2 (xsi:nil and content prohibition)
990 // See AssessStartElementSchemaValidity() and ValidateCharacters()
992 string elementNs = reader.NamespaceURI;
993 // 3. attribute uses and
994 // 5. wild IDs
995 while (reader.MoveToNextAttribute ()) {
996 if (reader.NamespaceURI == "http://www.w3.org/2000/xmlns/")
997 continue;
998 else if (reader.NamespaceURI == XmlSchema.InstanceNamespace)
999 continue;
1000 XmlQualifiedName qname = new XmlQualifiedName (reader.LocalName, reader.NamespaceURI);
1001 XmlSchemaObject attMatch = FindAttributeDeclaration (cType, qname, elementNs);
1002 if (attMatch == null)
1003 HandleError ("Attribute declaration was not found for " + qname);
1004 else {
1005 XmlSchemaAttribute attdecl = attMatch as XmlSchemaAttribute;
1006 if (attdecl == null) { // i.e. anyAttribute
1007 XmlSchemaAnyAttribute anyAttrMatch = attMatch as XmlSchemaAnyAttribute;
1008 } else {
1009 AssessAttributeLocallyValidUse (attdecl);
1010 AssessAttributeLocallyValid (attdecl, true);
1014 reader.MoveToElement ();
1016 // Collect default attributes.
1017 // 4.
1018 foreach (DictionaryEntry entry in cType.AttributeUses) {
1019 XmlSchemaAttribute attr = (XmlSchemaAttribute) entry.Value;
1020 if (reader [attr.QualifiedName.Name, attr.QualifiedName.Namespace] == null) {
1021 if (attr.ValidatedUse == XmlSchemaUse.Required &&
1022 attr.ValidatedFixedValue == null)
1023 HandleError ("Required attribute " + attr.QualifiedName + " was not found.");
1024 else if (attr.ValidatedDefaultValue != null)
1025 DefaultAttributesCache.Add (attr);
1026 else if (attr.ValidatedFixedValue != null)
1027 DefaultAttributesCache.Add (attr);
1030 defaultAttributes = (XmlSchemaAttribute [])
1031 DefaultAttributesCache.ToArray (typeof (XmlSchemaAttribute));
1032 context.DefaultAttributes = defaultAttributes;
1033 if (defaultAttributesCache != null)
1034 defaultAttributesCache.Clear ();
1035 // 5. wild IDs was already checked above.
1038 // Spec 3.10.4 Item Valid (Wildcard)
1039 private bool AttributeWildcardItemValid (XmlSchemaAnyAttribute anyAttr, XmlQualifiedName qname)
1041 if (anyAttr.HasValueAny)
1042 return true;
1043 if (anyAttr.HasValueOther && (anyAttr.TargetNamespace == "" || reader.NamespaceURI != anyAttr.TargetNamespace))
1044 return true;
1045 if (anyAttr.HasValueTargetNamespace && reader.NamespaceURI == anyAttr.TargetNamespace)
1046 return true;
1047 if (anyAttr.HasValueLocal && reader.NamespaceURI == "")
1048 return true;
1049 for (int i = 0; i < anyAttr.ResolvedNamespaces.Count; i++)
1050 if (anyAttr.ResolvedNamespaces [i] == reader.NamespaceURI)
1051 return true;
1052 return false;
1055 private XmlSchemaObject FindAttributeDeclaration (
1056 XmlSchemaComplexType cType,
1057 XmlQualifiedName qname,
1058 string elementNs)
1060 XmlSchemaObject result = cType.AttributeUses [qname];
1061 if (result != null)
1062 return result;
1063 if (cType.AttributeWildcard == null)
1064 return null;
1066 if (!AttributeWildcardItemValid (cType.AttributeWildcard, qname))
1067 return null;
1069 if (cType.AttributeWildcard.ResolvedProcessContents == XmlSchemaContentProcessing.Skip)
1070 return cType.AttributeWildcard;
1071 XmlSchemaAttribute attr = schemas.GlobalAttributes [qname] as XmlSchemaAttribute;
1072 if (attr != null)
1073 return attr;
1074 if (cType.AttributeWildcard.ResolvedProcessContents == XmlSchemaContentProcessing.Lax)
1075 return cType.AttributeWildcard;
1076 else
1077 return null;
1080 // 3.2.4 Attribute Locally Valid and 3.4.4 - 5.wildIDs
1081 private void AssessAttributeLocallyValid (XmlSchemaAttribute attr, bool checkWildIDs)
1083 // 1.
1084 switch (reader.NamespaceURI) {
1085 case XmlNamespaceManager.XmlnsXml:
1086 case XmlNamespaceManager.XmlnsXmlns:
1087 case XmlSchema.InstanceNamespace:
1088 break;
1090 // 2. - 4.
1091 if (attr.AttributeType == null)
1092 HandleError ("Attribute type is missing for " + attr.QualifiedName);
1093 XmlSchemaDatatype dt = attr.AttributeType as XmlSchemaDatatype;
1094 if (dt == null)
1095 dt = ((XmlSchemaSimpleType) attr.AttributeType).Datatype;
1096 // It is a bit heavy process, so let's omit as long as possible ;-)
1097 if (dt != XmlSchemaSimpleType.AnySimpleType || attr.ValidatedFixedValue != null) {
1098 string normalized = dt.Normalize (reader.Value);
1099 object parsedValue = null;
1100 try {
1101 parsedValue = dt.ParseValue (normalized, reader.NameTable, this.ParserContext.NamespaceManager);
1102 } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
1103 HandleError ("Attribute value is invalid against its data type " + dt.TokenizedType, ex);
1105 if (attr.ValidatedFixedValue != null && attr.ValidatedFixedValue != normalized)
1106 HandleError ("The value of the attribute " + attr.QualifiedName + " does not match with its fixed value.");
1107 if (checkWildIDs)
1108 AssessEachAttributeIdentityConstraint (dt, normalized, parsedValue);
1112 private void AssessEachAttributeIdentityConstraint (XmlSchemaDatatype dt,
1113 string normalized, object parsedValue)
1115 // Get normalized value and (if required) parsedValue if missing.
1116 switch (dt.TokenizedType) {
1117 case XmlTokenizedType.IDREFS:
1118 if (normalized == null)
1119 normalized = dt.Normalize (reader.Value);
1120 if (parsedValue == null)
1121 parsedValue = dt.ParseValue (normalized, reader.NameTable, ParserContext.NamespaceManager);
1122 break;
1123 case XmlTokenizedType.ID:
1124 case XmlTokenizedType.IDREF:
1125 if (normalized == null)
1126 normalized = dt.Normalize (reader.Value);
1127 break;
1130 // Validate identity constraints.
1131 switch (dt.TokenizedType) {
1132 case XmlTokenizedType.ID:
1133 if (thisElementId != null)
1134 HandleError ("ID type attribute was already assigned in the containing element.");
1135 thisElementId = normalized;
1136 if (idList.Contains (normalized))
1137 HandleError ("Duplicate ID value was found.");
1138 else
1139 idList.Add (normalized, normalized);
1140 if (MissingIDReferences.Contains (normalized))
1141 MissingIDReferences.Remove (normalized);
1142 break;
1143 case XmlTokenizedType.IDREF:
1144 if (!idList.Contains (normalized))
1145 MissingIDReferences.Add (normalized);
1146 break;
1147 case XmlTokenizedType.IDREFS:
1148 string [] idrefs = (string []) parsedValue;
1149 for (int i = 0; i < idrefs.Length; i++) {
1150 string id = idrefs [i];
1151 if (!idList.Contains (id))
1152 MissingIDReferences.Add (id);
1154 break;
1158 private void AssessAttributeLocallyValidUse (XmlSchemaAttribute attr)
1160 // This is extra check than spec 3.5.4
1161 if (attr.ValidatedUse == XmlSchemaUse.Prohibited)
1162 HandleError ("Attribute " + attr.QualifiedName + " is prohibited in this context.");
1165 private void AssessEndElementSchemaValidity ()
1167 if (childParticleState == null)
1168 childParticleState = context.ParticleState;
1169 ValidateEndElementParticle (); // validate against childrens' state.
1171 if (shouldValidateCharacters) {
1172 ValidateEndCharacters ();
1173 shouldValidateCharacters = false;
1176 // 3.3.4 Assess ElementLocallyValidElement 5: value constraints.
1177 // 3.3.4 Assess ElementLocallyValidType 3.1.3. = StringValid(3.14.4)
1178 // => ValidateEndCharacters().
1180 // Reset Identity constraints.
1181 for (int i = 0; i < keyTables.Count; i++) {
1182 XsdKeyTable keyTable = this.keyTables [i] as XsdKeyTable;
1183 if (keyTable.StartDepth == reader.Depth) {
1184 EndIdentityValidation (keyTable);
1185 } else {
1186 for (int k = 0; k < keyTable.Entries.Count; k++) {
1187 XsdKeyEntry entry = keyTable.Entries [k] as XsdKeyEntry;
1188 // Remove finished (maybe key not found) entries.
1189 if (entry.StartDepth == reader.Depth) {
1190 if (entry.KeyFound)
1191 keyTable.FinishedEntries.Add (entry);
1192 else if (entry.KeySequence.SourceSchemaIdentity is XmlSchemaKey)
1193 HandleError ("Key sequence is missing.");
1194 keyTable.Entries.RemoveAt (k);
1195 k--;
1197 // Pop validated key depth to find two or more fields.
1198 else {
1199 for (int j = 0; j < entry.KeyFields.Count; j++) {
1200 XsdKeyEntryField kf = entry.KeyFields [j];
1201 if (!kf.FieldFound && kf.FieldFoundDepth == reader.Depth) {
1202 kf.FieldFoundDepth = 0;
1203 kf.FieldFoundPath = null;
1210 for (int i = 0; i < keyTables.Count; i++) {
1211 XsdKeyTable keyseq = this.keyTables [i] as XsdKeyTable;
1212 if (keyseq.StartDepth == reader.Depth) {
1213 keyTables.RemoveAt (i);
1214 i--;
1218 // Reset xsi:nil, if required.
1219 if (xsiNilDepth == reader.Depth)
1220 xsiNilDepth = -1;
1223 // 3.11.4 Identity Constraint Satisfied
1224 private void AssessStartIdentityConstraints ()
1226 if (tmpKeyrefPool != null)
1227 tmpKeyrefPool.Clear ();
1228 if (context.Element != null && context.Element.Constraints.Count > 0) {
1229 // (a) Create new key sequences, if required.
1230 for (int i = 0; i < context.Element.Constraints.Count; i++) {
1231 XmlSchemaIdentityConstraint ident = (XmlSchemaIdentityConstraint) context.Element.Constraints [i];
1232 XsdKeyTable seq = CreateNewKeyTable (ident);
1233 if (ident is XmlSchemaKeyref) {
1234 if (tmpKeyrefPool == null)
1235 tmpKeyrefPool = new ArrayList ();
1236 tmpKeyrefPool.Add (seq);
1241 // (b) Evaluate current key sequences.
1242 for (int i = 0; i < keyTables.Count; i++) {
1243 XsdKeyTable seq = (XsdKeyTable) keyTables [i];
1244 if (seq.SelectorMatches (this.elementQNameStack, reader) != null) {
1245 // creates and registers new entry.
1246 XsdKeyEntry entry = new XsdKeyEntry (seq, reader);
1247 seq.Entries.Add (entry);
1251 // (c) Evaluate field paths.
1252 for (int i = 0; i < keyTables.Count; i++) {
1253 XsdKeyTable seq = (XsdKeyTable) keyTables [i];
1254 // If possible, create new field entry candidates.
1255 for (int j = 0; j < seq.Entries.Count; j++) {
1256 XsdKeyEntry entry = seq.Entries [j] as XsdKeyEntry;
1257 try {
1258 entry.FieldMatches (this.elementQNameStack, this);
1259 } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
1260 HandleError ("Identity field value is invalid against its data type.", ex);
1266 private XsdKeyTable CreateNewKeyTable (XmlSchemaIdentityConstraint ident)
1268 XsdKeyTable seq = new XsdKeyTable (ident, this);
1269 seq.StartDepth = reader.Depth;
1270 XmlSchemaKeyref keyref = ident as XmlSchemaKeyref;
1271 this.keyTables.Add (seq);
1272 return seq;
1275 private void EndIdentityValidation (XsdKeyTable seq)
1277 ArrayList errors = new ArrayList ();
1278 for (int i = 0; i < seq.Entries.Count; i++) {
1279 XsdKeyEntry entry = (XsdKeyEntry) seq.Entries [i];
1280 if (entry.KeyFound)
1281 continue;
1282 if (seq.SourceSchemaIdentity is XmlSchemaKey)
1283 errors.Add ("line " + entry.SelectorLineNumber + "position " + entry.SelectorLinePosition);
1285 if (errors.Count > 0)
1286 HandleError ("Invalid identity constraints were found. Key was not found. "
1287 + String.Join (", ", errors.ToArray (typeof (string)) as string []));
1289 errors.Clear ();
1290 // Find reference target
1291 XmlSchemaKeyref xsdKeyref = seq.SourceSchemaIdentity as XmlSchemaKeyref;
1292 if (xsdKeyref != null) {
1293 for (int i = this.keyTables.Count - 1; i >= 0; i--) {
1294 XsdKeyTable target = this.keyTables [i] as XsdKeyTable;
1295 if (target.SourceSchemaIdentity == xsdKeyref.Target) {
1296 seq.ReferencedKey = target;
1297 for (int j = 0; j < seq.FinishedEntries.Count; j++) {
1298 XsdKeyEntry entry = (XsdKeyEntry) seq.FinishedEntries [j];
1299 for (int k = 0; k < target.FinishedEntries.Count; k++) {
1300 XsdKeyEntry targetEntry = (XsdKeyEntry) target.FinishedEntries [k];
1301 if (entry.CompareIdentity (targetEntry)) {
1302 entry.KeyRefFound = true;
1303 break;
1309 if (seq.ReferencedKey == null)
1310 HandleError ("Target key was not found.");
1311 for (int i = 0; i < seq.FinishedEntries.Count; i++) {
1312 XsdKeyEntry entry = (XsdKeyEntry) seq.FinishedEntries [i];
1313 if (!entry.KeyRefFound)
1314 errors.Add (" line " + entry.SelectorLineNumber + ", position " + entry.SelectorLinePosition);
1316 if (errors.Count > 0)
1317 HandleError ("Invalid identity constraints were found. Referenced key was not found: "
1318 + String.Join (" / ", errors.ToArray (typeof (string)) as string []));
1322 // Overrided Methods
1324 public override void Close ()
1326 reader.Close ();
1329 public override string GetAttribute (int i)
1331 switch (reader.NodeType) {
1332 case XmlNodeType.XmlDeclaration:
1333 case XmlNodeType.DocumentType:
1334 return reader.GetAttribute (i);
1337 if (reader.AttributeCount > i)
1338 reader.GetAttribute (i);
1339 int defIdx = i - nonDefaultAttributeCount;
1340 if (i < AttributeCount)
1341 return defaultAttributes [defIdx].DefaultValue;
1343 throw new ArgumentOutOfRangeException ("i", i, "Specified attribute index is out of range.");
1346 public override string GetAttribute (string name)
1348 switch (reader.NodeType) {
1349 case XmlNodeType.XmlDeclaration:
1350 case XmlNodeType.DocumentType:
1351 return reader.GetAttribute (name);
1354 string value = reader.GetAttribute (name);
1355 if (value != null)
1356 return value;
1358 XmlQualifiedName qname = SplitQName (name);
1359 return GetDefaultAttribute (qname.Name, qname.Namespace);
1362 private XmlQualifiedName SplitQName (string name)
1364 if (!XmlChar.IsName (name))
1365 throw new ArgumentException ("Invalid name was specified.", "name");
1367 Exception ex = null;
1368 XmlQualifiedName qname = XmlSchemaUtil.ToQName (reader, name, out ex);
1369 if (ex != null)
1370 return XmlQualifiedName.Empty;
1371 else
1372 return qname;
1375 public override string GetAttribute (string localName, string ns)
1377 switch (reader.NodeType) {
1378 case XmlNodeType.XmlDeclaration:
1379 case XmlNodeType.DocumentType:
1380 return reader.GetAttribute (localName, ns);
1383 string value = reader.GetAttribute (localName, ns);
1384 if (value != null)
1385 return value;
1387 return GetDefaultAttribute (localName, ns);
1390 private string GetDefaultAttribute (string localName, string ns)
1392 int idx = this.FindDefaultAttribute (localName, ns);
1393 if (idx < 0)
1394 return null;
1395 string value = defaultAttributes [idx].ValidatedDefaultValue;
1396 if (value == null)
1397 value = defaultAttributes [idx].ValidatedFixedValue;
1398 return value;
1401 private int FindDefaultAttribute (string localName, string ns)
1403 for (int i = 0; i < this.defaultAttributes.Length; i++) {
1404 XmlSchemaAttribute attr = defaultAttributes [i];
1405 if (attr.QualifiedName.Name == localName &&
1406 (ns == null || attr.QualifiedName.Namespace == ns))
1407 return i;
1409 return -1;
1412 bool IXmlLineInfo.HasLineInfo ()
1414 return readerLineInfo != null && readerLineInfo.HasLineInfo ();
1417 public override string LookupNamespace (string prefix)
1419 return reader.LookupNamespace (prefix);
1422 string IXmlNamespaceResolver.LookupNamespace (string prefix, bool atomizedNames)
1424 IXmlNamespaceResolver res = reader as IXmlNamespaceResolver;
1425 if (res != null)
1426 return res.LookupNamespace (prefix, atomizedNames);
1427 else
1428 return reader.LookupNamespace (prefix);
1431 public override void MoveToAttribute (int i)
1433 switch (reader.NodeType) {
1434 case XmlNodeType.XmlDeclaration:
1435 case XmlNodeType.DocumentType:
1436 reader.MoveToAttribute (i);
1437 return;
1440 currentQName = null;
1441 if (i < this.nonDefaultAttributeCount) {
1442 reader.MoveToAttribute (i);
1443 this.currentDefaultAttribute = -1;
1444 this.defaultAttributeConsumed = false;
1447 if (i < AttributeCount) {
1448 this.currentDefaultAttribute = i - nonDefaultAttributeCount;
1449 this.defaultAttributeConsumed = false;
1451 else
1452 throw new ArgumentOutOfRangeException ("i", i, "Attribute index is out of range.");
1455 public override bool MoveToAttribute (string name)
1457 switch (reader.NodeType) {
1458 case XmlNodeType.XmlDeclaration:
1459 case XmlNodeType.DocumentType:
1460 return reader.MoveToAttribute (name);
1463 currentQName = null;
1464 bool b = reader.MoveToAttribute (name);
1465 if (b) {
1466 this.currentDefaultAttribute = -1;
1467 this.defaultAttributeConsumed = false;
1468 return true;
1471 return MoveToDefaultAttribute (name, null);
1474 public override bool MoveToAttribute (string localName, string ns)
1476 switch (reader.NodeType) {
1477 case XmlNodeType.XmlDeclaration:
1478 case XmlNodeType.DocumentType:
1479 return reader.MoveToAttribute (localName, ns);
1482 currentQName = null;
1483 bool b = reader.MoveToAttribute (localName, ns);
1484 if (b) {
1485 this.currentDefaultAttribute = -1;
1486 this.defaultAttributeConsumed = false;
1487 return true;
1490 return MoveToDefaultAttribute (localName, ns);
1493 private bool MoveToDefaultAttribute (string localName, string ns)
1495 int idx = this.FindDefaultAttribute (localName, ns);
1496 if (idx < 0)
1497 return false;
1498 currentDefaultAttribute = idx;
1499 defaultAttributeConsumed = false;
1500 return true;
1503 public override bool MoveToElement ()
1505 currentDefaultAttribute = -1;
1506 defaultAttributeConsumed = false;
1507 currentQName = null;
1508 return reader.MoveToElement ();
1511 public override bool MoveToFirstAttribute ()
1513 switch (reader.NodeType) {
1514 case XmlNodeType.XmlDeclaration:
1515 case XmlNodeType.DocumentType:
1516 return reader.MoveToFirstAttribute ();
1519 currentQName = null;
1520 if (this.nonDefaultAttributeCount > 0) {
1521 bool b = reader.MoveToFirstAttribute ();
1522 if (b) {
1523 currentDefaultAttribute = -1;
1524 defaultAttributeConsumed = false;
1526 return b;
1529 if (this.defaultAttributes.Length > 0) {
1530 currentDefaultAttribute = 0;
1531 defaultAttributeConsumed = false;
1532 return true;
1534 else
1535 return false;
1538 public override bool MoveToNextAttribute ()
1540 switch (reader.NodeType) {
1541 case XmlNodeType.XmlDeclaration:
1542 case XmlNodeType.DocumentType:
1543 return reader.MoveToNextAttribute ();
1546 currentQName = null;
1547 if (currentDefaultAttribute >= 0) {
1548 if (defaultAttributes.Length == currentDefaultAttribute + 1)
1549 return false;
1550 currentDefaultAttribute++;
1551 defaultAttributeConsumed = false;
1552 return true;
1555 bool b = reader.MoveToNextAttribute ();
1556 if (b) {
1557 currentDefaultAttribute = -1;
1558 defaultAttributeConsumed = false;
1559 return true;
1562 if (defaultAttributes.Length > 0) {
1563 currentDefaultAttribute = 0;
1564 defaultAttributeConsumed = false;
1565 return true;
1567 else
1568 return false;
1571 private void ExamineAdditionalSchema ()
1573 XmlSchema schema = null;
1574 string schemaLocation = reader.GetAttribute ("schemaLocation", XmlSchema.InstanceNamespace);
1575 bool schemaAdded = false;
1576 if (schemaLocation != null) {
1577 string [] tmp = null;
1578 try {
1579 schemaLocation = XmlSchemaDatatype.FromName ("token", XmlSchema.Namespace).Normalize (schemaLocation);
1580 tmp = schemaLocation.Split (XmlChar.WhitespaceChars);
1581 } catch (Exception ex) {
1582 HandleError ("Invalid schemaLocation attribute format.", ex, true);
1583 tmp = new string [0];
1585 if (tmp.Length % 2 != 0)
1586 HandleError ("Invalid schemaLocation attribute format.");
1587 for (int i = 0; i < tmp.Length; i += 2) {
1588 Uri absUri = null;
1589 XmlTextReader xtr = null;
1590 try {
1591 absUri = new Uri ((this.BaseURI != "" ? new Uri (BaseURI) : null), tmp [i + 1]);
1592 xtr = new XmlTextReader (absUri.ToString (), NameTable);
1593 schema = XmlSchema.Read (xtr, null);
1594 } catch (Exception) { // FIXME: (wishlist) It is bad manner ;-(
1595 HandleError ("Could not resolve schema location URI: " + absUri, null, true);
1596 continue;
1597 } finally {
1598 if (xtr != null)
1599 xtr.Close ();
1601 if (schema.TargetNamespace == null)
1602 schema.TargetNamespace = tmp [i];
1603 else if (schema.TargetNamespace != tmp [i])
1604 HandleError ("Specified schema has different target namespace.");
1607 if (schema != null) {
1608 if (!schemas.Contains (schema.TargetNamespace)) {
1609 schemaAdded = true;
1610 schemas.Add (schema);
1613 schema = null;
1614 string noNsSchemaLocation = reader.GetAttribute ("noNamespaceSchemaLocation", XmlSchema.InstanceNamespace);
1615 if (noNsSchemaLocation != null) {
1616 Uri absUri = null;
1617 XmlTextReader xtr = null;
1618 try {
1619 absUri = new Uri ((this.BaseURI != "" ? new Uri (BaseURI) : null), noNsSchemaLocation);
1620 xtr = new XmlTextReader (absUri.ToString (), NameTable);
1621 schema = XmlSchema.Read (xtr, null);
1622 } catch (Exception) { // FIXME: (wishlist) It is bad manner ;-(
1623 HandleError ("Could not resolve schema location URI: " + absUri, null, true);
1624 } finally {
1625 if (xtr != null)
1626 xtr.Close ();
1628 if (schema != null && schema.TargetNamespace != null)
1629 HandleError ("Specified schema has different target namespace.");
1631 if (schema != null) {
1632 if (!schemas.Contains (schema.TargetNamespace)) {
1633 schemaAdded = true;
1634 schemas.Add (schema);
1637 // FIXME: should call Reprocess()?
1638 if (schemaAdded)
1639 schemas.Compile ();
1642 private bool HasMissingIDReferences ()
1644 return missingIDReferences != null
1645 && missingIDReferences.Count > 0;
1648 public override bool Read ()
1650 nonDefaultAttributeCount = 0;
1651 currentDefaultAttribute = -1;
1652 defaultAttributeConsumed = false;
1653 currentQName = null;
1654 thisElementId = null;
1655 defaultAttributes = new XmlSchemaAttribute [0];
1656 if (popContext) {
1657 elementQNameStack.RemoveAt (elementQNameStack.Count - 1);
1658 popContext = false;
1661 bool result = reader.Read ();
1662 // 3.3.4 ElementLocallyValidElement 7 = Root Valid.
1663 if (!result && HasMissingIDReferences ())
1664 HandleError ("There are missing ID references: " +
1665 String.Join (" ",
1666 this.missingIDReferences.ToArray (typeof (string)) as string []));
1668 switch (reader.NodeType) {
1669 case XmlNodeType.XmlDeclaration:
1670 this.nonDefaultAttributeCount = reader.AttributeCount;
1671 break;
1672 case XmlNodeType.Element:
1673 nonDefaultAttributeCount = reader.AttributeCount;
1675 // FIXME: schemaLocation could be specified
1676 // at any Depth.
1677 if (reader.Depth == 0)
1678 ExamineAdditionalSchema ();
1680 this.elementQNameStack.Add (new XmlQualifiedName (reader.LocalName, reader.NamespaceURI));
1682 // If there is no schema information, then no validation is performed.
1683 if (schemas.Count == 0)
1684 break;
1686 if (skipValidationDepth < 0 || reader.Depth <= skipValidationDepth) {
1687 if (shouldValidateCharacters) {
1688 ValidateEndCharacters ();
1689 shouldValidateCharacters = false;
1691 AssessStartElementSchemaValidity ();
1692 storedCharacters.Length = 0;
1693 } else {
1694 context.Clear ();
1697 if (reader.IsEmptyElement)
1698 goto case XmlNodeType.EndElement;
1699 else
1700 shouldValidateCharacters = true;
1701 break;
1702 case XmlNodeType.EndElement:
1703 if (reader.Depth == skipValidationDepth) {
1704 skipValidationDepth = -1;
1705 context.Clear ();
1707 else
1708 AssessEndElementSchemaValidity ();
1710 storedCharacters.Length = 0;
1711 childParticleState = null;
1712 popContext = true;
1713 break;
1715 case XmlNodeType.CDATA:
1716 case XmlNodeType.SignificantWhitespace:
1717 case XmlNodeType.Text:
1718 XmlSchemaComplexType ct = context.ActualType as XmlSchemaComplexType;
1719 if (ct != null && storedCharacters.Length > 0) {
1720 switch (ct.ContentType) {
1721 case XmlSchemaContentType.ElementOnly:
1722 case XmlSchemaContentType.Empty:
1723 HandleError ("Not allowed character content was found.");
1724 break;
1728 ValidateCharacters ();
1729 break;
1732 return result;
1735 public override bool ReadAttributeValue ()
1737 if (currentDefaultAttribute < 0)
1738 return reader.ReadAttributeValue ();
1740 if (this.defaultAttributeConsumed)
1741 return false;
1743 defaultAttributeConsumed = true;
1744 return true;
1747 #if NET_1_0
1748 public override string ReadInnerXml ()
1750 // MS.NET 1.0 has a serious bug here. It skips validation.
1751 return reader.ReadInnerXml ();
1754 public override string ReadOuterXml ()
1756 // MS.NET 1.0 has a serious bug here. It skips validation.
1757 return reader.ReadOuterXml ();
1759 #endif
1761 // XmlReader.ReadString() should call derived this.Read().
1762 public override string ReadString ()
1764 #if NET_1_0
1765 return reader.ReadString ();
1766 #else
1767 return base.ReadString ();
1768 #endif
1771 // This class itself does not have this feature.
1772 public override void ResolveEntity ()
1774 reader.ResolveEntity ();
1777 internal class XsdValidationContext
1779 Hashtable contextStack;
1781 public XsdValidationContext ()
1783 contextStack = new Hashtable ();
1786 // Some of them might be missing (See the spec section 5.3, and also 3.3.4).
1787 public XmlSchemaElement Element;
1788 public XsdValidationState ParticleState;
1789 public XmlSchemaAttribute [] DefaultAttributes;
1791 // Some of them might be missing (See the spec section 5.3).
1792 public object SchemaType;
1794 public object LocalTypeDefinition;
1796 public object ActualType {
1797 get {
1798 if (LocalTypeDefinition != null)
1799 return LocalTypeDefinition;
1800 else
1801 return SchemaType;
1805 public void Clear ()
1807 Element = null;
1808 SchemaType = null;
1809 ParticleState = null;
1810 LocalTypeDefinition = null;
1813 public void PushScope (int depth)
1815 contextStack [depth] = this.MemberwiseClone ();
1818 public void PopScope (int depth)
1820 Load (depth);
1821 contextStack.Remove (depth + 1);
1824 public void Load (int depth)
1826 Clear ();
1827 XsdValidationContext restored = (XsdValidationContext) contextStack [depth];
1828 if (restored != null) {
1829 this.Element = restored.Element;
1830 this.ParticleState = restored.ParticleState;
1831 this.SchemaType = restored.SchemaType;
1832 this.LocalTypeDefinition = restored.LocalTypeDefinition;