2002-08-25 Tim Coleman <tim@timcoleman.com>
[mono.git] / mcs / class / System.XML / System.Xml / XmlNode.cs
1 //
2 // System.Xml.XmlNode
3 //
4 // Author:
5 //   Kral Ferch <kral_ferch@hotmail.com>
6 //
7 // (C) 2002 Kral Ferch
8 //
9
10 using System;
11 using System.Collections;
12 using System.IO;
13 using System.Text;
14 using System.Xml.XPath;
15
16 namespace System.Xml
17 {
18         public abstract class XmlNode : ICloneable, IEnumerable, IXPathNavigable
19         {
20                 #region Fields
21
22                 XmlDocument ownerDocument;
23                 XmlNode parentNode;
24
25                 #endregion
26
27                 #region Constructors
28
29                 internal XmlNode (XmlDocument ownerDocument)
30                 {
31                         this.ownerDocument = ownerDocument;
32                 }
33
34                 #endregion
35
36                 #region Properties
37
38                 public virtual XmlAttributeCollection Attributes
39                 {
40                         get { return null; }
41                 }
42
43                 public virtual string BaseURI
44                 {
45                         get { return ParentNode.BaseURI; }
46                 }
47
48                 public virtual XmlNodeList ChildNodes {
49                         get {
50                                 return new XmlNodeListChildren(this);
51                         }
52                 }
53
54                 public virtual XmlNode FirstChild {
55                         get {
56                                 if (LastChild != null) {
57                                         return LastLinkedChild.NextLinkedSibling;
58                                 }
59                                 else {
60                                         return null;
61                                 }
62                         }
63                 }
64
65                 public virtual bool HasChildNodes {
66                         get { return LastChild != null; }
67                 }
68
69                 [MonoTODO]
70                 public virtual string InnerText {
71                         get {
72                                 StringBuilder builder = new StringBuilder ();
73                                 AppendChildValues (this, builder);
74                                 return builder.ToString ();
75                         }
76
77                         set { throw new NotImplementedException (); }
78                 }
79
80                 private void AppendChildValues(XmlNode parent, StringBuilder builder)
81                 {
82                         XmlNode node = parent.FirstChild;
83
84                         while (node != null) {
85                                 builder.Append (node.Value);
86                                 AppendChildValues (node, builder);
87                                 node = node.NextSibling;
88                         }
89                 }
90
91                 [MonoTODO("Setter.")]
92                 public virtual string InnerXml {
93                         get {
94                                 StringWriter sw = new StringWriter ();
95                                 XmlTextWriter xtw = new XmlTextWriter (sw);
96
97                                 WriteContentTo(xtw);
98
99                                 return sw.GetStringBuilder().ToString();
100                         }
101
102                         set { throw new NotImplementedException (); }
103                 }
104
105                 public virtual bool IsReadOnly {
106                         get { return false; }
107                 }
108
109                 [System.Runtime.CompilerServices.IndexerName("Item")]
110                 public virtual XmlElement this [string name] {
111                         get { 
112                                 foreach (XmlNode node in ChildNodes) {
113                                         if ((node.NodeType == XmlNodeType.Element) &&
114                                             (node.Name == name)) {
115                                                 return (XmlElement) node;
116                                         }
117                                 }
118
119                                 return null;
120                         }
121                 }
122
123                 [System.Runtime.CompilerServices.IndexerName("Item")]
124                 public virtual XmlElement this [string localname, string ns] {
125                         get { 
126                                 foreach (XmlNode node in ChildNodes) {
127                                         if ((node.NodeType == XmlNodeType.Element) &&
128                                             (node.LocalName == localname) && 
129                                             (node.NamespaceURI == ns)) {
130                                                 return (XmlElement) node;
131                                         }
132                                 }
133
134                                 return null;
135                         }
136                 }
137
138                 public virtual XmlNode LastChild {
139                         get { return LastLinkedChild; }
140                 }
141
142                 internal virtual XmlLinkedNode LastLinkedChild {
143                         get { return null; }
144                         set { }
145                 }
146
147                 public abstract string LocalName { get; }
148
149                 public abstract string Name     { get; }
150
151                 public virtual string NamespaceURI {
152                         get { return String.Empty; }
153                 }
154
155                 public virtual XmlNode NextSibling {
156                         get { return null; }
157                 }
158
159                 public abstract XmlNodeType NodeType { get;     }
160
161                 public virtual string OuterXml {
162                         get {
163                                 StringWriter sw = new StringWriter ();
164                                 XmlTextWriter xtw = new XmlTextWriter (sw);
165
166                                 WriteTo(xtw);
167
168                                 return sw.GetStringBuilder().ToString();
169                         }
170                 }
171
172                 public virtual XmlDocument OwnerDocument {
173                         get { return ownerDocument; }
174                 }
175
176                 public virtual XmlNode ParentNode {
177                         get { return parentNode; }
178                 }
179
180                 public virtual string Prefix {
181                         get { return String.Empty; }
182                         set {}
183                 }
184
185                 public virtual XmlNode PreviousSibling {
186                         get { return null; }
187                 }
188
189                 public virtual string Value {
190                         get { return null; }
191                         set { throw new InvalidOperationException ("This node does not have a value"); }
192                 }
193
194                 #endregion
195
196                 #region Methods
197
198                 public virtual XmlNode AppendChild (XmlNode newChild)
199                 {
200                         XmlDocument ownerDoc = (NodeType == XmlNodeType.Document) ? (XmlDocument)this : OwnerDocument;
201
202                         ownerDoc.onNodeInserting (newChild, this);
203
204                         if (NodeType == XmlNodeType.Document || NodeType == XmlNodeType.Element || NodeType == XmlNodeType.Attribute) {
205                                 
206                                 if (newChild.OwnerDocument != ownerDoc)
207                                         throw new ArgumentException ("Can't append a node created by another document.");
208
209                                 XmlLinkedNode newLinkedChild = (XmlLinkedNode) newChild;
210                                 XmlLinkedNode lastLinkedChild = LastLinkedChild;
211
212                                 newLinkedChild.parentNode = this;
213                                 
214                                 if (lastLinkedChild != null) {
215                                         newLinkedChild.NextLinkedSibling = lastLinkedChild.NextLinkedSibling;
216                                         lastLinkedChild.NextLinkedSibling = newLinkedChild;
217                                 } else
218                                         newLinkedChild.NextLinkedSibling = newLinkedChild;
219                                 
220                                 LastLinkedChild = newLinkedChild;
221
222                                 ownerDoc.onNodeInserted (newChild, newChild.ParentNode);
223
224                                 return newChild;
225                         } else
226                                 throw new InvalidOperationException();
227                 }
228
229                 [MonoTODO]
230                 public virtual XmlNode Clone ()
231                 {
232                         throw new NotImplementedException ();
233                 }
234
235                 public abstract XmlNode CloneNode (bool deep);
236
237                 [MonoTODO]
238                 public XPathNavigator CreateNavigator ()
239                 {
240                         return new XmlDocumentNavigator(this);
241                 }
242
243                 public IEnumerator GetEnumerator ()
244                 {
245                         return new XmlNodeListChildren(this).GetEnumerator();
246                 }
247
248                 [MonoTODO]
249                 public virtual string GetNamespaceOfPrefix (string prefix)
250                 {
251                         throw new NotImplementedException ();
252                 }
253
254                 [MonoTODO]
255                 public virtual string GetPrefixOfNamespace (string namespaceURI)
256                 {
257                         throw new NotImplementedException ();
258                 }
259
260                 object ICloneable.Clone ()
261                 {
262                         return Clone ();
263                 }
264
265                 IEnumerator IEnumerable.GetEnumerator ()
266                 {
267                         return GetEnumerator ();
268                 }
269
270                 [MonoTODO]
271                 public virtual XmlNode InsertAfter (XmlNode newChild, XmlNode refChild)
272                 {
273                         throw new NotImplementedException ();
274                 }
275
276                 [MonoTODO]
277                 public virtual XmlNode InsertBefore (XmlNode newChild, XmlNode refChild)
278                 {
279                         throw new NotImplementedException ();
280                 }
281
282                 [MonoTODO]
283                 public virtual void Normalize ()
284                 {
285                         throw new NotImplementedException ();
286                 }
287
288                 [MonoTODO]
289                 public virtual XmlNode PrependChild (XmlNode newChild)
290                 {
291                         throw new NotImplementedException ();
292                 }
293
294                 public virtual void RemoveAll ()
295                 {
296                         XmlDocument ownerDoc = (NodeType == XmlNodeType.Document) ? (XmlDocument)this : OwnerDocument;
297
298                         ownerDoc.onNodeRemoving (this, this.ParentNode);
299                         LastLinkedChild = null;
300                         ownerDoc.onNodeRemoved (this, this.ParentNode);
301                 }
302
303                 public virtual XmlNode RemoveChild (XmlNode oldChild)
304                 {
305                         OwnerDocument.onNodeRemoving (oldChild, oldChild.ParentNode);
306
307                         if (NodeType == XmlNodeType.Document || NodeType == XmlNodeType.Element || NodeType == XmlNodeType.Attribute) 
308                         {
309                                 if (IsReadOnly)
310                                         throw new ArgumentException();
311
312                                 if (Object.ReferenceEquals(LastLinkedChild, LastLinkedChild.NextLinkedSibling) && Object.ReferenceEquals(LastLinkedChild, oldChild))
313                                         LastLinkedChild = null;
314                                 else {
315                                         XmlLinkedNode oldLinkedChild = (XmlLinkedNode)oldChild;
316                                         XmlLinkedNode beforeLinkedChild = LastLinkedChild;
317                                         
318                                         while (!Object.ReferenceEquals(beforeLinkedChild.NextLinkedSibling, LastLinkedChild) && !Object.ReferenceEquals(beforeLinkedChild.NextLinkedSibling, oldLinkedChild))
319                                                 beforeLinkedChild = beforeLinkedChild.NextLinkedSibling;
320
321                                         if (!Object.ReferenceEquals(beforeLinkedChild.NextLinkedSibling, oldLinkedChild))
322                                                 throw new ArgumentException();
323
324                                         beforeLinkedChild.NextLinkedSibling = oldLinkedChild.NextLinkedSibling;
325                                         oldLinkedChild.NextLinkedSibling = null;
326                                  }
327
328                                 OwnerDocument.onNodeRemoved (oldChild, oldChild.ParentNode);
329
330                                 return oldChild;
331                         } 
332                         else
333                                 throw new ArgumentException();
334                 }
335
336                 [MonoTODO]
337                 public virtual XmlNode ReplaceChild (XmlNode newChild, XmlNode oldChild)
338                 {
339                         throw new NotImplementedException ();
340                 }
341
342                 public XmlNodeList SelectNodes (string xpath)
343                 {
344                         return SelectNodes (xpath, null);
345                 }
346
347                 [MonoTODO]
348                 public XmlNodeList SelectNodes (string xpath, XmlNamespaceManager nsmgr)
349                 {
350                         XPathNavigator nav = CreateNavigator ();
351                         XPathExpression expr = nav.Compile (xpath);
352                         if (nsmgr != null)
353                                 expr.SetContext (nsmgr);
354                         XPathNodeIterator iter = nav.Select (expr);
355                         ArrayList rgNodes = new ArrayList ();
356                         while (iter.MoveNext ())
357                         {
358                                 rgNodes.Add (((XmlDocumentNavigator) iter.Current).Node);
359                         }
360                         return new XmlNodeArrayList (rgNodes);
361                 }
362
363                 public XmlNode SelectSingleNode (string xpath)
364                 {
365                         return SelectSingleNode (xpath, null);
366                 }
367
368                 [MonoTODO]
369                 public XmlNode SelectSingleNode (string xpath, XmlNamespaceManager nsmgr)
370                 {
371                         XPathNavigator nav = CreateNavigator ();
372                         XPathExpression expr = nav.Compile (xpath);
373                         if (nsmgr != null)
374                                 expr.SetContext (nsmgr);
375                         XPathNodeIterator iter = nav.Select (expr);
376                         if (!iter.MoveNext ())
377                                 return null;
378                         return ((XmlDocumentNavigator) iter.Current).Node;
379                 }
380
381                 internal void SetParentNode (XmlNode parent)
382                 {
383                         parentNode = parent;
384                 }
385
386                 [MonoTODO]
387                 public virtual bool Supports (string feature, string version)
388                 {
389                         throw new NotImplementedException ();
390                 }
391
392                 public abstract void WriteContentTo (XmlWriter w);
393
394                 public abstract void WriteTo (XmlWriter w);
395
396                 #endregion
397         }
398 }