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
24 ReadState state = ReadState.Initial;
28 bool nextIsEndElement; // used for ReadString()
30 StringBuilder valueBuilder = new StringBuilder ();
31 XmlNamespaceManager defaultNsmgr;
33 private XmlNode ownerElement {
35 return (current.NodeType == XmlNodeType.Attribute) ? ((XmlAttribute)current).OwnerElement : current;
41 public XmlNodeReader (XmlNode node)
44 document = startNode.NodeType == XmlNodeType.Document ?
45 startNode as XmlDocument : startNode.OwnerDocument;
47 if (node.NodeType != XmlNodeType.Document
48 && node.NodeType != XmlNodeType.DocumentFragment)
50 defaultNsmgr = new XmlNamespaceManager (this.NameTable);
58 public override int AttributeCount {
60 if (isEndElement || current == null || current.Attributes == null)
62 return ownerElement.Attributes.Count;
66 public override string BaseURI {
70 return current.BaseURI;
74 [MonoTODO("wait for XML resolver")]
75 public override bool CanResolveEntity {
77 throw new NotImplementedException ();
81 public override int Depth {
85 public override bool EOF {
87 return this.ReadState == ReadState.EndOfFile
88 || this.ReadState == ReadState.Error;
92 public override bool HasAttributes {
94 if (isEndElement || current == null)
97 if (current.Attributes == null ||
98 current.Attributes.Count == 0)
105 public override bool HasValue {
110 if (current.NodeType == XmlNodeType.Element ||
111 current.NodeType == XmlNodeType.EntityReference ||
112 current.NodeType == XmlNodeType.Document ||
113 current.NodeType == XmlNodeType.DocumentFragment ||
114 current.NodeType == XmlNodeType.Notation ||
115 current.NodeType == XmlNodeType.EndElement ||
116 current.NodeType == XmlNodeType.EndEntity)
124 [MonoTODO("waiting for DTD implementation")]
125 public override bool IsDefault {
130 if (current.NodeType != XmlNodeType.Attribute)
134 return ((XmlAttribute) current).isDefault;
139 public override bool IsEmptyElement {
144 if(current.NodeType == XmlNodeType.Element)
145 return ((XmlElement) current).IsEmpty;
151 public override string this [int i] {
153 // This is MS.NET bug which returns attributes in spite of EndElement.
154 if (isEndElement || current == null)
157 if (NodeType == XmlNodeType.XmlDeclaration) {
158 XmlDeclaration decl = current as XmlDeclaration;
163 if (decl.Encoding != String.Empty)
164 return decl.Encoding;
165 else if (decl.Standalone != String.Empty)
166 return decl.Standalone;
168 throw new ArgumentOutOfRangeException ("Index out of range.");
170 if (decl.Encoding != String.Empty && decl.Standalone != null)
171 return decl.Standalone;
173 throw new ArgumentOutOfRangeException ("Index out of range.");
177 if (i < 0 || i > AttributeCount)
178 throw new ArgumentOutOfRangeException ("Index out of range.");
180 return ownerElement.Attributes [i].Value;
184 private string GetXmlDeclarationAttribute (string name)
186 XmlDeclaration decl = current as XmlDeclaration;
191 return decl.Encoding;
193 return decl.Standalone;
198 private string GetDocumentTypeAttribute (string name)
200 XmlDocumentType doctype = current as XmlDocumentType;
203 return doctype.PublicId;
205 return doctype.SystemId;
210 public override string this [string name] {
212 // This is MS.NET bug which returns attributes in spite of EndElement.
213 if (isEndElement || current == null)
216 if (NodeType == XmlNodeType.XmlDeclaration)
217 return GetXmlDeclarationAttribute (name);
218 else if (NodeType == XmlNodeType.DocumentType)
219 return GetDocumentTypeAttribute (name);
221 XmlAttribute attr = ownerElement.Attributes [name];
229 public override string this [string name, string namespaceURI] {
231 // This is MS.NET bug which returns attributes in spite of EndElement.
232 if (isEndElement || current == null)
235 if (NodeType == XmlNodeType.XmlDeclaration)
236 return GetXmlDeclarationAttribute (name);
238 XmlAttribute attr = ownerElement.Attributes [name, namespaceURI];
240 return null; // In fact MS.NET returns null instead of String.Empty.
246 public override string LocalName {
251 switch (current.NodeType) {
252 case XmlNodeType.Attribute:
253 case XmlNodeType.DocumentType:
254 case XmlNodeType.Element:
255 case XmlNodeType.EntityReference:
256 case XmlNodeType.ProcessingInstruction:
257 case XmlNodeType.XmlDeclaration:
258 return current.LocalName;
265 public override string Name {
270 switch (current.NodeType) {
271 case XmlNodeType.Attribute:
272 case XmlNodeType.DocumentType:
273 case XmlNodeType.Element:
274 case XmlNodeType.EntityReference:
275 case XmlNodeType.ProcessingInstruction:
276 case XmlNodeType.XmlDeclaration:
284 public override string NamespaceURI {
289 return current.NamespaceURI;
293 public override XmlNameTable NameTable {
294 get { return document.NameTable; }
297 public override XmlNodeType NodeType {
300 return XmlNodeType.None;
302 return isEndElement ? XmlNodeType.EndElement : current.NodeType;
306 public override string Prefix {
311 return current.Prefix;
315 public override char QuoteChar {
319 public override ReadState ReadState {
320 get { return state; }
323 public override string Value {
325 if (NodeType == XmlNodeType.DocumentType)
326 return ((XmlDocumentType) current).InternalSubset;
328 return HasValue ? current.Value : String.Empty;
332 public override string XmlLang {
337 return current.XmlLang;
341 public override XmlSpace XmlSpace {
344 return XmlSpace.None;
346 return current.XmlSpace;
353 public override void Close ()
356 state = ReadState.Closed;
359 public override string GetAttribute (int attributeIndex)
361 return this [attributeIndex];
364 public override string GetAttribute (string name)
369 public override string GetAttribute (string name, string namespaceURI)
371 return this [name, namespaceURI];
374 public override string LookupNamespace (string prefix)
379 XmlAttribute curAttr = current as XmlAttribute;
380 XmlNode target = curAttr != null ? curAttr.OwnerElement : current;
384 XmlAttribute attr = target.Attributes ["xmlns"];
387 target = target.ParentNode;
388 } while (target.NodeType != XmlNodeType.Document);
390 string name = "xmlns:" + prefix;
392 XmlAttribute attr = target.Attributes [name];
395 target = target.ParentNode;
396 } while (target.NodeType != XmlNodeType.Document);
398 return defaultNsmgr.LookupNamespace (prefix);
401 public override void MoveToAttribute (int attributeIndex)
403 if (isEndElement || attributeIndex < 0 || attributeIndex > AttributeCount)
404 throw new ArgumentOutOfRangeException ();
406 state = ReadState.Interactive;
407 current = ownerElement.Attributes [attributeIndex];
410 public override bool MoveToAttribute (string name)
412 if (isEndElement || current == null)
414 XmlNode tmpCurrent = current;
415 if (current.ParentNode.NodeType == XmlNodeType.Attribute)
416 current = current.ParentNode;
418 XmlAttribute attr = ownerElement.Attributes [name];
420 current = tmpCurrent;
429 public override bool MoveToAttribute (string name, string namespaceURI)
431 if (isEndElement || current == null)
434 XmlAttribute attr = ownerElement.Attributes [name, namespaceURI];
443 private void MoveToParentElement ()
445 // This is buggy. It is not only the case when EndElement = true.
448 current = current.ParentNode;
451 public override bool MoveToElement ()
455 if (current.NodeType == XmlNodeType.Attribute) {
456 current = ((XmlAttribute) current).OwnerElement;
462 public override bool MoveToFirstAttribute ()
467 if(ownerElement.Attributes.Count > 0)
469 current = ownerElement.Attributes [0];
476 public override bool MoveToNextAttribute ()
481 if (current.NodeType != XmlNodeType.Attribute)
482 return MoveToFirstAttribute ();
485 XmlAttributeCollection ac = ((XmlAttribute) current).OwnerElement.Attributes;
486 for (int i=0; i<ac.Count-1; i++)
488 XmlAttribute attr = ac [i];
502 private bool MoveToNextSibling ()
504 if (nextIsEndElement) {
505 // nextIsEndElement is set only by ReadString.
506 nextIsEndElement = false;
507 MoveToParentElement ();
508 } else if (alreadyRead) {
510 return current != null;
512 if (current.NextSibling != null) {
513 isEndElement = false;
514 current = current.NextSibling;
516 MoveToParentElement ();
518 if (current == null) {
519 state = ReadState.EndOfFile;
526 [MonoTODO("Entity handling is not supported.")]
527 public override bool Read ()
532 if (ReadState == ReadState.Initial) {
534 state = ReadState.Interactive;
535 // when startNode is document or fragment
537 current = startNode.FirstChild;
540 if (current == null) {
541 state = ReadState.Error;
550 if (IsEmptyElement || isEndElement) {
551 // Then go up and move to next.
552 // If no more nodes, then set EOF.
553 isEndElement = false;
554 if (current.ParentNode == null
555 || current.ParentNode.NodeType == XmlNodeType.Document
556 || current.ParentNode.NodeType == XmlNodeType.DocumentFragment) {
558 state = ReadState.EndOfFile;
560 } else if (current.NextSibling == null) {
562 current = current.ParentNode;
566 current = current.NextSibling;
570 } else if (nextIsEndElement) {
571 // nextIsEndElement is set only by ReadString.
572 nextIsEndElement = false;
574 return current != null;
576 } else if (alreadyRead) {
578 return current != null;
581 if (!isEndElement && current.FirstChild != null) {
582 isEndElement = false;
583 current = current.FirstChild;
585 } else if (current.NodeType == XmlNodeType.Element) {
587 if (current.FirstChild != null)
590 MoveToNextSibling ();
592 return current != null;
595 public override bool ReadAttributeValue ()
597 if (current.NodeType == XmlNodeType.Attribute) {
598 current = current.FirstChild;
599 return current != null;
600 } else if (current.ParentNode.NodeType == XmlNodeType.Attribute) {
601 if (current.NextSibling == null)
603 current = current.NextSibling;
609 // Its traversal behavior is almost same as Read().
610 public override string ReadInnerXml ()
612 if (this.state != ReadState.Interactive)
615 XmlNode initial = current;
616 // Almost copied from XmlTextReader.
618 case XmlNodeType.Attribute:
620 case XmlNodeType.Element:
624 int startDepth = depth;
629 if (NodeType ==XmlNodeType.None)
630 throw new XmlException ("unexpected end of xml.");
631 else if (NodeType == XmlNodeType.EndElement && depth == startDepth) {
636 return initial.InnerXml;
637 case XmlNodeType.None:
645 [MonoTODO("Need to move to next content.")]
646 // Its traversal behavior is almost same as Read().
647 public override string ReadOuterXml ()
649 if (NodeType == XmlNodeType.EndElement)
651 XmlNode initial = current;
654 case XmlNodeType.Attribute:
655 return current.OuterXml;
656 case XmlNodeType.Element:
657 if (NodeType == XmlNodeType.Element && !IsEmptyElement)
661 return initial.OuterXml;
662 case XmlNodeType.None:
670 public override string ReadString ()
672 return ReadStringInternal ();
676 public override void ResolveEntity ()
678 throw new NotImplementedException ();
679 // if (current.NodeType != XmlNodeType.EntityReference)
680 // throw new InvalidOperationException ("The current node is not an Entity Reference");
683 [MonoTODO("test it.")]
684 public override void Skip ()
686 // Why is this overriden? Such skipping might raise
687 // (or ignore) unexpected validation error.