2 // XmlSchemaValidatingReader.cs
5 // Atsushi Enomoto <atsushi@ximian.com>
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;
35 using System.Xml.Schema;
36 using System.Xml.XPath;
43 using System.Collections.Generic;
44 using QName = System.Xml.XmlQualifiedName;
45 using Form = System.Xml.Schema.XmlSchemaForm;
46 using Use = System.Xml.Schema.XmlSchemaUse;
47 using ContentType = System.Xml.Schema.XmlSchemaContentType;
48 using Validity = System.Xml.Schema.XmlSchemaValidity;
49 using ValidationFlags = System.Xml.Schema.XmlSchemaValidationFlags;
50 using SOMList = System.Xml.Schema.XmlSchemaObjectCollection;
51 using SOMObject = System.Xml.Schema.XmlSchemaObject;
52 using XsElement = System.Xml.Schema.XmlSchemaElement;
53 using XsAttr = System.Xml.Schema.XmlSchemaAttribute;
54 using AttrGroup = System.Xml.Schema.XmlSchemaAttributeGroup;
55 using AttrGroupRef = System.Xml.Schema.XmlSchemaAttributeGroupRef;
56 using XsDatatype = System.Xml.Schema.XmlSchemaDatatype;
57 using SchemaType = System.Xml.Schema.XmlSchemaType;
58 using SimpleType = System.Xml.Schema.XmlSchemaSimpleType;
59 using ComplexType = System.Xml.Schema.XmlSchemaComplexType;
60 using SimpleModel = System.Xml.Schema.XmlSchemaSimpleContent;
61 using SimpleExt = System.Xml.Schema.XmlSchemaSimpleContentExtension;
62 using SimpleRst = System.Xml.Schema.XmlSchemaSimpleContentRestriction;
63 using ComplexModel = System.Xml.Schema.XmlSchemaComplexContent;
64 using ComplexExt = System.Xml.Schema.XmlSchemaComplexContentExtension;
65 using ComplexRst = System.Xml.Schema.XmlSchemaComplexContentRestriction;
66 using SimpleTypeRst = System.Xml.Schema.XmlSchemaSimpleTypeRestriction;
67 using SimpleList = System.Xml.Schema.XmlSchemaSimpleTypeList;
68 using SimpleUnion = System.Xml.Schema.XmlSchemaSimpleTypeUnion;
69 using SchemaFacet = System.Xml.Schema.XmlSchemaFacet;
70 using LengthFacet = System.Xml.Schema.XmlSchemaLengthFacet;
71 using MinLengthFacet = System.Xml.Schema.XmlSchemaMinLengthFacet;
72 using Particle = System.Xml.Schema.XmlSchemaParticle;
73 using Sequence = System.Xml.Schema.XmlSchemaSequence;
74 using Choice = System.Xml.Schema.XmlSchemaChoice;
75 using ValException = System.Xml.Schema.XmlSchemaValidationException;
77 namespace Mono.Xml.Schema
79 internal class XmlSchemaValidatingReader : XmlReader, IXmlLineInfo,
80 IXmlSchemaInfo, IXmlNamespaceResolver, IHasXmlParserContext
82 static readonly XsAttr [] emptyAttributeArray =
85 #region Instance Fields
88 ValidationFlags options;
90 XmlValueGetter getter;
92 IXmlLineInfo readerLineInfo;
93 ValidationType validationType;
94 IXmlNamespaceResolver nsResolver;
96 XsAttr [] defaultAttributes = emptyAttributeArray;
97 int currentDefaultAttribute = -1;
98 ArrayList defaultAttributesCache = new ArrayList ();
99 bool defaultAttributeConsumed;
100 XmlSchemaType currentAttrType;
103 // Extra for XmlSchemaValidtingReader
104 // (not in XsdValidatingReader)
105 XsElement element; // ... xsinfo.Element?
109 public XmlSchemaValidatingReader (XmlReader reader,
110 XmlReaderSettings settings)
112 IXmlNamespaceResolver nsResolver = reader as IXmlNamespaceResolver;
113 if (nsResolver == null)
114 // throw new ArgumentException ("Argument XmlReader must implement IXmlNamespaceResolver.");
115 nsResolver = new XmlNamespaceManager (reader.NameTable);
117 XmlSchemaSet schemas = settings.Schemas;
119 schemas = new XmlSchemaSet ();
120 options = settings.ValidationFlags;
122 this.reader = reader;
123 v = new XmlSchemaValidator (
128 if (reader.BaseURI != String.Empty)
129 v.SourceUri = new Uri (reader.BaseURI);
131 readerLineInfo = reader as IXmlLineInfo;
132 getter = delegate () {
133 if (v.CurrentAttributeType != null)
134 return v.CurrentAttributeType.ParseValue (Value, NameTable, this);
138 xsinfo = new XmlSchemaInfo (); // transition cache
139 v.LineInfoProvider = this;
140 v.ValidationEventSender = reader;
141 this.nsResolver = nsResolver;
143 ValidationEventHandler += delegate (object o, ValidationEventArgs e) {
144 settings.OnValidationError (o, e);
146 if (settings != null && settings.Schemas != null)
147 v.XmlResolver = settings.Schemas.XmlResolver;
149 v.XmlResolver = new XmlUrlResolver ();
151 v.XmlResolver = new XmlUrlResolver ();
156 public event ValidationEventHandler ValidationEventHandler {
157 add { v.ValidationEventHandler += value; }
158 remove { v.ValidationEventHandler -= value; }
161 public XmlSchemaType ElementSchemaType {
163 return element != null ? element.ElementSchemaType : null;
167 // clear default attributes, MoveTo*Attribute() transitent
169 private void ResetStateOnRead ()
171 currentDefaultAttribute = -1;
172 defaultAttributeConsumed = false;
173 currentAttrType = null;
174 defaultAttributes = emptyAttributeArray;
175 v.CurrentAttributeType = null;
180 public int LineNumber {
181 get { return readerLineInfo != null ? readerLineInfo.LineNumber : 0; }
184 public int LinePosition {
185 get { return readerLineInfo != null ? readerLineInfo.LinePosition : 0; }
188 public XmlSchemaType SchemaType {
190 if (ReadState != ReadState.Interactive)
194 case XmlNodeType.Element:
195 if (ElementSchemaType != null)
196 return ElementSchemaType;
198 return null;//SourceReaderSchemaType;
199 case XmlNodeType.Attribute:
200 if (currentAttrType == null) {
201 ComplexType ct = ElementSchemaType as ComplexType;
203 XsAttr attdef = ct.AttributeUses [new XmlQualifiedName (LocalName, NamespaceURI)] as XsAttr;
205 currentAttrType = attdef.AttributeSchemaType;
206 return currentAttrType;
208 // currentAttrType = SourceReaderSchemaType;
210 return currentAttrType;
212 return null;//SourceReaderSchemaType;
217 public ValidationType ValidationType {
218 get { return validationType; }
220 if (ReadState != ReadState.Initial)
221 throw new InvalidOperationException ("ValidationType must be set before reading.");
222 validationType = value;
226 public IDictionary<string, string> GetNamespacesInScope (XmlNamespaceScope scope)
228 IXmlNamespaceResolver resolver = reader as IXmlNamespaceResolver;
229 if (resolver == null)
230 throw new NotSupportedException ("The input XmlReader does not implement IXmlNamespaceResolver and thus this validating reader cannot collect in-scope namespaces.");
231 return resolver.GetNamespacesInScope (scope);
234 public string LookupPrefix (string ns)
236 return nsResolver.LookupPrefix (ns);
239 // Public Overriden Properties
241 public override int AttributeCount {
243 return reader.AttributeCount + defaultAttributes.Length;
247 public override string BaseURI {
248 get { return reader.BaseURI; }
251 // If this class is used to implement XmlValidatingReader,
252 // it should be left to DTDValidatingReader. In other cases,
253 // it depends on the reader's ability.
254 public override bool CanResolveEntity {
255 get { return reader.CanResolveEntity; }
258 public override int Depth {
260 if (currentDefaultAttribute < 0)
262 if (this.defaultAttributeConsumed)
263 return reader.Depth + 2;
264 return reader.Depth + 1;
268 public override bool EOF {
269 get { return reader.EOF; }
272 public override bool HasValue {
274 if (currentDefaultAttribute < 0)
275 return reader.HasValue;
280 public override bool IsDefault {
282 if (currentDefaultAttribute < 0)
283 return reader.IsDefault;
288 public override bool IsEmptyElement {
290 if (currentDefaultAttribute < 0)
291 return reader.IsEmptyElement;
296 public override string this [int i] {
297 get { return GetAttribute (i); }
300 public override string this [string name] {
301 get { return GetAttribute (name); }
304 public override string this [string localName, string ns] {
305 get { return GetAttribute (localName, ns); }
308 int IXmlLineInfo.LineNumber {
309 get { return readerLineInfo != null ? readerLineInfo.LineNumber : 0; }
312 int IXmlLineInfo.LinePosition {
313 get { return readerLineInfo != null ? readerLineInfo.LinePosition : 0; }
316 public override string LocalName {
318 if (currentDefaultAttribute < 0)
319 return reader.LocalName;
320 if (defaultAttributeConsumed)
322 return defaultAttributes [currentDefaultAttribute].QualifiedName.Name;
326 public override string Name {
328 if (currentDefaultAttribute < 0)
330 if (defaultAttributeConsumed)
333 XmlQualifiedName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
334 string prefix = Prefix;
335 if (prefix == String.Empty)
338 return String.Concat (prefix, ":", qname.Name);
342 public override string NamespaceURI {
344 if (currentDefaultAttribute < 0)
345 return reader.NamespaceURI;
346 if (defaultAttributeConsumed)
348 return defaultAttributes [currentDefaultAttribute].QualifiedName.Namespace;
352 public override XmlNameTable NameTable {
353 get { return reader.NameTable; }
356 public override XmlNodeType NodeType {
358 if (currentDefaultAttribute < 0)
359 return reader.NodeType;
360 if (defaultAttributeConsumed)
361 return XmlNodeType.Text;
362 return XmlNodeType.Attribute;
366 public XmlParserContext ParserContext {
367 get { return XmlSchemaUtil.GetParserContext (reader); }
370 public override string Prefix {
372 if (currentDefaultAttribute < 0)
373 return reader.Prefix;
374 if (defaultAttributeConsumed)
376 XmlQualifiedName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
377 string prefix = nsResolver.LookupPrefix (qname.Namespace);
385 public override char QuoteChar {
386 get { return reader.QuoteChar; }
389 public override ReadState ReadState {
390 get { return reader.ReadState; }
393 public override IXmlSchemaInfo SchemaInfo {
395 return new XmlSchemaInfo () {
396 //ContentType = this.ContentType,
397 IsDefault = this.IsDefault,
399 MemberType = this.MemberType,
400 SchemaAttribute = this.SchemaAttribute,
401 SchemaElement = this.SchemaElement,
402 SchemaType = this.SchemaType,
403 Validity = this.Validity
408 public override string Value {
410 if (currentDefaultAttribute < 0)
412 string value = defaultAttributes [currentDefaultAttribute].ValidatedDefaultValue;
414 value = defaultAttributes [currentDefaultAttribute].ValidatedFixedValue;
419 public override string XmlLang {
421 string xmlLang = reader.XmlLang;
424 int idx = this.FindDefaultAttribute ("lang", XmlNamespaceManager.XmlnsXml);
427 xmlLang = defaultAttributes [idx].ValidatedDefaultValue;
429 xmlLang = defaultAttributes [idx].ValidatedFixedValue;
434 public override XmlSpace XmlSpace {
436 XmlSpace space = reader.XmlSpace;
437 if (space != XmlSpace.None)
439 int idx = this.FindDefaultAttribute ("space", XmlNamespaceManager.XmlnsXml);
441 return XmlSpace.None;
442 string spaceSpec = defaultAttributes [idx].ValidatedDefaultValue;
443 if (spaceSpec == null)
444 spaceSpec = defaultAttributes [idx].ValidatedFixedValue;
445 return (XmlSpace) Enum.Parse (typeof (XmlSpace), spaceSpec, false);
450 #region Public Methods
454 public override void Close ()
459 public override string GetAttribute (int i)
461 switch (reader.NodeType) {
462 case XmlNodeType.XmlDeclaration:
463 case XmlNodeType.DocumentType:
464 return reader.GetAttribute (i);
467 if (reader.AttributeCount > i)
468 reader.GetAttribute (i);
469 int defIdx = i - reader.AttributeCount;
470 if (i < AttributeCount)
471 return defaultAttributes [defIdx].DefaultValue;
473 throw new ArgumentOutOfRangeException ("i", i, "Specified attribute index is out of range.");
476 public override string GetAttribute (string name)
478 switch (reader.NodeType) {
479 case XmlNodeType.XmlDeclaration:
480 case XmlNodeType.DocumentType:
481 return reader.GetAttribute (name);
484 string value = reader.GetAttribute (name);
488 XmlQualifiedName qname = SplitQName (name);
489 return GetDefaultAttribute (qname.Name, qname.Namespace);
492 private XmlQualifiedName SplitQName (string name)
494 XmlConvert.VerifyName (name);
497 XmlQualifiedName qname = XmlSchemaUtil.ToQName (reader, name, out ex);
499 return XmlQualifiedName.Empty;
504 public override string GetAttribute (string localName, string ns)
506 switch (reader.NodeType) {
507 case XmlNodeType.XmlDeclaration:
508 case XmlNodeType.DocumentType:
509 return reader.GetAttribute (localName, ns);
512 string value = reader.GetAttribute (localName, ns);
516 return GetDefaultAttribute (localName, ns);
519 private string GetDefaultAttribute (string localName, string ns)
521 int idx = this.FindDefaultAttribute (localName, ns);
524 string value = defaultAttributes [idx].ValidatedDefaultValue;
526 value = defaultAttributes [idx].ValidatedFixedValue;
530 private int FindDefaultAttribute (string localName, string ns)
532 for (int i = 0; i < this.defaultAttributes.Length; i++) {
533 XsAttr attr = defaultAttributes [i];
534 if (attr.QualifiedName.Name == localName &&
535 (ns == null || attr.QualifiedName.Namespace == ns))
541 bool IXmlLineInfo.HasLineInfo ()
543 return readerLineInfo != null && readerLineInfo.HasLineInfo ();
546 public override string LookupNamespace (string prefix)
548 return reader.LookupNamespace (prefix);
551 public override void MoveToAttribute (int i)
553 switch (reader.NodeType) {
554 case XmlNodeType.XmlDeclaration:
555 case XmlNodeType.DocumentType:
556 reader.MoveToAttribute (i);
560 currentAttrType = null;
561 if (i < reader.AttributeCount) {
562 reader.MoveToAttribute (i);
563 this.currentDefaultAttribute = -1;
564 this.defaultAttributeConsumed = false;
567 if (i < AttributeCount) {
568 this.currentDefaultAttribute = i - reader.AttributeCount;
569 this.defaultAttributeConsumed = false;
572 throw new ArgumentOutOfRangeException ("i", i, "Attribute index is out of range.");
575 public override bool MoveToAttribute (string name)
577 switch (reader.NodeType) {
578 case XmlNodeType.XmlDeclaration:
579 case XmlNodeType.DocumentType:
580 return reader.MoveToAttribute (name);
583 currentAttrType = null;
584 bool b = reader.MoveToAttribute (name);
586 this.currentDefaultAttribute = -1;
587 this.defaultAttributeConsumed = false;
591 return MoveToDefaultAttribute (name, null);
594 public override bool MoveToAttribute (string localName, string ns)
596 switch (reader.NodeType) {
597 case XmlNodeType.XmlDeclaration:
598 case XmlNodeType.DocumentType:
599 return reader.MoveToAttribute (localName, ns);
602 currentAttrType = null;
603 bool b = reader.MoveToAttribute (localName, ns);
605 this.currentDefaultAttribute = -1;
606 this.defaultAttributeConsumed = false;
610 return MoveToDefaultAttribute (localName, ns);
613 private bool MoveToDefaultAttribute (string localName, string ns)
615 int idx = this.FindDefaultAttribute (localName, ns);
618 currentDefaultAttribute = idx;
619 defaultAttributeConsumed = false;
623 public override bool MoveToElement ()
625 currentDefaultAttribute = -1;
626 defaultAttributeConsumed = false;
627 currentAttrType = null;
628 return reader.MoveToElement ();
631 public override bool MoveToFirstAttribute ()
633 switch (reader.NodeType) {
634 case XmlNodeType.XmlDeclaration:
635 case XmlNodeType.DocumentType:
636 return reader.MoveToFirstAttribute ();
639 currentAttrType = null;
640 if (reader.AttributeCount > 0) {
641 bool b = reader.MoveToFirstAttribute ();
643 currentDefaultAttribute = -1;
644 defaultAttributeConsumed = false;
649 if (this.defaultAttributes.Length > 0) {
650 currentDefaultAttribute = 0;
651 defaultAttributeConsumed = false;
658 public override bool MoveToNextAttribute ()
660 switch (reader.NodeType) {
661 case XmlNodeType.XmlDeclaration:
662 case XmlNodeType.DocumentType:
663 return reader.MoveToNextAttribute ();
666 currentAttrType = null;
667 if (currentDefaultAttribute >= 0) {
668 if (defaultAttributes.Length == currentDefaultAttribute + 1)
670 currentDefaultAttribute++;
671 defaultAttributeConsumed = false;
675 bool b = reader.MoveToNextAttribute ();
677 currentDefaultAttribute = -1;
678 defaultAttributeConsumed = false;
682 if (defaultAttributes.Length > 0) {
683 currentDefaultAttribute = 0;
684 defaultAttributeConsumed = false;
691 public override bool Read ()
693 if (!reader.Read ()) {
694 if (!validationDone) {
696 validationDone = true;
703 switch (reader.NodeType) {
704 case XmlNodeType.Element:
705 string sl = reader.GetAttribute (
707 XmlSchema.InstanceNamespace);
708 string noNsSL = reader.GetAttribute (
709 "noNamespaceSchemaLocation",
710 XmlSchema.InstanceNamespace);
711 string xsiType = reader.GetAttribute ("type",
712 XmlSchema.InstanceNamespace);
713 string xsiNil = reader.GetAttribute ("nil",
714 XmlSchema.InstanceNamespace);
716 v.ValidateElement (reader.LocalName,
724 if (reader.MoveToFirstAttribute ()) {
726 switch (reader.NamespaceURI) {
727 case XmlSchema.InstanceNamespace:
728 switch (reader.LocalName) {
729 case "schemaLocation":
730 case "noNamespaceSchemaLocation":
736 case XmlNamespaceManager.XmlnsXmlns:
739 v.ValidateAttribute (
744 } while (reader.MoveToNextAttribute ());
745 reader.MoveToElement ();
747 v.GetUnspecifiedDefaultAttributes (
748 defaultAttributesCache);
749 defaultAttributes = (XsAttr [])
750 defaultAttributesCache.ToArray (
752 v.ValidateEndOfAttributes (xsinfo);
753 defaultAttributesCache.Clear ();
755 if (reader.IsEmptyElement)
756 goto case XmlNodeType.EndElement;
758 case XmlNodeType.EndElement:
759 // FIXME: find out what another overload means.
760 v.ValidateEndElement (xsinfo);
762 case XmlNodeType.Text:
763 v.ValidateText (getter);
765 case XmlNodeType.SignificantWhitespace:
766 case XmlNodeType.Whitespace:
767 v.ValidateWhitespace (getter);
774 public override bool ReadAttributeValue ()
776 if (currentDefaultAttribute < 0)
777 return reader.ReadAttributeValue ();
779 if (this.defaultAttributeConsumed)
782 defaultAttributeConsumed = true;
787 public override string ReadInnerXml ()
789 // MS.NET 1.0 has a serious bug here. It skips validation.
790 return ReadInnerXmlInternal ();
793 public override string ReadOuterXml ()
795 // MS.NET 1.0 has a serious bug here. It skips validation.
796 return ReadInnerXmlInternal ();
799 // XmlReader.ReadString() should call derived this.Read().
800 public override string ReadString ()
802 return ReadStringInternal ();
806 // This class itself does not have this feature.
807 public override void ResolveEntity ()
809 reader.ResolveEntity ();
814 #region IXmlSchemaInfo
817 get { return xsinfo.IsNil; }
820 public XmlSchemaSimpleType MemberType {
821 get { return xsinfo.MemberType; }
824 public XmlSchemaAttribute SchemaAttribute {
825 get { return xsinfo.SchemaAttribute; }
828 public XmlSchemaElement SchemaElement {
829 get { return xsinfo.SchemaElement; }
832 public XmlSchemaValidity Validity {
833 get { return xsinfo.Validity; }