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;
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 (
129 readerLineInfo = reader as IXmlLineInfo;
130 getter = delegate () { return Value; };
131 xsinfo = new XmlSchemaInfo (); // transition cache
132 v.LineInfoProvider = this;
133 v.ValidationEventSender = reader;
134 this.nsResolver = nsResolver;
136 ValidationEventHandler += delegate (object o, ValidationEventArgs e) {
137 settings.OnValidationError (o, e);
139 if (settings != null && settings.Schemas != null)
140 v.XmlResolver = settings.Schemas.XmlResolver;
142 v.XmlResolver = new XmlUrlResolver ();
144 v.XmlResolver = new XmlUrlResolver ();
149 public event ValidationEventHandler ValidationEventHandler {
150 add { v.ValidationEventHandler += value; }
151 remove { v.ValidationEventHandler -= value; }
154 public XmlSchemaType ElementSchemaType {
156 return element != null ? element.ElementSchemaType : null;
160 // clear default attributes, MoveTo*Attribute() transitent
162 private void ResetStateOnRead ()
164 currentDefaultAttribute = -1;
165 defaultAttributeConsumed = false;
166 currentAttrType = null;
167 defaultAttributes = emptyAttributeArray;
172 public int LineNumber {
173 get { return readerLineInfo != null ? readerLineInfo.LineNumber : 0; }
176 public int LinePosition {
177 get { return readerLineInfo != null ? readerLineInfo.LinePosition : 0; }
180 public XmlSchemaType SchemaType {
182 if (ReadState != ReadState.Interactive)
186 case XmlNodeType.Element:
187 if (ElementSchemaType != null)
188 return ElementSchemaType;
190 return null;//SourceReaderSchemaType;
191 case XmlNodeType.Attribute:
192 if (currentAttrType == null) {
193 ComplexType ct = ElementSchemaType as ComplexType;
195 XsAttr attdef = ct.AttributeUses [new XmlQualifiedName (LocalName, NamespaceURI)] as XsAttr;
197 currentAttrType = attdef.AttributeSchemaType;
198 return currentAttrType;
200 // currentAttrType = SourceReaderSchemaType;
202 return currentAttrType;
204 return null;//SourceReaderSchemaType;
209 public ValidationType ValidationType {
210 get { return validationType; }
212 if (ReadState != ReadState.Initial)
213 throw new InvalidOperationException ("ValidationType must be set before reading.");
214 validationType = value;
218 public IDictionary<string, string> GetNamespacesInScope (XmlNamespaceScope scope)
220 IXmlNamespaceResolver resolver = reader as IXmlNamespaceResolver;
221 if (resolver == null)
222 throw new NotSupportedException ("The input XmlReader does not implement IXmlNamespaceResolver and thus this validating reader cannot collect in-scope namespaces.");
223 return resolver.GetNamespacesInScope (scope);
226 public string LookupPrefix (string ns)
228 return nsResolver.LookupPrefix (ns);
231 // Public Overriden Properties
233 public override int AttributeCount {
235 return reader.AttributeCount + defaultAttributes.Length;
239 public override string BaseURI {
240 get { return reader.BaseURI; }
243 // If this class is used to implement XmlValidatingReader,
244 // it should be left to DTDValidatingReader. In other cases,
245 // it depends on the reader's ability.
246 public override bool CanResolveEntity {
247 get { return reader.CanResolveEntity; }
250 public override int Depth {
252 if (currentDefaultAttribute < 0)
254 if (this.defaultAttributeConsumed)
255 return reader.Depth + 2;
256 return reader.Depth + 1;
260 public override bool EOF {
261 get { return reader.EOF; }
264 public override bool HasValue {
266 if (currentDefaultAttribute < 0)
267 return reader.HasValue;
272 public override bool IsDefault {
274 if (currentDefaultAttribute < 0)
275 return reader.IsDefault;
280 public override bool IsEmptyElement {
282 if (currentDefaultAttribute < 0)
283 return reader.IsEmptyElement;
288 public override string this [int i] {
289 get { return GetAttribute (i); }
292 public override string this [string name] {
293 get { return GetAttribute (name); }
296 public override string this [string localName, string ns] {
297 get { return GetAttribute (localName, ns); }
300 int IXmlLineInfo.LineNumber {
301 get { return readerLineInfo != null ? readerLineInfo.LineNumber : 0; }
304 int IXmlLineInfo.LinePosition {
305 get { return readerLineInfo != null ? readerLineInfo.LinePosition : 0; }
308 public override string LocalName {
310 if (currentDefaultAttribute < 0)
311 return reader.LocalName;
312 if (defaultAttributeConsumed)
314 return defaultAttributes [currentDefaultAttribute].QualifiedName.Name;
318 public override string Name {
320 if (currentDefaultAttribute < 0)
322 if (defaultAttributeConsumed)
325 XmlQualifiedName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
326 string prefix = Prefix;
327 if (prefix == String.Empty)
330 return String.Concat (prefix, ":", qname.Name);
334 public override string NamespaceURI {
336 if (currentDefaultAttribute < 0)
337 return reader.NamespaceURI;
338 if (defaultAttributeConsumed)
340 return defaultAttributes [currentDefaultAttribute].QualifiedName.Namespace;
344 public override XmlNameTable NameTable {
345 get { return reader.NameTable; }
348 public override XmlNodeType NodeType {
350 if (currentDefaultAttribute < 0)
351 return reader.NodeType;
352 if (defaultAttributeConsumed)
353 return XmlNodeType.Text;
354 return XmlNodeType.Attribute;
359 public XmlParserContext ParserContext {
360 get { return XmlSchemaUtil.GetParserContext (reader); }
364 public override string Prefix {
366 if (currentDefaultAttribute < 0)
367 return reader.Prefix;
368 if (defaultAttributeConsumed)
370 XmlQualifiedName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
371 string prefix = nsResolver.LookupPrefix (qname.Namespace);
379 public override char QuoteChar {
380 get { return reader.QuoteChar; }
383 public override ReadState ReadState {
384 get { return reader.ReadState; }
387 public override IXmlSchemaInfo SchemaInfo {
391 public override string Value {
393 if (currentDefaultAttribute < 0)
395 string value = defaultAttributes [currentDefaultAttribute].ValidatedDefaultValue;
397 value = defaultAttributes [currentDefaultAttribute].ValidatedFixedValue;
402 public override string XmlLang {
404 string xmlLang = reader.XmlLang;
407 int idx = this.FindDefaultAttribute ("lang", XmlNamespaceManager.XmlnsXml);
410 xmlLang = defaultAttributes [idx].ValidatedDefaultValue;
412 xmlLang = defaultAttributes [idx].ValidatedFixedValue;
417 public override XmlSpace XmlSpace {
419 XmlSpace space = reader.XmlSpace;
420 if (space != XmlSpace.None)
422 int idx = this.FindDefaultAttribute ("space", XmlNamespaceManager.XmlnsXml);
424 return XmlSpace.None;
425 string spaceSpec = defaultAttributes [idx].ValidatedDefaultValue;
426 if (spaceSpec == null)
427 spaceSpec = defaultAttributes [idx].ValidatedFixedValue;
428 return (XmlSpace) Enum.Parse (typeof (XmlSpace), spaceSpec, false);
433 #region Public Methods
437 public override void Close ()
442 public override string GetAttribute (int i)
444 switch (reader.NodeType) {
445 case XmlNodeType.XmlDeclaration:
446 case XmlNodeType.DocumentType:
447 return reader.GetAttribute (i);
450 if (reader.AttributeCount > i)
451 reader.GetAttribute (i);
452 int defIdx = i - reader.AttributeCount;
453 if (i < AttributeCount)
454 return defaultAttributes [defIdx].DefaultValue;
456 throw new ArgumentOutOfRangeException ("i", i, "Specified attribute index is out of range.");
459 public override string GetAttribute (string name)
461 switch (reader.NodeType) {
462 case XmlNodeType.XmlDeclaration:
463 case XmlNodeType.DocumentType:
464 return reader.GetAttribute (name);
467 string value = reader.GetAttribute (name);
471 XmlQualifiedName qname = SplitQName (name);
472 return GetDefaultAttribute (qname.Name, qname.Namespace);
475 private XmlQualifiedName SplitQName (string name)
477 XmlConvert.VerifyName (name);
480 XmlQualifiedName qname = XmlSchemaUtil.ToQName (reader, name, out ex);
482 return XmlQualifiedName.Empty;
487 public override string GetAttribute (string localName, string ns)
489 switch (reader.NodeType) {
490 case XmlNodeType.XmlDeclaration:
491 case XmlNodeType.DocumentType:
492 return reader.GetAttribute (localName, ns);
495 string value = reader.GetAttribute (localName, ns);
499 return GetDefaultAttribute (localName, ns);
502 private string GetDefaultAttribute (string localName, string ns)
504 int idx = this.FindDefaultAttribute (localName, ns);
507 string value = defaultAttributes [idx].ValidatedDefaultValue;
509 value = defaultAttributes [idx].ValidatedFixedValue;
513 private int FindDefaultAttribute (string localName, string ns)
515 for (int i = 0; i < this.defaultAttributes.Length; i++) {
516 XsAttr attr = defaultAttributes [i];
517 if (attr.QualifiedName.Name == localName &&
518 (ns == null || attr.QualifiedName.Namespace == ns))
524 bool IXmlLineInfo.HasLineInfo ()
526 return readerLineInfo != null && readerLineInfo.HasLineInfo ();
529 public override string LookupNamespace (string prefix)
531 return reader.LookupNamespace (prefix);
534 public override void MoveToAttribute (int i)
536 switch (reader.NodeType) {
537 case XmlNodeType.XmlDeclaration:
538 case XmlNodeType.DocumentType:
539 reader.MoveToAttribute (i);
543 currentAttrType = null;
544 if (i < reader.AttributeCount) {
545 reader.MoveToAttribute (i);
546 this.currentDefaultAttribute = -1;
547 this.defaultAttributeConsumed = false;
550 if (i < AttributeCount) {
551 this.currentDefaultAttribute = i - reader.AttributeCount;
552 this.defaultAttributeConsumed = false;
555 throw new ArgumentOutOfRangeException ("i", i, "Attribute index is out of range.");
558 public override bool MoveToAttribute (string name)
560 switch (reader.NodeType) {
561 case XmlNodeType.XmlDeclaration:
562 case XmlNodeType.DocumentType:
563 return reader.MoveToAttribute (name);
566 currentAttrType = null;
567 bool b = reader.MoveToAttribute (name);
569 this.currentDefaultAttribute = -1;
570 this.defaultAttributeConsumed = false;
574 return MoveToDefaultAttribute (name, null);
577 public override bool MoveToAttribute (string localName, string ns)
579 switch (reader.NodeType) {
580 case XmlNodeType.XmlDeclaration:
581 case XmlNodeType.DocumentType:
582 return reader.MoveToAttribute (localName, ns);
585 currentAttrType = null;
586 bool b = reader.MoveToAttribute (localName, ns);
588 this.currentDefaultAttribute = -1;
589 this.defaultAttributeConsumed = false;
593 return MoveToDefaultAttribute (localName, ns);
596 private bool MoveToDefaultAttribute (string localName, string ns)
598 int idx = this.FindDefaultAttribute (localName, ns);
601 currentDefaultAttribute = idx;
602 defaultAttributeConsumed = false;
606 public override bool MoveToElement ()
608 currentDefaultAttribute = -1;
609 defaultAttributeConsumed = false;
610 currentAttrType = null;
611 return reader.MoveToElement ();
614 public override bool MoveToFirstAttribute ()
616 switch (reader.NodeType) {
617 case XmlNodeType.XmlDeclaration:
618 case XmlNodeType.DocumentType:
619 return reader.MoveToFirstAttribute ();
622 currentAttrType = null;
623 if (reader.AttributeCount > 0) {
624 bool b = reader.MoveToFirstAttribute ();
626 currentDefaultAttribute = -1;
627 defaultAttributeConsumed = false;
632 if (this.defaultAttributes.Length > 0) {
633 currentDefaultAttribute = 0;
634 defaultAttributeConsumed = false;
641 public override bool MoveToNextAttribute ()
643 switch (reader.NodeType) {
644 case XmlNodeType.XmlDeclaration:
645 case XmlNodeType.DocumentType:
646 return reader.MoveToNextAttribute ();
649 currentAttrType = null;
650 if (currentDefaultAttribute >= 0) {
651 if (defaultAttributes.Length == currentDefaultAttribute + 1)
653 currentDefaultAttribute++;
654 defaultAttributeConsumed = false;
658 bool b = reader.MoveToNextAttribute ();
660 currentDefaultAttribute = -1;
661 defaultAttributeConsumed = false;
665 if (defaultAttributes.Length > 0) {
666 currentDefaultAttribute = 0;
667 defaultAttributeConsumed = false;
674 public override bool Read ()
676 if (!reader.Read ()) {
677 if (!validationDone) {
679 validationDone = true;
686 switch (reader.NodeType) {
687 case XmlNodeType.Element:
688 string sl = reader.GetAttribute (
690 XmlSchema.InstanceNamespace);
691 string noNsSL = reader.GetAttribute (
692 "noNamespaceSchemaLocation",
693 XmlSchema.InstanceNamespace);
694 string xsiType = reader.GetAttribute ("type",
695 XmlSchema.InstanceNamespace);
696 string xsiNil = reader.GetAttribute ("nil",
697 XmlSchema.InstanceNamespace);
699 v.ValidateElement (reader.LocalName,
707 if (reader.MoveToFirstAttribute ()) {
709 switch (reader.NamespaceURI) {
710 case XmlSchema.InstanceNamespace:
711 switch (reader.LocalName) {
712 case "schemaLocation":
713 case "noNamespaceSchemaLocation":
719 case XmlNamespaceManager.XmlnsXmlns:
722 v.ValidateAttribute (
727 } while (reader.MoveToNextAttribute ());
728 reader.MoveToElement ();
730 v.GetUnspecifiedDefaultAttributes (
731 defaultAttributesCache);
732 defaultAttributes = (XsAttr [])
733 defaultAttributesCache.ToArray (
735 v.ValidateEndOfAttributes (xsinfo);
736 defaultAttributesCache.Clear ();
738 if (reader.IsEmptyElement)
739 goto case XmlNodeType.EndElement;
741 case XmlNodeType.EndElement:
742 // FIXME: find out what another overload means.
743 v.ValidateEndElement (xsinfo);
745 case XmlNodeType.Text:
746 v.ValidateText (getter);
748 case XmlNodeType.SignificantWhitespace:
749 case XmlNodeType.Whitespace:
750 v.ValidateWhitespace (getter);
757 public override bool ReadAttributeValue ()
759 if (currentDefaultAttribute < 0)
760 return reader.ReadAttributeValue ();
762 if (this.defaultAttributeConsumed)
765 defaultAttributeConsumed = true;
770 public override string ReadInnerXml ()
772 // MS.NET 1.0 has a serious bug here. It skips validation.
773 return ReadInnerXmlInternal ();
776 public override string ReadOuterXml ()
778 // MS.NET 1.0 has a serious bug here. It skips validation.
779 return ReadInnerXmlInternal ();
782 // XmlReader.ReadString() should call derived this.Read().
783 public override string ReadString ()
785 return ReadStringInternal ();
789 // This class itself does not have this feature.
790 public override void ResolveEntity ()
792 reader.ResolveEntity ();
797 #region IXmlSchemaInfo
800 get { return xsinfo.IsNil; }
803 public XmlSchemaSimpleType MemberType {
804 get { return xsinfo.MemberType; }
807 public XmlSchemaAttribute SchemaAttribute {
808 get { return xsinfo.SchemaAttribute; }
811 public XmlSchemaElement SchemaElement {
812 get { return xsinfo.SchemaElement; }
815 public XmlSchemaValidity Validity {
816 get { return xsinfo.Validity; }