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.");
117 nsResolver = new XmlNamespaceManager (reader.NameTable);
119 XmlSchemaSet schemas = settings.Schemas;
121 schemas = new XmlSchemaSet ();
122 options = settings.ValidationFlags;
124 this.reader = reader;
125 v = new XmlSchemaValidator (
131 readerLineInfo = reader as IXmlLineInfo;
132 startDepth = reader.Depth;
133 getter = delegate () { return Value; };
134 xsinfo = new XmlSchemaInfo (); // transition cache
135 v.LineInfoProvider = this;
136 v.ValidationEventSender = reader;
138 if (settings != null && settings.Schemas != null)
139 v.XmlResolver = settings.Schemas.XmlResolver;
141 v.XmlResolver = new XmlUrlResolver ();
143 v.XmlResolver = new XmlUrlResolver ();
148 public ValidationEventHandler ValidationEventHandler;
150 public XmlSchemaType ElementSchemaType {
152 return element != null ? element.ElementSchemaType : null;
156 // clear default attributes, MoveTo*Attribute() transitent
158 private void ResetStateOnRead ()
160 currentDefaultAttribute = -1;
161 defaultAttributeConsumed = false;
162 currentAttrType = null;
163 defaultAttributes = emptyAttributeArray;
168 public int LineNumber {
169 get { return readerLineInfo != null ? readerLineInfo.LineNumber : 0; }
172 public int LinePosition {
173 get { return readerLineInfo != null ? readerLineInfo.LinePosition : 0; }
176 public XmlSchemaType SchemaType {
178 if (ReadState != ReadState.Interactive)
182 case XmlNodeType.Element:
183 if (ElementSchemaType != null)
184 return ElementSchemaType;
186 return null;//SourceReaderSchemaType;
187 case XmlNodeType.Attribute:
188 if (currentAttrType == null) {
189 ComplexType ct = ElementSchemaType as ComplexType;
191 XsAttr attdef = ct.AttributeUses [new XmlQualifiedName (LocalName, NamespaceURI)] as XsAttr;
193 currentAttrType = attdef.AttributeSchemaType;
194 return currentAttrType;
196 // currentAttrType = SourceReaderSchemaType;
198 return currentAttrType;
200 return null;//SourceReaderSchemaType;
205 public ValidationType ValidationType {
206 get { return validationType; }
208 if (ReadState != ReadState.Initial)
209 throw new InvalidOperationException ("ValidationType must be set before reading.");
210 validationType = value;
214 public IDictionary<string, string> 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 public string LookupPrefix (string ns)
224 return nsResolver.LookupPrefix (ns);
227 // Public Overriden Properties
229 public override int AttributeCount {
231 return reader.AttributeCount + defaultAttributes.Length;
235 public override string BaseURI {
236 get { return reader.BaseURI; }
239 // If this class is used to implement XmlValidatingReader,
240 // it should be left to DTDValidatingReader. In other cases,
241 // it depends on the reader's ability.
242 public override bool CanResolveEntity {
243 get { return reader.CanResolveEntity; }
246 public override int Depth {
248 if (currentDefaultAttribute < 0)
250 if (this.defaultAttributeConsumed)
251 return reader.Depth + 2;
252 return reader.Depth + 1;
256 public override bool EOF {
257 get { return reader.EOF; }
260 public override bool HasValue {
262 if (currentDefaultAttribute < 0)
263 return reader.HasValue;
268 public override bool IsDefault {
270 if (currentDefaultAttribute < 0)
271 return reader.IsDefault;
276 public override bool IsEmptyElement {
278 if (currentDefaultAttribute < 0)
279 return reader.IsEmptyElement;
284 public override string this [int i] {
285 get { return GetAttribute (i); }
288 public override string this [string name] {
289 get { return GetAttribute (name); }
292 public override string this [string localName, string ns] {
293 get { return GetAttribute (localName, ns); }
296 int IXmlLineInfo.LineNumber {
297 get { return readerLineInfo != null ? readerLineInfo.LineNumber : 0; }
300 int IXmlLineInfo.LinePosition {
301 get { return readerLineInfo != null ? readerLineInfo.LinePosition : 0; }
304 public override string LocalName {
306 if (currentDefaultAttribute < 0)
307 return reader.LocalName;
308 if (defaultAttributeConsumed)
310 return defaultAttributes [currentDefaultAttribute].QualifiedName.Name;
314 public override string Name {
316 if (currentDefaultAttribute < 0)
318 if (defaultAttributeConsumed)
321 XmlQualifiedName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
322 string prefix = Prefix;
323 if (prefix == String.Empty)
326 return String.Concat (prefix, ":", qname.Name);
330 public override string NamespaceURI {
332 if (currentDefaultAttribute < 0)
333 return reader.NamespaceURI;
334 if (defaultAttributeConsumed)
336 return defaultAttributes [currentDefaultAttribute].QualifiedName.Namespace;
340 public override XmlNameTable NameTable {
341 get { return reader.NameTable; }
344 public override XmlNodeType NodeType {
346 if (currentDefaultAttribute < 0)
347 return reader.NodeType;
348 if (defaultAttributeConsumed)
349 return XmlNodeType.Text;
350 return XmlNodeType.Attribute;
355 public XmlParserContext ParserContext {
356 get { return XmlSchemaUtil.GetParserContext (reader); }
360 public override string Prefix {
362 if (currentDefaultAttribute < 0)
363 return reader.Prefix;
364 if (defaultAttributeConsumed)
366 XmlQualifiedName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
367 string prefix = nsResolver.LookupPrefix (qname.Namespace);
375 public override char QuoteChar {
376 get { return reader.QuoteChar; }
379 public override ReadState ReadState {
380 get { return reader.ReadState; }
383 public override IXmlSchemaInfo SchemaInfo {
387 public override string Value {
389 if (currentDefaultAttribute < 0)
391 string value = defaultAttributes [currentDefaultAttribute].ValidatedDefaultValue;
393 value = defaultAttributes [currentDefaultAttribute].ValidatedFixedValue;
398 public override string XmlLang {
400 string xmlLang = reader.XmlLang;
403 int idx = this.FindDefaultAttribute ("lang", XmlNamespaceManager.XmlnsXml);
406 xmlLang = defaultAttributes [idx].ValidatedDefaultValue;
408 xmlLang = defaultAttributes [idx].ValidatedFixedValue;
413 public override XmlSpace XmlSpace {
415 XmlSpace space = reader.XmlSpace;
416 if (space != XmlSpace.None)
418 int idx = this.FindDefaultAttribute ("space", XmlNamespaceManager.XmlnsXml);
420 return XmlSpace.None;
421 string spaceSpec = defaultAttributes [idx].ValidatedDefaultValue;
422 if (spaceSpec == null)
423 spaceSpec = defaultAttributes [idx].ValidatedFixedValue;
424 return (XmlSpace) Enum.Parse (typeof (XmlSpace), spaceSpec, false);
429 #region Public Methods
433 public override void Close ()
438 public override string GetAttribute (int i)
440 switch (reader.NodeType) {
441 case XmlNodeType.XmlDeclaration:
442 case XmlNodeType.DocumentType:
443 return reader.GetAttribute (i);
446 if (reader.AttributeCount > i)
447 reader.GetAttribute (i);
448 int defIdx = i - reader.AttributeCount;
449 if (i < AttributeCount)
450 return defaultAttributes [defIdx].DefaultValue;
452 throw new ArgumentOutOfRangeException ("i", i, "Specified attribute index is out of range.");
455 public override string GetAttribute (string name)
457 switch (reader.NodeType) {
458 case XmlNodeType.XmlDeclaration:
459 case XmlNodeType.DocumentType:
460 return reader.GetAttribute (name);
463 string value = reader.GetAttribute (name);
467 XmlQualifiedName qname = SplitQName (name);
468 return GetDefaultAttribute (qname.Name, qname.Namespace);
471 private XmlQualifiedName SplitQName (string name)
473 XmlConvert.VerifyName (name);
476 XmlQualifiedName qname = XmlSchemaUtil.ToQName (reader, name, out ex);
478 return XmlQualifiedName.Empty;
483 public override string GetAttribute (string localName, string ns)
485 switch (reader.NodeType) {
486 case XmlNodeType.XmlDeclaration:
487 case XmlNodeType.DocumentType:
488 return reader.GetAttribute (localName, ns);
491 string value = reader.GetAttribute (localName, ns);
495 return GetDefaultAttribute (localName, ns);
498 private string GetDefaultAttribute (string localName, string ns)
500 int idx = this.FindDefaultAttribute (localName, ns);
503 string value = defaultAttributes [idx].ValidatedDefaultValue;
505 value = defaultAttributes [idx].ValidatedFixedValue;
509 private int FindDefaultAttribute (string localName, string ns)
511 for (int i = 0; i < this.defaultAttributes.Length; i++) {
512 XsAttr attr = defaultAttributes [i];
513 if (attr.QualifiedName.Name == localName &&
514 (ns == null || attr.QualifiedName.Namespace == ns))
520 bool IXmlLineInfo.HasLineInfo ()
522 return readerLineInfo != null && readerLineInfo.HasLineInfo ();
525 public override string LookupNamespace (string prefix)
527 return reader.LookupNamespace (prefix);
530 public override void MoveToAttribute (int i)
532 switch (reader.NodeType) {
533 case XmlNodeType.XmlDeclaration:
534 case XmlNodeType.DocumentType:
535 reader.MoveToAttribute (i);
539 currentAttrType = null;
540 if (i < reader.AttributeCount) {
541 reader.MoveToAttribute (i);
542 this.currentDefaultAttribute = -1;
543 this.defaultAttributeConsumed = false;
546 if (i < AttributeCount) {
547 this.currentDefaultAttribute = i - reader.AttributeCount;
548 this.defaultAttributeConsumed = false;
551 throw new ArgumentOutOfRangeException ("i", i, "Attribute index is out of range.");
554 public override bool MoveToAttribute (string name)
556 switch (reader.NodeType) {
557 case XmlNodeType.XmlDeclaration:
558 case XmlNodeType.DocumentType:
559 return reader.MoveToAttribute (name);
562 currentAttrType = null;
563 bool b = reader.MoveToAttribute (name);
565 this.currentDefaultAttribute = -1;
566 this.defaultAttributeConsumed = false;
570 return MoveToDefaultAttribute (name, null);
573 public override bool MoveToAttribute (string localName, string ns)
575 switch (reader.NodeType) {
576 case XmlNodeType.XmlDeclaration:
577 case XmlNodeType.DocumentType:
578 return reader.MoveToAttribute (localName, ns);
581 currentAttrType = null;
582 bool b = reader.MoveToAttribute (localName, ns);
584 this.currentDefaultAttribute = -1;
585 this.defaultAttributeConsumed = false;
589 return MoveToDefaultAttribute (localName, ns);
592 private bool MoveToDefaultAttribute (string localName, string ns)
594 int idx = this.FindDefaultAttribute (localName, ns);
597 currentDefaultAttribute = idx;
598 defaultAttributeConsumed = false;
602 public override bool MoveToElement ()
604 currentDefaultAttribute = -1;
605 defaultAttributeConsumed = false;
606 currentAttrType = null;
607 return reader.MoveToElement ();
610 public override bool MoveToFirstAttribute ()
612 switch (reader.NodeType) {
613 case XmlNodeType.XmlDeclaration:
614 case XmlNodeType.DocumentType:
615 return reader.MoveToFirstAttribute ();
618 currentAttrType = null;
619 if (reader.AttributeCount > 0) {
620 bool b = reader.MoveToFirstAttribute ();
622 currentDefaultAttribute = -1;
623 defaultAttributeConsumed = false;
628 if (this.defaultAttributes.Length > 0) {
629 currentDefaultAttribute = 0;
630 defaultAttributeConsumed = false;
637 public override bool MoveToNextAttribute ()
639 switch (reader.NodeType) {
640 case XmlNodeType.XmlDeclaration:
641 case XmlNodeType.DocumentType:
642 return reader.MoveToNextAttribute ();
645 currentAttrType = null;
646 if (currentDefaultAttribute >= 0) {
647 if (defaultAttributes.Length == currentDefaultAttribute + 1)
649 currentDefaultAttribute++;
650 defaultAttributeConsumed = false;
654 bool b = reader.MoveToNextAttribute ();
656 currentDefaultAttribute = -1;
657 defaultAttributeConsumed = false;
661 if (defaultAttributes.Length > 0) {
662 currentDefaultAttribute = 0;
663 defaultAttributeConsumed = false;
670 public override bool Read ()
672 if (!reader.Read ()) {
679 switch (reader.NodeType) {
680 case XmlNodeType.Element:
681 string sl = reader.GetAttribute (
683 XmlSchema.InstanceNamespace);
684 string noNsSL = reader.GetAttribute (
685 "noNamespaceSchemaLocation",
686 XmlSchema.InstanceNamespace);
687 string xsiType = reader.GetAttribute ("type",
688 XmlSchema.InstanceNamespace);
689 string xsiNil = reader.GetAttribute ("nil",
690 XmlSchema.InstanceNamespace);
692 v.ValidateElement (reader.LocalName,
700 if (reader.MoveToFirstAttribute ()) {
702 switch (reader.NamespaceURI) {
703 case XmlSchema.InstanceNamespace:
704 switch (reader.LocalName) {
705 case "schemaLocation":
706 case "noNamespaceSchemaLocation":
712 case XmlNamespaceManager.XmlnsXmlns:
715 v.ValidateAttribute (
720 } while (reader.MoveToNextAttribute ());
721 reader.MoveToElement ();
723 v.GetUnspecifiedDefaultAttributes (
724 defaultAttributesCache);
725 defaultAttributes = (XsAttr [])
726 defaultAttributesCache.ToArray (
728 v.ValidateEndOfAttributes (xsinfo);
729 defaultAttributesCache.Clear ();
731 if (reader.IsEmptyElement)
732 goto case XmlNodeType.EndElement;
734 case XmlNodeType.EndElement:
735 // FIXME: find out what another overload means.
736 v.ValidateEndElement (xsinfo);
738 case XmlNodeType.Text:
739 v.ValidateText (getter);
741 case XmlNodeType.SignificantWhitespace:
742 case XmlNodeType.Whitespace:
743 v.ValidateWhitespace (getter);
750 public override bool ReadAttributeValue ()
752 if (currentDefaultAttribute < 0)
753 return reader.ReadAttributeValue ();
755 if (this.defaultAttributeConsumed)
758 defaultAttributeConsumed = true;
763 public override string ReadInnerXml ()
765 // MS.NET 1.0 has a serious bug here. It skips validation.
766 return ReadInnerXmlInternal ();
769 public override string ReadOuterXml ()
771 // MS.NET 1.0 has a serious bug here. It skips validation.
772 return ReadInnerXmlInternal ();
775 // XmlReader.ReadString() should call derived this.Read().
776 public override string ReadString ()
778 return ReadStringInternal ();
782 // This class itself does not have this feature.
783 public override void ResolveEntity ()
785 reader.ResolveEntity ();
790 #region IXmlSchemaInfo
793 get { return xsinfo.IsNil; }
796 public XmlSchemaSimpleType MemberType {
797 get { return xsinfo.MemberType; }
800 public XmlSchemaAttribute SchemaAttribute {
801 get { return xsinfo.SchemaAttribute; }
804 public XmlSchemaElement SchemaElement {
805 get { return xsinfo.SchemaElement; }
808 public XmlSchemaValidity Validity {
809 get { return xsinfo.Validity; }