1 // -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
\r
3 // System.Xml.XmlTextReader.cs
\r
6 // Jason Diamond (jason@injektilo.org)
\r
8 // (C) 2001 Jason Diamond http://injektilo.org/
\r
12 // This can only parse basic XML: elements, attributes, processing
\r
13 // instructions, and comments are OK but there's no support for
\r
14 // entity/character references or namespaces yet.
\r
16 // It barfs on DOCTYPE declarations and CDATA sections.
\r
18 // There's also no checking being done for either well-formedness
\r
21 // ParserContext and NameTables aren't being used yet.
\r
23 // The XmlTextReader-specific properties and methods have yet to
\r
24 // be added or implemented.
\r
26 // Some thought needs to be given to performance. There's too many
\r
27 // strings and string builders being allocated.
\r
29 // None of the MoveTo methods have been implemented yet.
\r
31 // LineNumber and LinePosition aren't being tracked.
\r
33 // xml:space, xml:lang, and xml:base aren't being tracked.
\r
35 // Depth isn't being tracked.
\r
38 using System.Collections;
\r
43 namespace System.Xml
\r
45 public class XmlTextReader : XmlReader
\r
49 protected XmlTextReader()
\r
54 public XmlTextReader(Stream input)
\r
57 reader = new StreamReader(
\r
63 public XmlTextReader(string url)
\r
66 WebClient client = new WebClient();
\r
67 reader = new StreamReader(
\r
68 client.OpenRead(url),
\r
73 public XmlTextReader(TextReader input)
\r
79 public XmlTextReader(Stream input, XmlNameTable nameTable)
\r
81 // TODO: implement me.
\r
82 throw new NotImplementedException();
\r
85 public XmlTextReader(string baseURI, Stream input)
\r
87 // TODO: implement me.
\r
88 throw new NotImplementedException();
\r
91 public XmlTextReader(string baseURI, TextReader input)
\r
93 // TODO: implement me.
\r
94 throw new NotImplementedException();
\r
97 public XmlTextReader(string url, XmlNameTable nameTable)
\r
99 // TODO: implement me.
\r
100 throw new NotImplementedException();
\r
103 public XmlTextReader(
\r
105 XmlNameTable nameTable)
\r
107 // TODO: implement me.
\r
108 throw new NotImplementedException();
\r
111 public XmlTextReader(
\r
112 Stream inputFragment,
\r
113 XmlNodeType fragmentType,
\r
114 XmlParserContext context)
\r
116 // TODO: implement me.
\r
117 throw new NotImplementedException();
\r
120 public XmlTextReader(
\r
123 XmlNameTable nameTable)
\r
125 // TODO: implement me.
\r
126 throw new NotImplementedException();
\r
129 public XmlTextReader(
\r
132 XmlNameTable nameTable)
\r
134 // TODO: implement me.
\r
135 throw new NotImplementedException();
\r
138 public XmlTextReader(
\r
140 XmlNodeType fragmentType,
\r
141 XmlParserContext context)
\r
143 // TODO: implement me.
\r
144 throw new NotImplementedException();
\r
149 public override int AttributeCount
\r
153 return attributes.Count;
\r
157 public override string BaseURI
\r
161 // TODO: implement me.
\r
166 public override bool CanResolveEntity
\r
170 // TODO: implement me.
\r
175 public override int Depth
\r
179 // TODO: implement me.
\r
184 public override bool EOF
\r
189 readState == ReadState.EndOfFile ||
\r
190 readState == ReadState.Closed;
\r
194 public override bool HasValue
\r
198 return value != String.Empty;
\r
202 public override bool IsDefault
\r
206 // TODO: implement me.
\r
211 public override bool IsEmptyElement
\r
215 return isEmptyElement;
\r
219 public override string this[int i]
\r
223 return GetAttribute(i);
\r
227 public override string this[string name]
\r
231 return GetAttribute(name);
\r
235 public override string this[
\r
237 string namespaceName]
\r
241 return GetAttribute(localName, namespaceName);
\r
245 public override string LocalName
\r
249 // TODO: implement me.
\r
254 public override string Name
\r
262 public override string NamespaceURI
\r
266 // TODO: implement me.
\r
271 public override XmlNameTable NameTable
\r
275 // TODO: implement me.
\r
280 public override XmlNodeType NodeType
\r
288 public override string Prefix
\r
292 // TODO: implement me.
\r
297 public override char QuoteChar
\r
301 // TODO: implement me.
\r
306 public override ReadState ReadState
\r
314 public override string Value
\r
322 public override string XmlLang
\r
326 // TODO: implement me.
\r
331 public override XmlSpace XmlSpace
\r
335 // TODO: implement me.
\r
336 return XmlSpace.Default;
\r
342 public override void Close()
\r
344 readState = ReadState.Closed;
\r
347 public override string GetAttribute(int i)
\r
349 // TODO: implement me.
\r
353 public override string GetAttribute(string name)
\r
355 return (string)attributes[name];
\r
358 public override string GetAttribute(
\r
360 string namespaceName)
\r
362 // TODO: implement me.
\r
366 public override string LookupNamespace(string prefix)
\r
368 // TODO: implement me.
\r
372 public override void MoveToAttribute(int i)
\r
374 // TODO: implement me.
\r
377 public override bool MoveToAttribute(string name)
\r
379 // TODO: implement me.
\r
383 public override bool MoveToAttribute(
\r
385 string namespaceName)
\r
387 // TODO: implement me.
\r
391 public override bool MoveToElement()
\r
393 // TODO: implement me.
\r
397 public override bool MoveToFirstAttribute()
\r
399 // TODO: implement me.
\r
403 public override bool MoveToNextAttribute()
\r
405 // TODO: implement me.
\r
409 public override bool Read()
\r
413 readState = ReadState.Interactive;
\r
415 more = ReadContent();
\r
420 public override bool ReadAttributeValue()
\r
422 // TODO: implement me.
\r
426 public override string ReadInnerXml()
\r
428 // TODO: implement me.
\r
432 public override string ReadOuterXml()
\r
434 // TODO: implement me.
\r
438 public override string ReadString()
\r
440 // TODO: implement me.
\r
444 public override void ResolveEntity()
\r
446 // TODO: implement me.
\r
451 private TextReader reader;
\r
452 private ReadState readState;
\r
454 private XmlNodeType nodeType;
\r
455 private string name;
\r
456 private bool isEmptyElement;
\r
457 private string value;
\r
458 private Hashtable attributes;
\r
460 private void Init()
\r
462 readState = ReadState.Initial;
\r
464 nodeType = XmlNodeType.None;
\r
465 name = String.Empty;
\r
466 isEmptyElement = false;
\r
467 value = String.Empty;
\r
468 attributes = new Hashtable();
\r
471 // Use this method rather than setting the properties
\r
472 // directly so that all the necessary properties can
\r
473 // be changed in harmony with each other. Maybe the
\r
474 // fields should be in a seperate class to help enforce
\r
476 private void SetProperties(
\r
477 XmlNodeType nodeType,
\r
479 bool isEmptyElement,
\r
481 bool clearAttributes)
\r
483 this.nodeType = nodeType;
\r
485 this.isEmptyElement = isEmptyElement;
\r
486 this.value = value;
\r
488 if (clearAttributes)
\r
494 private void AddAttribute(string name, string value)
\r
496 attributes.Add(name, value);
\r
499 private void ClearAttributes()
\r
501 attributes.Clear();
\r
504 // This should really keep track of some state so
\r
505 // that it's not possible to have more than one document
\r
506 // element or text outside of the document element.
\r
507 private bool ReadContent()
\r
511 switch (reader.Peek())
\r
519 readState = ReadState.EndOfFile;
\r
521 XmlNodeType.None, // nodeType
\r
522 String.Empty, // name
\r
523 false, // isEmptyElement
\r
524 String.Empty, // value
\r
525 true // clearAttributes
\r
538 // The leading '<' has already been consumed.
\r
539 private void ReadTag()
\r
541 switch (reader.Peek())
\r
549 ReadProcessingInstruction();
\r
561 // The leading '<' has already been consumed.
\r
562 private void ReadStartTag()
\r
564 string name = ReadName();
\r
567 bool isEmptyElement = false;
\r
571 if (XmlChar.IsFirstNameChar(reader.Peek()))
\r
576 if (reader.Peek() == '/')
\r
579 isEmptyElement = true;
\r
585 XmlNodeType.Element, // nodeType
\r
587 isEmptyElement, // isEmptyElement
\r
588 String.Empty, // value
\r
589 false // clearAttributes
\r
593 // The reader is positioned on the first character
\r
594 // of the element's name.
\r
595 private void ReadEndTag()
\r
597 string name = ReadName();
\r
602 XmlNodeType.EndElement, // nodeType
\r
604 false, // isEmptyElement
\r
605 String.Empty, // value
\r
606 true // clearAttributes
\r
610 // The reader is positioned on the first character
\r
612 private void ReadText()
\r
614 StringBuilder text = new StringBuilder();
\r
615 text.Append((char)reader.Read());
\r
617 while (reader.Peek() != '<' && reader.Peek() != -1)
\r
619 text.Append((char)reader.Read());
\r
623 XmlNodeType.Text, // nodeType
\r
624 String.Empty, // name
\r
625 false, // isEmptyElement
\r
626 text.ToString(), // value
\r
627 true // clearAttributes
\r
631 // The reader is positioned on the first character of
\r
632 // the attribute name.
\r
633 private void ReadAttributes()
\r
637 string name = ReadName();
\r
641 string value = ReadAttribute();
\r
644 AddAttribute(name, value);
\r
646 while (reader.Peek() != '/' && reader.Peek() != '>' && reader.Peek() != -1);
\r
649 // The reader is positioned on the quote character.
\r
650 private string ReadAttribute()
\r
652 int quoteChar = reader.Read();
\r
654 if (quoteChar != '\'' && quoteChar != '\"')
\r
656 throw new Exception("an attribute value was not quoted");
\r
659 StringBuilder valueBuilder = new StringBuilder();
\r
661 while (reader.Peek() != quoteChar)
\r
663 int ch = reader.Read();
\r
668 throw new Exception("attribute values cannot contain '<'");
\r
670 throw new Exception("unexpected end of file in an attribute value");
\r
673 valueBuilder.Append((char)ch);
\r
678 return valueBuilder.ToString();
\r
681 // The reader is positioned on the first character
\r
683 private void ReadProcessingInstruction()
\r
685 string target = ReadName();
\r
688 StringBuilder valueBuilder = new StringBuilder();
\r
690 while (reader.Peek() != -1)
\r
692 int ch = reader.Read();
\r
694 if (ch == '?' && reader.Peek() == '>')
\r
700 valueBuilder.Append((char)ch);
\r
704 XmlNodeType.ProcessingInstruction, // nodeType
\r
706 false, // isEmptyElement
\r
707 valueBuilder.ToString(), // value
\r
708 true // clearAttributes
\r
712 // The reader is positioned on the first character after
\r
713 // the leading '<!'.
\r
714 private void ReadComment()
\r
719 StringBuilder valueBuilder = new StringBuilder();
\r
721 while (reader.Peek() != -1)
\r
723 int ch = reader.Read();
\r
725 if (ch == '-' && reader.Peek() == '-')
\r
729 if (reader.Peek() != '>')
\r
731 throw new Exception("comments cannot contain '--'");
\r
738 valueBuilder.Append((char)ch);
\r
742 XmlNodeType.Comment, // nodeType
\r
743 String.Empty, // name
\r
744 false, // isEmptyElement
\r
745 valueBuilder.ToString(), // value
\r
746 true // clearAttributes
\r
750 // The reader is positioned on the first character
\r
752 private string ReadName()
\r
754 if (!XmlChar.IsFirstNameChar(reader.Peek()))
\r
756 throw new Exception("a name did not start with a legal character");
\r
759 StringBuilder nameBuilder = new StringBuilder();
\r
761 nameBuilder.Append((char)reader.Read());
\r
763 while (XmlChar.IsNameChar(reader.Peek()))
\r
765 nameBuilder.Append((char)reader.Read());
\r
768 return nameBuilder.ToString();
\r
771 // Read the next character and compare it against the
\r
772 // specified character.
\r
773 private void Expect(int expected)
\r
775 int ch = reader.Read();
\r
777 if (ch != expected)
\r
779 throw new Exception(String.Format(
\r
780 "expected '{0}' ({1:X}) but found '{2}' ({3:X})",
\r
788 // Does not consume the first non-whitespace character.
\r
789 private void SkipWhitespace()
\r
791 while (XmlChar.IsWhitespace(reader.Peek()))
\r