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,
82 static readonly XsAttr [] emptyAttributeArray =
85 #region Instance Fields
88 ValidationFlags options;
90 XmlValueGetter getter;
92 IXmlLineInfo readerLineInfo;
93 ValidationType validationType;
94 IXmlNamespaceResolver nsResolver;
97 StringBuilder tmpBuilder = new StringBuilder ();
99 XsAttr [] defaultAttributes = emptyAttributeArray;
100 int currentDefaultAttribute = -1;
101 ArrayList defaultAttributesCache = new ArrayList ();
102 bool defaultAttributeConsumed;
103 XmlSchemaType currentAttrType;
105 // Extra for XmlSchemaValidtingReader
106 // (not in XsdValidatingReader)
107 XsElement element; // ... xsinfo.Element?
111 public XmlSchemaValidatingReader (XmlReader reader,
112 XmlReaderSettings settings)
114 IXmlNamespaceResolver nsResolver = reader as IXmlNamespaceResolver;
115 if (nsResolver == null)
116 throw new ArgumentException ("Argument XmlReader must implement IXmlNamespaceResolver.");
118 XmlSchemaSet schemas = settings.Schemas;
120 schemas = new XmlSchemaSet ();
121 options = settings.ValidationFlags;
123 this.reader = reader;
124 v = new XmlSchemaValidator (
130 readerLineInfo = reader as IXmlLineInfo;
131 startDepth = reader.Depth;
132 getter = delegate () { return Value; };
133 xsinfo = new XmlSchemaInfo (); // transition cache
134 v.LineInfoProvider = this;
135 v.ValidationEventSender = reader;
137 if (settings != null && settings.Schemas != null)
138 v.XmlResolver = settings.Schemas.XmlResolver;
140 v.XmlResolver = new XmlUrlResolver ();
142 v.XmlResolver = new XmlUrlResolver ();
147 public ValidationEventHandler ValidationEventHandler;
149 public XmlSchemaType ElementSchemaType {
151 return element != null ? element.ElementSchemaType : null;
155 // clear default attributes, MoveTo*Attribute() transitent
157 private void ResetStateOnRead ()
159 currentDefaultAttribute = -1;
160 defaultAttributeConsumed = false;
161 currentAttrType = null;
162 defaultAttributes = emptyAttributeArray;
167 public int LineNumber {
168 get { return readerLineInfo != null ? readerLineInfo.LineNumber : 0; }
171 public int LinePosition {
172 get { return readerLineInfo != null ? readerLineInfo.LinePosition : 0; }
175 public XmlSchemaType SchemaType {
177 if (ReadState != ReadState.Interactive)
181 case XmlNodeType.Element:
182 if (ElementSchemaType != null)
183 return ElementSchemaType;
185 return null;//SourceReaderSchemaType;
186 case XmlNodeType.Attribute:
187 if (currentAttrType == null) {
188 ComplexType ct = ElementSchemaType as ComplexType;
190 XsAttr attdef = ct.AttributeUses [new XmlQualifiedName (LocalName, NamespaceURI)] as XsAttr;
192 currentAttrType = attdef.AttributeSchemaType;
193 return currentAttrType;
195 // currentAttrType = SourceReaderSchemaType;
197 return currentAttrType;
199 return null;//SourceReaderSchemaType;
204 public ValidationType ValidationType {
205 get { return validationType; }
207 if (ReadState != ReadState.Initial)
208 throw new InvalidOperationException ("ValidationType must be set before reading.");
209 validationType = value;
213 public IDictionary<string, string> GetNamespacesInScope (XmlNamespaceScope scope)
215 IXmlNamespaceResolver resolver = reader as IXmlNamespaceResolver;
216 if (resolver == null)
217 throw new NotSupportedException ("The input XmlReader does not implement IXmlNamespaceResolver and thus this validating reader cannot collect in-scope namespaces.");
218 return resolver.GetNamespacesInScope (scope);
221 public string LookupPrefix (string ns)
223 return nsResolver.LookupPrefix (ns);
226 // Public Overriden Properties
228 public override int AttributeCount {
230 return reader.AttributeCount + defaultAttributes.Length;
234 public override string BaseURI {
235 get { return reader.BaseURI; }
238 // If this class is used to implement XmlValidatingReader,
239 // it should be left to DTDValidatingReader. In other cases,
240 // it depends on the reader's ability.
241 public override bool CanResolveEntity {
242 get { return reader.CanResolveEntity; }
245 public override int Depth {
247 if (currentDefaultAttribute < 0)
249 if (this.defaultAttributeConsumed)
250 return reader.Depth + 2;
251 return reader.Depth + 1;
255 public override bool EOF {
256 get { return reader.EOF; }
259 public override bool HasValue {
261 if (currentDefaultAttribute < 0)
262 return reader.HasValue;
267 public override bool IsDefault {
269 if (currentDefaultAttribute < 0)
270 return reader.IsDefault;
275 public override bool IsEmptyElement {
277 if (currentDefaultAttribute < 0)
278 return reader.IsEmptyElement;
283 public override string this [int i] {
284 get { return GetAttribute (i); }
287 public override string this [string name] {
288 get { return GetAttribute (name); }
291 public override string this [string localName, string ns] {
292 get { return GetAttribute (localName, ns); }
295 int IXmlLineInfo.LineNumber {
296 get { return readerLineInfo != null ? readerLineInfo.LineNumber : 0; }
299 int IXmlLineInfo.LinePosition {
300 get { return readerLineInfo != null ? readerLineInfo.LinePosition : 0; }
303 public override string LocalName {
305 if (currentDefaultAttribute < 0)
306 return reader.LocalName;
307 if (defaultAttributeConsumed)
309 return defaultAttributes [currentDefaultAttribute].QualifiedName.Name;
313 public override string Name {
315 if (currentDefaultAttribute < 0)
317 if (defaultAttributeConsumed)
320 XmlQualifiedName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
321 string prefix = Prefix;
322 if (prefix == String.Empty)
325 return String.Concat (prefix, ":", qname.Name);
329 public override string NamespaceURI {
331 if (currentDefaultAttribute < 0)
332 return reader.NamespaceURI;
333 if (defaultAttributeConsumed)
335 return defaultAttributes [currentDefaultAttribute].QualifiedName.Namespace;
339 public override XmlNameTable NameTable {
340 get { return reader.NameTable; }
343 public override XmlNodeType NodeType {
345 if (currentDefaultAttribute < 0)
346 return reader.NodeType;
347 if (defaultAttributeConsumed)
348 return XmlNodeType.Text;
349 return XmlNodeType.Attribute;
354 public XmlParserContext ParserContext {
355 get { return XmlSchemaUtil.GetParserContext (reader); }
359 public override string Prefix {
361 if (currentDefaultAttribute < 0)
362 return reader.Prefix;
363 if (defaultAttributeConsumed)
365 XmlQualifiedName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
366 string prefix = nsResolver.LookupPrefix (qname.Namespace);
374 public override char QuoteChar {
375 get { return reader.QuoteChar; }
378 public override ReadState ReadState {
379 get { return reader.ReadState; }
382 public override IXmlSchemaInfo SchemaInfo {
386 public override string Value {
388 if (currentDefaultAttribute < 0)
390 string value = defaultAttributes [currentDefaultAttribute].ValidatedDefaultValue;
392 value = defaultAttributes [currentDefaultAttribute].ValidatedFixedValue;
397 public override string XmlLang {
399 string xmlLang = reader.XmlLang;
402 int idx = this.FindDefaultAttribute ("lang", XmlNamespaceManager.XmlnsXml);
405 xmlLang = defaultAttributes [idx].ValidatedDefaultValue;
407 xmlLang = defaultAttributes [idx].ValidatedFixedValue;
412 public override XmlSpace XmlSpace {
414 XmlSpace space = reader.XmlSpace;
415 if (space != XmlSpace.None)
417 int idx = this.FindDefaultAttribute ("space", XmlNamespaceManager.XmlnsXml);
419 return XmlSpace.None;
420 string spaceSpec = defaultAttributes [idx].ValidatedDefaultValue;
421 if (spaceSpec == null)
422 spaceSpec = defaultAttributes [idx].ValidatedFixedValue;
423 return (XmlSpace) Enum.Parse (typeof (XmlSpace), spaceSpec, false);
428 #region Public Methods
432 public override void Close ()
437 public override string GetAttribute (int i)
439 switch (reader.NodeType) {
440 case XmlNodeType.XmlDeclaration:
441 case XmlNodeType.DocumentType:
442 return reader.GetAttribute (i);
445 if (reader.AttributeCount > i)
446 reader.GetAttribute (i);
447 int defIdx = i - reader.AttributeCount;
448 if (i < AttributeCount)
449 return defaultAttributes [defIdx].DefaultValue;
451 throw new ArgumentOutOfRangeException ("i", i, "Specified attribute index is out of range.");
454 public override string GetAttribute (string name)
456 switch (reader.NodeType) {
457 case XmlNodeType.XmlDeclaration:
458 case XmlNodeType.DocumentType:
459 return reader.GetAttribute (name);
462 string value = reader.GetAttribute (name);
466 XmlQualifiedName qname = SplitQName (name);
467 return GetDefaultAttribute (qname.Name, qname.Namespace);
470 private XmlQualifiedName SplitQName (string name)
472 XmlConvert.VerifyName (name);
475 XmlQualifiedName qname = XmlSchemaUtil.ToQName (reader, name, out ex);
477 return XmlQualifiedName.Empty;
482 public override string GetAttribute (string localName, string ns)
484 switch (reader.NodeType) {
485 case XmlNodeType.XmlDeclaration:
486 case XmlNodeType.DocumentType:
487 return reader.GetAttribute (localName, ns);
490 string value = reader.GetAttribute (localName, ns);
494 return GetDefaultAttribute (localName, ns);
497 private string GetDefaultAttribute (string localName, string ns)
499 int idx = this.FindDefaultAttribute (localName, ns);
502 string value = defaultAttributes [idx].ValidatedDefaultValue;
504 value = defaultAttributes [idx].ValidatedFixedValue;
508 private int FindDefaultAttribute (string localName, string ns)
510 for (int i = 0; i < this.defaultAttributes.Length; i++) {
511 XsAttr attr = defaultAttributes [i];
512 if (attr.QualifiedName.Name == localName &&
513 (ns == null || attr.QualifiedName.Namespace == ns))
519 bool IXmlLineInfo.HasLineInfo ()
521 return readerLineInfo != null && readerLineInfo.HasLineInfo ();
524 public override string LookupNamespace (string prefix)
526 return reader.LookupNamespace (prefix);
529 public override void MoveToAttribute (int i)
531 switch (reader.NodeType) {
532 case XmlNodeType.XmlDeclaration:
533 case XmlNodeType.DocumentType:
534 reader.MoveToAttribute (i);
538 currentAttrType = null;
539 if (i < reader.AttributeCount) {
540 reader.MoveToAttribute (i);
541 this.currentDefaultAttribute = -1;
542 this.defaultAttributeConsumed = false;
545 if (i < AttributeCount) {
546 this.currentDefaultAttribute = i - reader.AttributeCount;
547 this.defaultAttributeConsumed = false;
550 throw new ArgumentOutOfRangeException ("i", i, "Attribute index is out of range.");
553 public override bool MoveToAttribute (string name)
555 switch (reader.NodeType) {
556 case XmlNodeType.XmlDeclaration:
557 case XmlNodeType.DocumentType:
558 return reader.MoveToAttribute (name);
561 currentAttrType = null;
562 bool b = reader.MoveToAttribute (name);
564 this.currentDefaultAttribute = -1;
565 this.defaultAttributeConsumed = false;
569 return MoveToDefaultAttribute (name, null);
572 public override bool MoveToAttribute (string localName, string ns)
574 switch (reader.NodeType) {
575 case XmlNodeType.XmlDeclaration:
576 case XmlNodeType.DocumentType:
577 return reader.MoveToAttribute (localName, ns);
580 currentAttrType = null;
581 bool b = reader.MoveToAttribute (localName, ns);
583 this.currentDefaultAttribute = -1;
584 this.defaultAttributeConsumed = false;
588 return MoveToDefaultAttribute (localName, ns);
591 private bool MoveToDefaultAttribute (string localName, string ns)
593 int idx = this.FindDefaultAttribute (localName, ns);
596 currentDefaultAttribute = idx;
597 defaultAttributeConsumed = false;
601 public override bool MoveToElement ()
603 currentDefaultAttribute = -1;
604 defaultAttributeConsumed = false;
605 currentAttrType = null;
606 return reader.MoveToElement ();
609 public override bool MoveToFirstAttribute ()
611 switch (reader.NodeType) {
612 case XmlNodeType.XmlDeclaration:
613 case XmlNodeType.DocumentType:
614 return reader.MoveToFirstAttribute ();
617 currentAttrType = null;
618 if (reader.AttributeCount > 0) {
619 bool b = reader.MoveToFirstAttribute ();
621 currentDefaultAttribute = -1;
622 defaultAttributeConsumed = false;
627 if (this.defaultAttributes.Length > 0) {
628 currentDefaultAttribute = 0;
629 defaultAttributeConsumed = false;
636 public override bool MoveToNextAttribute ()
638 switch (reader.NodeType) {
639 case XmlNodeType.XmlDeclaration:
640 case XmlNodeType.DocumentType:
641 return reader.MoveToNextAttribute ();
644 currentAttrType = null;
645 if (currentDefaultAttribute >= 0) {
646 if (defaultAttributes.Length == currentDefaultAttribute + 1)
648 currentDefaultAttribute++;
649 defaultAttributeConsumed = false;
653 bool b = reader.MoveToNextAttribute ();
655 currentDefaultAttribute = -1;
656 defaultAttributeConsumed = false;
660 if (defaultAttributes.Length > 0) {
661 currentDefaultAttribute = 0;
662 defaultAttributeConsumed = false;
669 public override bool Read ()
671 if (!reader.Read ()) {
678 switch (reader.NodeType) {
679 case XmlNodeType.Element:
680 string sl = reader.GetAttribute (
682 XmlSchema.InstanceNamespace);
683 string noNsSL = reader.GetAttribute (
684 "noNamespaceSchemaLocation",
685 XmlSchema.InstanceNamespace);
686 string xsiType = reader.GetAttribute ("type",
687 XmlSchema.InstanceNamespace);
688 string xsiNil = reader.GetAttribute ("nil",
689 XmlSchema.InstanceNamespace);
691 v.ValidateElement (reader.LocalName,
699 if (reader.MoveToFirstAttribute ()) {
701 switch (reader.NamespaceURI) {
702 case XmlSchema.InstanceNamespace:
703 switch (reader.LocalName) {
704 case "schemaLocation":
705 case "noNamespaceSchemaLocation":
711 case XmlNamespaceManager.XmlnsXmlns:
714 v.ValidateAttribute (
719 } while (reader.MoveToNextAttribute ());
720 reader.MoveToElement ();
722 v.GetUnspecifiedDefaultAttributes (
723 defaultAttributesCache);
724 defaultAttributes = (XsAttr [])
725 defaultAttributesCache.ToArray (
727 v.ValidateEndOfAttributes (xsinfo);
728 defaultAttributesCache.Clear ();
730 if (reader.IsEmptyElement)
731 goto case XmlNodeType.EndElement;
733 case XmlNodeType.EndElement:
734 // FIXME: find out what another overload means.
735 v.ValidateEndElement (xsinfo);
737 case XmlNodeType.Text:
738 v.ValidateText (getter);
740 case XmlNodeType.SignificantWhitespace:
741 case XmlNodeType.Whitespace:
742 v.ValidateWhitespace (getter);
749 public override bool ReadAttributeValue ()
751 if (currentDefaultAttribute < 0)
752 return reader.ReadAttributeValue ();
754 if (this.defaultAttributeConsumed)
757 defaultAttributeConsumed = true;
762 public override string ReadInnerXml ()
764 // MS.NET 1.0 has a serious bug here. It skips validation.
765 return ReadInnerXmlInternal ();
768 public override string ReadOuterXml ()
770 // MS.NET 1.0 has a serious bug here. It skips validation.
771 return ReadInnerXmlInternal ();
774 // XmlReader.ReadString() should call derived this.Read().
775 public override string ReadString ()
777 return ReadStringInternal ();
781 // This class itself does not have this feature.
782 public override void ResolveEntity ()
784 reader.ResolveEntity ();
789 #region IXmlSchemaInfo
792 get { return xsinfo.IsNil; }
795 public XmlSchemaSimpleType MemberType {
796 get { return xsinfo.MemberType; }
799 public XmlSchemaAttribute SchemaAttribute {
800 get { return xsinfo.SchemaAttribute; }
803 public XmlSchemaElement SchemaElement {
804 get { return xsinfo.SchemaElement; }
807 public XmlSchemaValidity Validity {
808 get { return xsinfo.Validity; }