2 // System.Xml.XmlValidatingReader.cs
5 // Tim Coleman (tim@timcoleman.com)
6 // Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
8 // Copyright (C) Tim Coleman, 2002
9 // (C)2003 Atsushi Enomoto
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 using System
.Collections
;
36 using System
.Xml
.Schema
;
38 using Mono
.Xml
.Schema
;
43 [Obsolete("Use XmlReader created by XmlReader.Create() method using"
44 + " appropriate XmlReaderSettings instead.")]
45 public class XmlValidatingReader
: XmlReader
, IXmlLineInfo
, IXmlNamespaceResolver
, IHasXmlParserContext
47 public class XmlValidatingReader
: XmlReader
, IXmlLineInfo
, IHasXmlParserContext
53 EntityHandling entityHandling
;
54 XmlReader sourceReader
;
55 XmlTextReader xmlTextReader
;
56 XmlReader validatingReader
;
57 XmlResolver resolver
; // Only used to non-XmlTextReader XmlReader
58 bool specifiedResolver
;
59 ValidationType validationType
;
60 // for 2.0: Now it is obsolete. It is allocated only when it is required
62 DTDValidatingReader dtdReader
;
63 IHasXmlSchemaInfo schemaInfo
;
64 StringBuilder storedCharacters
;
70 public XmlValidatingReader (XmlReader reader
)
72 sourceReader
= reader
;
73 xmlTextReader
= reader
as XmlTextReader
;
74 if (xmlTextReader
== null)
75 resolver
= new XmlUrlResolver ();
76 entityHandling
= EntityHandling
.ExpandEntities
;
77 validationType
= ValidationType
.Auto
;
78 schemas
= new XmlSchemaSet ();
79 storedCharacters
= new StringBuilder ();
82 public XmlValidatingReader (Stream xmlFragment
, XmlNodeType fragType
, XmlParserContext context
)
83 : this (new XmlTextReader (xmlFragment
, fragType
, context
))
87 public XmlValidatingReader (string xmlFragment
, XmlNodeType fragType
, XmlParserContext context
)
88 : this (new XmlTextReader (xmlFragment
, fragType
, context
))
92 #endregion // Constructors
96 public override int AttributeCount
{
97 get { return validatingReader == null ? 0 : validatingReader.AttributeCount; }
100 public override string BaseURI
{
101 get { return validatingReader == null ? sourceReader.BaseURI : validatingReader.BaseURI; }
104 // This property for this class always return true.
105 public override bool CanResolveEntity
{
109 public override int Depth
{
110 get { return validatingReader == null ? 0 : validatingReader.Depth; }
113 public Encoding Encoding
{
115 if (xmlTextReader
!= null)
116 return xmlTextReader
.Encoding
;
118 throw new NotSupportedException ("Encoding is supported only for XmlTextReader.");
122 public EntityHandling EntityHandling
{
123 get { return entityHandling; }
124 set { entityHandling = value; }
127 public override bool EOF
{
128 get { return validatingReader == null ? false : validatingReader.EOF; }
131 #if DTD_HANDLE_EVENTS
132 internal bool HasValidationEvent
{
133 get { return ValidationEventHandler != null; }
137 public override bool HasValue
{
138 get { return validatingReader == null ? false : validatingReader.HasValue; }
141 public override bool IsDefault
{
142 get { return validatingReader == null ? false : validatingReader.IsDefault; }
145 public override bool IsEmptyElement
{
146 get { return validatingReader == null ? false : validatingReader.IsEmptyElement; }
151 public override string this [int i
] {
152 get { return GetAttribute (i); }
155 public override string this [string name
] {
156 get { return GetAttribute (name); }
159 public override string this [string localName
, string namespaceName
] {
160 get { return GetAttribute (localName, namespaceName); }
165 public int LineNumber
{
167 int IXmlLineInfo
.LineNumber
{
172 IXmlLineInfo info
= validatingReader
as IXmlLineInfo
;
173 return info
!= null ? info
.LineNumber
: 0;
178 public int LinePosition
{
180 int IXmlLineInfo
.LinePosition
{
185 IXmlLineInfo info
= validatingReader
as IXmlLineInfo
;
186 return info
!= null ? info
.LinePosition
: 0;
190 public override string LocalName
{
192 if (validatingReader
== null)
195 return validatingReader
.LocalName
;
197 return validatingReader
.Name
;
201 public override string Name
{
202 get { return validatingReader == null ? String.Empty : validatingReader.Name; }
205 public bool Namespaces
{
207 if (xmlTextReader
!= null)
208 return xmlTextReader
.Namespaces
;
213 if (ReadState
!= ReadState
.Initial
)
214 throw new InvalidOperationException ("Namespaces have to be set before reading.");
216 if (xmlTextReader
!= null)
217 xmlTextReader
.Namespaces
= value;
219 throw new NotSupportedException ("Property 'Namespaces' is supported only for XmlTextReader.");
223 public override string NamespaceURI
{
225 if (validatingReader
== null)
228 return validatingReader
.NamespaceURI
;
234 public override XmlNameTable NameTable
{
235 get { return validatingReader == null ? sourceReader.NameTable : validatingReader.NameTable; }
238 public override XmlNodeType NodeType
{
239 get { return validatingReader == null ? XmlNodeType.None : validatingReader.NodeType; }
242 public override string Prefix
{
243 get { return validatingReader == null ? String.Empty : validatingReader.Prefix; }
246 public override char QuoteChar
{
247 get { return validatingReader == null ? sourceReader.QuoteChar : validatingReader.QuoteChar; }
250 public XmlReader Reader
{
251 get { return sourceReader; }
254 public override ReadState ReadState
{
256 if (validatingReader
== null)
257 return ReadState
.Initial
;
258 return validatingReader
.ReadState
;
262 internal XmlResolver Resolver
{
264 // This is special rule... MS.NET shares the
265 // XmlResolver between XmlTextReader and
266 // XmlValidatingReader, so we mimick that
267 // silly behavior here.
268 if (this.xmlTextReader
!= null)
269 return this.xmlTextReader
.Resolver
;
275 public XmlSchemaCollection Schemas
{
277 return schemas
.SchemaCollection
;
281 internal void SetSchemas (XmlSchemaSet schemas
)
283 this.schemas
= schemas
;
286 public object SchemaType
{
287 get { return schemaInfo.SchemaType; }
292 public override XmlReaderSettings Settings
{
293 get { return validatingReader == null ? sourceReader.Settings : validatingReader.Settings; }
297 [MonoTODO ("We decided not to support XDR schema that spec is obsolete.")]
298 public ValidationType ValidationType
{
299 get { return validationType; }
301 if (ReadState
!= ReadState
.Initial
)
302 throw new InvalidOperationException ("ValidationType cannot be set after the first call to Read method.");
303 switch (validationType
) {
304 case ValidationType
.Auto
:
305 case ValidationType
.DTD
:
306 case ValidationType
.None
:
307 case ValidationType
.Schema
:
308 validationType
= value;
310 case ValidationType
.XDR
:
311 throw new NotSupportedException ();
316 public override string Value
{
317 get { return validatingReader == null ? String.Empty : validatingReader.Value; }
320 public override string XmlLang
{
321 get { return validatingReader == null ? String.Empty : validatingReader.XmlLang; }
324 public XmlResolver XmlResolver
{
326 specifiedResolver
= true;
327 if (xmlTextReader
!= null)
328 xmlTextReader
.XmlResolver
= value;
332 XsdValidatingReader xsvr
= validatingReader
as XsdValidatingReader
;
334 xsvr
.XmlResolver
= value;
335 DTDValidatingReader dvr
= validatingReader
as DTDValidatingReader
;
337 dvr
.XmlResolver
= value;
341 public override XmlSpace XmlSpace
{
342 get { return validatingReader == null ? XmlSpace.None : validatingReader.XmlSpace; }
345 #endregion // Properties
349 public override void Close ()
351 if (validatingReader
== null)
352 sourceReader
.Close ();
354 validatingReader
.Close ();
357 public override string GetAttribute (int i
)
359 if (validatingReader
== null)
360 throw new IndexOutOfRangeException ("Reader is not started.");
361 return validatingReader
[i
];
364 public override string GetAttribute (string name
)
366 return validatingReader
== null ? null : validatingReader
[name
];
369 public override string GetAttribute (string localName
, string namespaceName
)
371 return validatingReader
== null ? null : validatingReader
[localName
, namespaceName
];
374 XmlParserContext IHasXmlParserContext
.ParserContext
{
375 get { return dtdReader != null ? dtdReader.ParserContext : null; }
379 IDictionary IXmlNamespaceResolver
.GetNamespacesInScope (XmlNamespaceScope scope
)
381 return ((IHasXmlParserContext
) this).ParserContext
.NamespaceManager
.GetNamespacesInScope (scope
);
386 public bool HasLineInfo ()
388 bool IXmlLineInfo
.HasLineInfo ()
391 IXmlLineInfo info
= validatingReader
as IXmlLineInfo
;
392 return info
!= null ? info
.HasLineInfo () : false;
395 public override string LookupNamespace (string prefix
)
397 if (validatingReader
!= null)
398 return sourceReader
.LookupNamespace (prefix
);
400 return validatingReader
.LookupNamespace (prefix
);
404 string IXmlNamespaceResolver
.LookupPrefix (string ns
)
406 IXmlNamespaceResolver res
= null;
407 if (validatingReader
!= null)
408 res
= sourceReader
as IXmlNamespaceResolver
;
410 res
= validatingReader
as IXmlNamespaceResolver
;
412 res
.LookupNamespace (ns
) :
416 string IXmlNamespaceResolver
.LookupPrefix (string ns
, bool atomizedNames
)
418 IXmlNamespaceResolver res
= null;
419 if (validatingReader
!= null)
420 res
= sourceReader
as IXmlNamespaceResolver
;
422 res
= validatingReader
as IXmlNamespaceResolver
;
424 res
.LookupNamespace (ns
, atomizedNames
) :
430 public override void MoveToAttribute (int i
)
432 if (validatingReader
== null)
433 throw new IndexOutOfRangeException ("Reader is not started.");
435 validatingReader
.MoveToAttribute (i
);
438 public override bool MoveToAttribute (string name
)
440 if (validatingReader
== null)
442 return validatingReader
.MoveToAttribute (name
);
445 public override bool MoveToAttribute (string localName
, string namespaceName
)
447 if (validatingReader
== null)
449 return validatingReader
.MoveToAttribute (localName
, namespaceName
);
452 public override bool MoveToElement ()
454 if (validatingReader
== null)
456 return validatingReader
.MoveToElement ();
459 public override bool MoveToFirstAttribute ()
461 if (validatingReader
== null)
463 return validatingReader
.MoveToFirstAttribute ();
466 public override bool MoveToNextAttribute ()
468 if (validatingReader
== null)
470 return validatingReader
.MoveToNextAttribute ();
473 [MonoTODO ("We decided not to support XDR schema that spec is obsolete.")]
474 public override bool Read ()
476 if (ReadState
== ReadState
.Initial
) {
477 switch (ValidationType
) {
478 case ValidationType
.Auto
:
479 case ValidationType
.None
:
480 goto case ValidationType
.Schema
; // might be specified by xsi:schemaLocation.
481 case ValidationType
.DTD
:
482 validatingReader
= dtdReader
= new DTDValidatingReader (sourceReader
, this);
483 dtdReader
.XmlResolver
= Resolver
;
485 case ValidationType
.Schema
:
486 dtdReader
= new DTDValidatingReader (sourceReader
, this);
487 XsdValidatingReader xsvr
= new XsdValidatingReader (dtdReader
, this);
488 xsvr
.Schemas
= Schemas
.SchemaSet
;
489 validatingReader
= xsvr
;
490 xsvr
.XmlResolver
= Resolver
;
491 dtdReader
.XmlResolver
= Resolver
;
493 case ValidationType
.XDR
:
494 throw new NotSupportedException ();
496 schemaInfo
= validatingReader
as IHasXmlSchemaInfo
;
498 return validatingReader
.Read ();
501 public override bool ReadAttributeValue ()
503 if (validatingReader
== null)
505 return validatingReader
.ReadAttributeValue ();
509 // LAMESPEC: MS.NET 1.0 has critical bug here.
510 // After calling these methods, validation does not work anymore!
511 public override string ReadInnerXml ()
513 if (validatingReader
== null)
515 return validatingReader
.ReadInnerXml ();
518 public override string ReadOuterXml ()
520 if (validatingReader
== null)
522 return validatingReader
.ReadOuterXml ();
527 public override string ReadString ()
529 return base.ReadStringInternal ();
532 public override string ReadString ()
534 return base.ReadString ();
539 public override object ReadTypedValue ()
541 public object ReadTypedValue ()
544 if (dtdReader
== null)
546 XmlSchemaDatatype dt
= schemaInfo
.SchemaType
as XmlSchemaDatatype
;
550 case XmlNodeType
.Element
:
554 storedCharacters
.Length
= 0;
559 case XmlNodeType
.SignificantWhitespace
:
560 case XmlNodeType
.Text
:
561 case XmlNodeType
.CDATA
:
562 storedCharacters
.Append (Value
);
564 case XmlNodeType
.Comment
:
570 } while (loop
&& !EOF
);
571 return dt
.ParseValue (storedCharacters
.ToString (), NameTable
, dtdReader
.ParserContext
.NamespaceManager
);
572 case XmlNodeType
.Attribute
:
573 return dt
.ParseValue (Value
, NameTable
, dtdReader
.ParserContext
.NamespaceManager
);
578 public override void ResolveEntity ()
580 validatingReader
.ResolveEntity ();
583 // It should be "protected" as usual "event model"
584 // methods are, but validation event is not exposed,
585 // so it is no other way to make it "internal".
586 internal void OnValidationEvent (object o
, ValidationEventArgs e
)
588 if (ValidationEventHandler
!= null)
589 ValidationEventHandler (o
, e
);
590 else if (ValidationType
!= ValidationType
.None
&& e
.Severity
== XmlSeverityType
.Error
)
593 #endregion // Methods
595 #region Events and Delegates
597 public event ValidationEventHandler ValidationEventHandler
;
599 #endregion // Events and Delegates