5 // Kral Ferch <kral_ferch@hotmail.com>
11 using System.Collections;
14 using System.Xml.XPath;
18 public abstract class XmlNode : ICloneable, IEnumerable, IXPathNavigable
22 XmlDocument ownerDocument;
29 internal XmlNode (XmlDocument ownerDocument)
31 this.ownerDocument = ownerDocument;
38 public virtual XmlAttributeCollection Attributes
43 public virtual string BaseURI
45 get { return ParentNode.BaseURI; }
48 public virtual XmlNodeList ChildNodes {
50 return new XmlNodeListChildren(this);
54 public virtual XmlNode FirstChild {
56 if (LastChild != null) {
57 return LastLinkedChild.NextLinkedSibling;
65 public virtual bool HasChildNodes {
66 get { return LastChild != null; }
70 public virtual string InnerText {
72 StringBuilder builder = new StringBuilder ();
73 AppendChildValues (this, builder);
74 return builder.ToString ();
77 set { throw new NotImplementedException (); }
80 private void AppendChildValues (XmlNode parent, StringBuilder builder)
82 XmlNode node = parent.FirstChild;
84 while (node != null) {
85 if (node.NodeType == XmlNodeType.Text)
86 builder.Append (node.Value);
87 AppendChildValues (node, builder);
88 node = node.NextSibling;
93 public virtual string InnerXml {
95 StringWriter sw = new StringWriter ();
96 XmlTextWriter xtw = new XmlTextWriter (sw);
100 return sw.GetStringBuilder().ToString();
103 set { throw new NotImplementedException (); }
106 public virtual bool IsReadOnly {
107 get { return false; }
110 [System.Runtime.CompilerServices.IndexerName("Item")]
111 public virtual XmlElement this [string name] {
113 foreach (XmlNode node in ChildNodes) {
114 if ((node.NodeType == XmlNodeType.Element) &&
115 (node.Name == name)) {
116 return (XmlElement) node;
124 [System.Runtime.CompilerServices.IndexerName("Item")]
125 public virtual XmlElement this [string localname, string ns] {
127 foreach (XmlNode node in ChildNodes) {
128 if ((node.NodeType == XmlNodeType.Element) &&
129 (node.LocalName == localname) &&
130 (node.NamespaceURI == ns)) {
131 return (XmlElement) node;
139 public virtual XmlNode LastChild {
140 get { return LastLinkedChild; }
143 internal virtual XmlLinkedNode LastLinkedChild {
148 public abstract string LocalName { get; }
150 public abstract string Name { get; }
152 public virtual string NamespaceURI {
153 get { return String.Empty; }
156 public virtual XmlNode NextSibling {
160 public abstract XmlNodeType NodeType { get; }
162 public virtual string OuterXml {
164 StringWriter sw = new StringWriter ();
165 XmlTextWriter xtw = new XmlTextWriter (sw);
169 return sw.GetStringBuilder().ToString();
173 public virtual XmlDocument OwnerDocument {
174 get { return ownerDocument; }
177 public virtual XmlNode ParentNode {
178 get { return parentNode; }
181 public virtual string Prefix {
182 get { return String.Empty; }
186 public virtual XmlNode PreviousSibling {
190 public virtual string Value {
192 set { throw new InvalidOperationException ("This node does not have a value"); }
199 public virtual XmlNode AppendChild (XmlNode newChild)
201 XmlDocument ownerDoc = (NodeType == XmlNodeType.Document) ? (XmlDocument)this : OwnerDocument;
203 ownerDoc.onNodeInserting (newChild, this);
205 if (NodeType == XmlNodeType.Document || NodeType == XmlNodeType.Element || NodeType == XmlNodeType.Attribute) {
207 if (newChild.OwnerDocument != ownerDoc)
208 throw new ArgumentException ("Can't append a node created by another document.");
210 XmlLinkedNode newLinkedChild = (XmlLinkedNode) newChild;
211 XmlLinkedNode lastLinkedChild = LastLinkedChild;
213 newLinkedChild.parentNode = this;
215 if (lastLinkedChild != null) {
216 newLinkedChild.NextLinkedSibling = lastLinkedChild.NextLinkedSibling;
217 lastLinkedChild.NextLinkedSibling = newLinkedChild;
219 newLinkedChild.NextLinkedSibling = newLinkedChild;
221 LastLinkedChild = newLinkedChild;
223 ownerDoc.onNodeInserted (newChild, newChild.ParentNode);
227 throw new InvalidOperationException();
231 public virtual XmlNode Clone ()
233 throw new NotImplementedException ();
236 public abstract XmlNode CloneNode (bool deep);
239 public XPathNavigator CreateNavigator ()
241 return new XmlDocumentNavigator(this);
244 public IEnumerator GetEnumerator ()
246 return new XmlNodeListChildren(this).GetEnumerator();
250 public virtual string GetNamespaceOfPrefix (string prefix)
252 throw new NotImplementedException ();
256 public virtual string GetPrefixOfNamespace (string namespaceURI)
258 throw new NotImplementedException ();
261 object ICloneable.Clone ()
266 IEnumerator IEnumerable.GetEnumerator ()
268 return GetEnumerator ();
272 public virtual XmlNode InsertAfter (XmlNode newChild, XmlNode refChild)
274 throw new NotImplementedException ();
278 public virtual XmlNode InsertBefore (XmlNode newChild, XmlNode refChild)
280 throw new NotImplementedException ();
284 public virtual void Normalize ()
286 throw new NotImplementedException ();
290 public virtual XmlNode PrependChild (XmlNode newChild)
292 throw new NotImplementedException ();
295 public virtual void RemoveAll ()
297 XmlDocument ownerDoc = (NodeType == XmlNodeType.Document) ? (XmlDocument)this : OwnerDocument;
299 ownerDoc.onNodeRemoving (this, this.ParentNode);
300 LastLinkedChild = null;
301 ownerDoc.onNodeRemoved (this, this.ParentNode);
304 public virtual XmlNode RemoveChild (XmlNode oldChild)
306 OwnerDocument.onNodeRemoving (oldChild, oldChild.ParentNode);
308 if (NodeType == XmlNodeType.Document || NodeType == XmlNodeType.Element || NodeType == XmlNodeType.Attribute)
311 throw new ArgumentException();
313 if (Object.ReferenceEquals(LastLinkedChild, LastLinkedChild.NextLinkedSibling) && Object.ReferenceEquals(LastLinkedChild, oldChild))
314 LastLinkedChild = null;
316 XmlLinkedNode oldLinkedChild = (XmlLinkedNode)oldChild;
317 XmlLinkedNode beforeLinkedChild = LastLinkedChild;
319 while (!Object.ReferenceEquals(beforeLinkedChild.NextLinkedSibling, LastLinkedChild) && !Object.ReferenceEquals(beforeLinkedChild.NextLinkedSibling, oldLinkedChild))
320 beforeLinkedChild = beforeLinkedChild.NextLinkedSibling;
322 if (!Object.ReferenceEquals(beforeLinkedChild.NextLinkedSibling, oldLinkedChild))
323 throw new ArgumentException();
325 beforeLinkedChild.NextLinkedSibling = oldLinkedChild.NextLinkedSibling;
326 oldLinkedChild.NextLinkedSibling = null;
329 OwnerDocument.onNodeRemoved (oldChild, oldChild.ParentNode);
334 throw new ArgumentException();
338 public virtual XmlNode ReplaceChild (XmlNode newChild, XmlNode oldChild)
340 throw new NotImplementedException ();
343 public XmlNodeList SelectNodes (string xpath)
345 return SelectNodes (xpath, null);
349 public XmlNodeList SelectNodes (string xpath, XmlNamespaceManager nsmgr)
351 XPathNavigator nav = CreateNavigator ();
352 XPathExpression expr = nav.Compile (xpath);
354 expr.SetContext (nsmgr);
355 XPathNodeIterator iter = nav.Select (expr);
356 ArrayList rgNodes = new ArrayList ();
357 while (iter.MoveNext ())
359 rgNodes.Add (((XmlDocumentNavigator) iter.Current).Node);
361 return new XmlNodeArrayList (rgNodes);
364 public XmlNode SelectSingleNode (string xpath)
366 return SelectSingleNode (xpath, null);
370 public XmlNode SelectSingleNode (string xpath, XmlNamespaceManager nsmgr)
372 XPathNavigator nav = CreateNavigator ();
373 XPathExpression expr = nav.Compile (xpath);
375 expr.SetContext (nsmgr);
376 XPathNodeIterator iter = nav.Select (expr);
377 if (!iter.MoveNext ())
379 return ((XmlDocumentNavigator) iter.Current).Node;
382 internal void SetParentNode (XmlNode parent)
388 public virtual bool Supports (string feature, string version)
390 throw new NotImplementedException ();
393 public abstract void WriteContentTo (XmlWriter w);
395 public abstract void WriteTo (XmlWriter w);
397 // It parses with XmlReader and then construct DOM of the parsed contents.
398 internal protected void ConstructDOM(XmlReader xmlReader, XmlNode currentNode)
400 // I am not confident whether this method should be placed in this class or not...
401 // Please verify its validity and then erase this comment;-)
403 XmlDocument doc = currentNode is XmlDocument ? (XmlDocument)currentNode : currentNode.OwnerDocument;
404 // Below are 'almost' copied from XmlDocument.Load(XmlReader xmlReader)
405 while (xmlReader.Read ())
407 switch (xmlReader.NodeType)
\r
410 case XmlNodeType.CDATA:
411 newNode = doc.CreateCDataSection(xmlReader.Value);
412 currentNode.AppendChild (newNode);
415 case XmlNodeType.Comment:
416 newNode = doc.CreateComment (xmlReader.Value);
417 currentNode.AppendChild (newNode);
420 case XmlNodeType.Element:
421 XmlElement element = doc.CreateElement (xmlReader.Prefix, xmlReader.LocalName, xmlReader.NamespaceURI);
422 currentNode.AppendChild (element);
424 // set the element's attributes.
425 while (xmlReader.MoveToNextAttribute ())
\r
427 XmlAttribute attribute = doc.CreateAttribute (xmlReader.Prefix, xmlReader.LocalName, xmlReader.NamespaceURI);
428 attribute.Value = xmlReader.Value;
429 element.SetAttributeNode (attribute);
432 xmlReader.MoveToElement ();
434 // if this element isn't empty, push it onto our "stack".
435 if (!xmlReader.IsEmptyElement)
436 currentNode = element;
440 case XmlNodeType.EndElement:
441 currentNode = currentNode.ParentNode;
444 case XmlNodeType.ProcessingInstruction:
445 newNode = doc.CreateProcessingInstruction (xmlReader.Name, xmlReader.Value);
446 currentNode.AppendChild (newNode);
449 case XmlNodeType.Text:
450 newNode = doc.CreateTextNode (xmlReader.Value);
451 currentNode.AppendChild (newNode);
454 case XmlNodeType.XmlDeclaration:
\r
455 // String Empties are dummy, then gives over setting value contents to setter.
\r
456 newNode = doc.CreateNode(XmlNodeType.XmlDeclaration, String.Empty, String.Empty);
\r
457 ((XmlDeclaration)newNode).Value = xmlReader.Value;
\r
458 this.AppendChild(newNode);
\r
464 // It parses this and all the ancestor elements,
465 // find 'xmlns' declarations, stores and then return them.
467 internal protected XmlNamespaceManager ConstructNamespaceManager()
469 XmlDocument doc = this is XmlDocument ? (XmlDocument)this : this.OwnerDocument;
470 XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
471 XmlElement el = null;
472 switch(this.NodeType)
474 case XmlNodeType.Attribute:
475 el = ((XmlAttribute)this).OwnerElement;
477 case XmlNodeType.Element:
478 el = this as XmlElement;
481 el = this.ParentNode as XmlElement;
487 foreach(XmlAttribute attr in el.Attributes)
489 if(attr.Prefix == "xmlns")
491 if(nsmgr.LookupNamespace(attr.LocalName) == null )
493 nsmgr.AddNamespace(attr.LocalName, attr.Value);
497 // When reached to document, then it will set null value :)
498 el = el.ParentNode as XmlElement;