2 // System.Xml.XmlNodeReader.cs
5 // Duncan Mak (duncan@ximian.com)
6 // Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
13 using System.Collections;
19 public class XmlNodeReader : XmlReader
25 ReadState state = ReadState.Initial;
29 bool nextIsEndElement; // used for ReadString()
32 public XmlNodeReader (XmlNode node)
35 if (node.NodeType != XmlNodeType.Document
36 && node.NodeType != XmlNodeType.DocumentFragment)
44 public override int AttributeCount {
49 return ((ICollection) current.Attributes).Count;
53 public override string BaseURI {
57 return current.BaseURI;
61 [MonoTODO("wait for XML resolver")]
62 public override bool CanResolveEntity {
64 throw new NotImplementedException ();
68 public override int Depth {
72 public override bool EOF {
74 return this.ReadState == ReadState.EndOfFile
75 || this.ReadState == ReadState.Error;
79 public override bool HasAttributes {
84 if (current.Attributes == null)
91 public override bool HasValue {
96 if (current.NodeType == XmlNodeType.Element ||
97 current.NodeType == XmlNodeType.EntityReference ||
98 current.NodeType == XmlNodeType.Document ||
99 current.NodeType == XmlNodeType.DocumentFragment ||
100 current.NodeType == XmlNodeType.Notation ||
101 current.NodeType == XmlNodeType.EndElement ||
102 current.NodeType == XmlNodeType.EndEntity)
110 [MonoTODO("waiting for DTD implementation")]
111 public override bool IsDefault {
116 if (current.NodeType != XmlNodeType.Attribute)
120 return ((XmlAttribute) current).isDefault;
125 [MonoTODO("test it.")]
126 public override bool IsEmptyElement {
131 if(current.NodeType == XmlNodeType.Element)
132 return ((XmlElement) current).IsEmpty;
138 public override string this [int i] {
143 if (i < 0 || i > AttributeCount)
144 throw new ArgumentOutOfRangeException ("i is out of range.");
146 return current.Attributes [i].Value;
150 public override string this [string name] {
155 string ret = current.Attributes [name].Value;
164 public override string this [string name, string namespaceURI] {
169 string ret = current.Attributes [name, namespaceURI].Value;
178 public override string LocalName {
183 if (current is XmlCharacterData)
186 return current.LocalName;
190 public override string Name {
199 public override string NamespaceURI {
204 return current.NamespaceURI;
208 public override XmlNameTable NameTable {
211 current.NodeType == XmlNodeType.Document ?
212 current as XmlDocument : current.OwnerDocument;
213 return doc.NameTable;
217 public override XmlNodeType NodeType {
220 return XmlNodeType.None;
222 return isEndElement ? XmlNodeType.EndElement : current.NodeType;
226 public override string Prefix {
231 return current.Prefix;
235 public override char QuoteChar {
239 public override ReadState ReadState {
240 get { return state; }
243 public override string Value {
245 return HasValue ? current.Value : String.Empty;
249 public override string XmlLang {
254 return current.XmlLang;
258 public override XmlSpace XmlSpace {
261 return XmlSpace.None;
263 return current.XmlSpace;
270 public override void Close ()
273 state = ReadState.Closed;
276 public override string GetAttribute (int attributeIndex)
278 return this [attributeIndex];
281 public override string GetAttribute (string name)
286 public override string GetAttribute (string name, string namespaceURI)
288 return this [name, namespaceURI];
291 // FIXME: Its performance is not good.
292 public override string LookupNamespace (string prefix)
294 XmlNamespaceManager nsmgr = current.ConstructNamespaceManager();
295 return nsmgr.LookupNamespace (prefix);
298 public override void MoveToAttribute (int attributeIndex)
300 if (attributeIndex < 0 || attributeIndex > AttributeCount)
301 throw new ArgumentOutOfRangeException ();
303 state = ReadState.Interactive;
304 current = current.Attributes [attributeIndex];
307 public override bool MoveToAttribute (string name)
309 if (GetAttribute (name) == null)
312 current = current.Attributes [name];
317 public override bool MoveToAttribute (string name, string namespaceURI)
319 if (GetAttribute (name, namespaceURI) == null)
322 current = current.Attributes [name, namespaceURI];
327 private void MoveToEndElement ()
331 current = current.ParentNode;
334 public override bool MoveToElement ()
338 if (current.NodeType == XmlNodeType.Attribute) {
339 current = ((XmlAttribute) current).OwnerElement;
345 public override bool MoveToFirstAttribute ()
347 if(current.Attributes.Count > 0)
349 current = current.Attributes [0];
356 public override bool MoveToNextAttribute ()
358 if (current.NodeType != XmlNodeType.Attribute)
359 return MoveToFirstAttribute ();
362 XmlAttributeCollection ac = ((XmlAttribute) current).OwnerElement.Attributes;
363 for (int i=0; i<ac.Count-1; i++)
365 XmlAttribute attr = ac [i];
376 private bool MoveToNextSibling ()
378 if (nextIsEndElement) {
379 // nextIsEndElement is set only by ReadString.
380 nextIsEndElement = false;
382 } else if (alreadyRead) {
384 return current != null;
386 if (current.NextSibling != null) {
387 isEndElement = false;
388 current = current.NextSibling;
392 return current != null;
395 [MonoTODO("Entity handling is not supported.")]
396 public override bool Read ()
401 if (ReadState == ReadState.Initial) {
403 state = ReadState.Interactive;
404 // when startNode is document or fragment
406 current = startNode.FirstChild;
409 if (current == null) {
410 state = ReadState.Error;
420 // Then go up and move to next.
421 // If no more nodes, then set EOF.
422 isEndElement = false;
423 if (current.ParentNode == null
424 || current.ParentNode.NodeType == XmlNodeType.Document
425 || current.ParentNode.NodeType == XmlNodeType.DocumentFragment) {
427 state = ReadState.EndOfFile;
429 } else if (current.NextSibling == null) {
431 current = current.ParentNode;
435 current = current.NextSibling;
439 } else if (nextIsEndElement) {
440 // nextIsEndElement is set only by ReadString.
441 nextIsEndElement = false;
443 return current != null;
445 } else if (alreadyRead) {
447 return current != null;
450 // hmm... here may be unnecessary codes. plz check anyone ;)
451 if (!isEndElement && current.FirstChild != null) {
452 isEndElement = false;
453 current = current.FirstChild;
455 } else if (depth == 0) {
456 state = ReadState.EndOfFile;
459 MoveToNextSibling ();
461 return current != null;
464 public override bool ReadAttributeValue ()
466 if (current.NodeType == XmlNodeType.Attribute) {
467 current = current.FirstChild;
468 return current != null;
469 } else if (current.ParentNode.NodeType == XmlNodeType.Attribute) {
470 current = current.NextSibling;
471 return current != null;
476 [MonoTODO("Need to move to next content.")]
477 // Its traversal behavior is almost same as Read().
478 public override string ReadInnerXml ()
480 if (ReadState == ReadState.Initial) {
481 state = ReadState.Error;
482 return String.Empty; // heh
485 if (current.NodeType != XmlNodeType.Attribute &&
486 current.NodeType != XmlNodeType.Element)
489 return current.InnerXml;
492 [MonoTODO("Need to move to next content.")]
493 // Its traversal behavior is almost same as Read().
494 public override string ReadOuterXml ()
496 if (NodeType == XmlNodeType.EndElement)
499 if (current.NodeType != XmlNodeType.Attribute &&
500 current.NodeType != XmlNodeType.Element)
503 return current.OuterXml;
506 public override string ReadString ()
508 if (NodeType == XmlNodeType.EndElement)
511 XmlNode original = current;
512 StringBuilder builder = new StringBuilder();
513 if (NodeType == XmlNodeType.Element) {
514 foreach (XmlNode child in current.ChildNodes) {
515 if (child is XmlCharacterData && !(child is XmlComment))
516 builder.Append (child.Value);
524 if (current == original) {
525 nextIsEndElement = true;
530 builder.Append (current.Value);
531 if (current.NextSibling == null) {
532 nextIsEndElement = true;
534 } else if (current.NextSibling.NodeType == XmlNodeType.Comment)
537 current = current.NextSibling;
540 if (current.NextSibling == null) {
541 nextIsEndElement = true;
545 return builder.ToString ();
549 public override void ResolveEntity ()
551 throw new NotImplementedException ();
552 // if (current.NodeType != XmlNodeType.EntityReference)
553 // throw new InvalidOperationException ("The current node is not an Entity Reference");
556 [MonoTODO("test it.")]
557 public override void Skip ()
560 if(current.ChildNodes.Count > 0)
561 MoveToNextSibling ();