2 // System.Xml.XmlTextReader2.cs - XmlTextReader for .NET 2.0
\r
5 // Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
\r
7 // Copyright (C) 2004 Novell, Inc.
\r
11 // Permission is hereby granted, free of charge, to any person obtaining
\r
12 // a copy of this software and associated documentation files (the
\r
13 // "Software"), to deal in the Software without restriction, including
\r
14 // without limitation the rights to use, copy, modify, merge, publish,
\r
15 // distribute, sublicense, and/or sell copies of the Software, and to
\r
16 // permit persons to whom the Software is furnished to do so, subject to
\r
17 // the following conditions:
\r
19 // The above copyright notice and this permission notice shall be
\r
20 // included in all copies or substantial portions of the Software.
\r
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
\r
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
\r
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
\r
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
\r
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
\r
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
\r
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
33 using XmlTextReaderImpl = Mono.Xml2.XmlTextReader;
\r
36 using System.Collections;
\r
37 using System.Globalization;
\r
40 using System.Xml.Schema;
\r
43 namespace System.Xml
\r
45 public class XmlTextReader : XmlReader,
\r
46 IXmlLineInfo, IXmlNamespaceResolver, IHasXmlParserContext
\r
48 XmlTextReader entity;
\r
49 XmlTextReaderImpl source;
\r
50 bool entityInsideAttribute;
\r
51 bool insideAttribute;
\r
52 string cachedAttributeValue;
\r
53 bool attributeValueConsumed;
\r
55 protected XmlTextReader ()
\r
59 public XmlTextReader (Stream input)
\r
60 : this (new XmlStreamReader (input))
\r
64 public XmlTextReader (string url)
\r
65 : this(url, new NameTable ())
\r
69 public XmlTextReader (TextReader input)
\r
70 : this (input, new NameTable ())
\r
74 protected XmlTextReader (XmlNameTable nt)
\r
75 : this (String.Empty, XmlNodeType.Element, null)
\r
79 public XmlTextReader (Stream input, XmlNameTable nt)
\r
80 : this(new XmlStreamReader (input), nt)
\r
84 public XmlTextReader (string url, Stream input)
\r
85 : this (url, new XmlStreamReader (input))
\r
89 public XmlTextReader (string url, TextReader input)
\r
90 : this (url, input, new NameTable ())
\r
94 public XmlTextReader (string url, XmlNameTable nt)
\r
96 source = new XmlTextReaderImpl (url, nt);
\r
99 public XmlTextReader (TextReader input, XmlNameTable nt)
\r
100 : this (String.Empty, input, nt)
\r
104 public XmlTextReader (Stream xmlFragment, XmlNodeType fragType, XmlParserContext context)
\r
106 source = new XmlTextReaderImpl (xmlFragment, fragType, context);
\r
109 public XmlTextReader (string url, Stream input, XmlNameTable nt)
\r
110 : this (url, new XmlStreamReader (input), nt)
\r
114 public XmlTextReader (string url, TextReader input, XmlNameTable nt)
\r
116 source = new XmlTextReaderImpl (url, input, nt);
\r
119 public XmlTextReader (string xmlFragment, XmlNodeType fragType, XmlParserContext context)
\r
121 source = new XmlTextReaderImpl (xmlFragment, fragType, context);
\r
124 private XmlTextReader (XmlTextReaderImpl entityContainer, bool insideAttribute)
\r
126 source = entityContainer;
\r
127 this.entityInsideAttribute = insideAttribute;
\r
132 private XmlReader Current {
\r
133 get { return entity != null && entity.ReadState != ReadState.Initial ? (XmlReader) entity : source; }
\r
136 public override int AttributeCount {
\r
137 get { return Current.AttributeCount; }
\r
140 public override string BaseURI {
\r
141 get { return Current.BaseURI; }
\r
144 public override bool CanReadBinaryContent {
\r
145 get { return true; }
\r
148 public override bool CanReadValueChunk {
\r
149 get { return true; }
\r
152 public override bool CanResolveEntity {
\r
153 get { return true; }
\r
156 public override int Depth {
\r
158 // On EndEntity, depth is the same as that
\r
159 // of EntityReference.
\r
160 if (entity != null && entity.ReadState == ReadState.Interactive)
\r
161 return source.Depth + entity.Depth + 1;
\r
163 return source.Depth;
\r
167 public override bool EOF {
\r
168 get { return source.EOF; }
\r
171 public override bool HasValue {
\r
172 get { return Current.HasValue; }
\r
175 public override bool IsDefault {
\r
176 get { return Current.IsDefault; }
\r
179 public override bool IsEmptyElement {
\r
180 get { return Current.IsEmptyElement; }
\r
183 public override string LocalName {
\r
184 get { return Current.LocalName; }
\r
187 public override string Name {
\r
188 get { return Current.Name; }
\r
191 public override string NamespaceURI {
\r
192 get { return Current.NamespaceURI; }
\r
195 public override XmlNameTable NameTable {
\r
196 get { return Current.NameTable; }
\r
199 public override XmlNodeType NodeType {
\r
201 if (Current == entity)
\r
202 return entity.EOF ? XmlNodeType.EndEntity : entity.NodeType;
\r
204 return source.NodeType;
\r
208 internal XmlParserContext ParserContext {
\r
209 get { return ((IHasXmlParserContext) Current).ParserContext; }
\r
212 XmlParserContext IHasXmlParserContext.ParserContext {
\r
213 get { return this.ParserContext; }
\r
216 public override string Prefix {
\r
217 get { return Current.Prefix; }
\r
220 public override char QuoteChar {
\r
221 get { return Current.QuoteChar; }
\r
224 public override ReadState ReadState {
\r
225 get { return entity != null ? ReadState.Interactive : source.ReadState; }
\r
228 public override XmlReaderSettings Settings {
\r
229 get { return base.Settings; }
\r
232 public override string Value {
\r
233 get { return Current.Value; }
\r
236 public override string XmlLang {
\r
237 get { return Current.XmlLang; }
\r
240 public override XmlSpace XmlSpace {
\r
241 get { return Current.XmlSpace; }
\r
246 internal bool CharacterChecking {
\r
248 if (entity != null)
\r
249 return entity.CharacterChecking;
\r
251 return source.CharacterChecking;
\r
254 if (entity != null)
\r
255 entity.CharacterChecking = value;
\r
256 source.CharacterChecking = value;
\r
260 internal bool CloseInput {
\r
262 if (entity != null)
\r
263 return entity.CloseInput;
\r
265 return source.CloseInput;
\r
268 if (entity != null)
\r
269 entity.CloseInput = value;
\r
270 source.CloseInput = value;
\r
274 internal ConformanceLevel Conformance {
\r
276 if (entity != null)
\r
277 entity.Conformance = value;
\r
278 source.Conformance = value;
\r
282 internal XmlResolver Resolver {
\r
283 get { return source.Resolver; }
\r
286 private void CopyProperties (XmlTextReader other)
\r
288 CharacterChecking = other.CharacterChecking;
\r
289 CloseInput = other.CloseInput;
\r
290 if (other.Settings != null)
\r
291 Conformance = other.Settings.ConformanceLevel;
\r
292 XmlResolver = other.Resolver;
\r
297 public Encoding Encoding {
\r
299 if (entity != null)
\r
300 return entity.Encoding;
\r
302 return source.Encoding;
\r
306 public EntityHandling EntityHandling {
\r
307 get { return source.EntityHandling; }
\r
309 if (entity != null)
\r
310 entity.EntityHandling = value;
\r
311 source.EntityHandling = value;
\r
315 public int LineNumber {
\r
317 if (entity != null)
\r
318 return entity.LineNumber;
\r
320 return source.LineNumber;
\r
324 public int LinePosition {
\r
326 if (entity != null)
\r
327 return entity.LinePosition;
\r
329 return source.LinePosition;
\r
333 public bool Namespaces {
\r
334 get { return source.Namespaces; }
\r
336 if (entity != null)
\r
337 entity.Namespaces = value;
\r
338 source.Namespaces = value;
\r
342 public bool Normalization {
\r
343 get { return source.Normalization; }
\r
345 if (entity != null)
\r
346 entity.Normalization = value;
\r
347 source.Normalization = value;
\r
351 public bool ProhibitDtd {
\r
352 get { return source.ProhibitDtd; }
\r
354 if (entity != null)
\r
355 entity.ProhibitDtd = value;
\r
356 source.ProhibitDtd = value;
\r
360 public WhitespaceHandling WhitespaceHandling {
\r
361 get { return source.WhitespaceHandling; }
\r
363 if (entity != null)
\r
364 entity.WhitespaceHandling = value;
\r
365 source.WhitespaceHandling = value;
\r
369 public XmlResolver XmlResolver {
\r
371 if (entity != null)
\r
372 entity.XmlResolver = value;
\r
373 source.XmlResolver = value;
\r
381 internal void AdjustLineInfoOffset (int lineNumberOffset, int linePositionOffset)
\r
383 if (entity != null)
\r
384 entity.AdjustLineInfoOffset (lineNumberOffset, linePositionOffset);
\r
385 source.AdjustLineInfoOffset (lineNumberOffset, linePositionOffset);
\r
388 internal void SetNameTable (XmlNameTable nameTable)
\r
390 if (entity != null)
\r
391 entity.SetNameTable (nameTable);
\r
392 source.SetNameTable (nameTable);
\r
397 public override void Close ()
\r
399 if (entity != null)
\r
404 public override string GetAttribute (int i)
\r
406 return Current.GetAttribute (i);
\r
409 // MS.NET 1.0 msdn says that this method returns String.Empty
\r
410 // for absent attribute, but in fact it returns null.
\r
411 // This description is corrected in MS.NET 1.1 msdn.
\r
412 public override string GetAttribute (string name)
\r
414 return Current.GetAttribute (name);
\r
417 public override string GetAttribute (string localName, string namespaceURI)
\r
419 return Current.GetAttribute (localName, namespaceURI);
\r
422 public IDictionary GetNamespacesInScope (XmlNamespaceScope scope)
\r
424 return ((IXmlNamespaceResolver) Current).GetNamespacesInScope (scope);
\r
427 public override string LookupNamespace (string prefix)
\r
429 return Current.LookupNamespace (prefix, false);
\r
432 public override string LookupNamespace (string prefix, bool atomizedName)
\r
434 return ((IXmlNamespaceResolver) Current).LookupNamespace (prefix, atomizedName);
\r
437 string IXmlNamespaceResolver.LookupPrefix (string ns)
\r
439 return ((IXmlNamespaceResolver) Current).LookupPrefix (ns, false);
\r
442 public string LookupPrefix (string ns, bool atomizedName)
\r
444 return ((IXmlNamespaceResolver) Current).LookupPrefix (ns, atomizedName);
\r
447 public override void MoveToAttribute (int i)
\r
449 if (entity != null && entityInsideAttribute) {
\r
453 Current.MoveToAttribute (i);
\r
454 insideAttribute = true;
\r
457 public override bool MoveToAttribute (string name)
\r
459 if (entity != null && !entityInsideAttribute)
\r
460 return entity.MoveToAttribute (name);
\r
461 if (!source.MoveToAttribute (name))
\r
463 if (entity != null && entityInsideAttribute) {
\r
467 insideAttribute = true;
\r
471 public override bool MoveToAttribute (string localName, string namespaceName)
\r
473 if (entity != null && !entityInsideAttribute)
\r
474 return entity.MoveToAttribute (localName, namespaceName);
\r
475 if (!source.MoveToAttribute (localName, namespaceName))
\r
477 if (entity != null && entityInsideAttribute) {
\r
481 insideAttribute = true;
\r
485 public override bool MoveToElement ()
\r
487 if (entity != null && entityInsideAttribute) {
\r
491 if (!Current.MoveToElement ())
\r
493 insideAttribute = false;
\r
497 public override bool MoveToFirstAttribute ()
\r
499 if (entity != null && !entityInsideAttribute)
\r
500 return entity.MoveToFirstAttribute ();
\r
501 if (!source.MoveToFirstAttribute ())
\r
503 if (entity != null && entityInsideAttribute) {
\r
507 insideAttribute = true;
\r
511 public override bool MoveToNextAttribute ()
\r
513 if (entity != null && !entityInsideAttribute)
\r
514 return entity.MoveToNextAttribute ();
\r
515 if (!source.MoveToNextAttribute ())
\r
517 if (entity != null && entityInsideAttribute) {
\r
521 insideAttribute = true;
\r
525 public override bool Read ()
\r
527 insideAttribute = false;
\r
529 if (entity != null && (entityInsideAttribute || entity.EOF)) {
\r
533 if (entity != null) {
\r
534 if (entity.Read ())
\r
536 if (EntityHandling == EntityHandling.ExpandEntities) {
\r
537 // EndEntity must be skipped
\r
543 return true; // either success or EndEntity
\r
546 if (!source.Read ())
\r
548 if (EntityHandling == EntityHandling.ExpandEntities
\r
549 && source.NodeType == XmlNodeType.EntityReference) {
\r
557 public override bool ReadAttributeValue ()
\r
559 if (entity != null && entityInsideAttribute) {
\r
566 return true; // either success or EndEntity
\r
569 return Current.ReadAttributeValue ();
\r
572 public override string ReadString ()
\r
574 return base.ReadString ();
\r
577 public void ResetState ()
\r
579 if (entity != null)
\r
580 entity.ResetState ();
\r
581 source.ResetState ();
\r
584 public override void ResolveEntity ()
\r
586 if (entity != null)
\r
587 entity.ResolveEntity ();
\r
589 if (source.NodeType != XmlNodeType.EntityReference)
\r
590 throw new InvalidOperationException ("The current node is not an Entity Reference");
\r
591 XmlTextReaderImpl entReader =
\r
592 ParserContext.Dtd.GenerateEntityContentReader (source.Name, ParserContext);
\r
593 if (entReader == null)
\r
594 throw new XmlException (this as IXmlLineInfo, this.BaseURI, String.Format ("Reference to undeclared entity '{0}'.", source.Name));
\r
595 entity = new XmlTextReader (
\r
596 entReader, insideAttribute);
\r
597 entity.CopyProperties (this);
\r
601 public override void Skip ()
\r
606 [MonoTODO ("Check how expanded entity is handled here.")]
\r
607 public TextReader GetRemainder ()
\r
609 if (entity != null) {
\r
613 return source.GetRemainder ();
\r
616 public bool HasLineInfo ()
\r
621 [MonoTODO ("Check how expanded entity is handled here.")]
\r
622 public int ReadBase64 (byte [] buffer, int offset, int length)
\r
624 if (entity != null)
\r
625 return entity.ReadBase64 (buffer, offset, length);
\r
627 return source.ReadBase64 (buffer, offset, length);
\r
630 [MonoTODO ("Check how expanded entity is handled here.")]
\r
631 public int ReadBinHex (byte [] buffer, int offset, int length)
\r
633 if (entity != null)
\r
634 return entity.ReadBinHex (buffer, offset, length);
\r
636 return source.ReadBinHex (buffer, offset, length);
\r
639 [MonoTODO ("Check how expanded entity is handled here.")]
\r
640 public int ReadChars (char [] buffer, int offset, int length)
\r
642 if (entity != null)
\r
643 return entity.ReadChars (buffer, offset, length);
\r
645 return source.ReadChars (buffer, offset, length);
\r
649 [MonoTODO ("Check how expanded entity is handled here.")]
\r
650 public override int ReadContentAsBase64 (byte [] buffer, int offset, int length)
\r
652 if (entity != null)
\r
653 return entity.ReadContentAsBase64 (buffer, offset, length);
\r
655 return source.ReadContentAsBase64 (buffer, offset, length);
\r
658 [MonoTODO ("Check how expanded entity is handled here.")]
\r
659 public override int ReadContentAsBinHex (byte [] buffer, int offset, int length)
\r
661 if (entity != null)
\r
662 return entity.ReadContentAsBinHex (buffer, offset, length);
\r
664 return source.ReadContentAsBinHex (buffer, offset, length);
\r
667 [MonoTODO ("Check how expanded entity is handled here.")]
\r
668 public override int ReadElementContentAsBase64 (byte [] buffer, int offset, int length)
\r
670 if (entity != null)
\r
671 return entity.ReadElementContentAsBase64 (buffer, offset, length);
\r
673 return source.ReadElementContentAsBase64 (buffer, offset, length);
\r
676 [MonoTODO ("Check how expanded entity is handled here.")]
\r
677 public override int ReadElementContentAsBinHex (byte [] buffer, int offset, int length)
\r
679 if (entity != null)
\r
680 return entity.ReadElementContentAsBinHex (buffer, offset, length);
\r
682 return source.ReadElementContentAsBinHex (buffer, offset, length);
\r