2003-02-03 Gonzalo Paniagua Javier <gonzalo@ximian.com>
[mono.git] / mcs / class / System.XML / System.Xml / XmlElement.cs
1 //
2 // System.Xml.XmlElement
3 //
4 // Author:
5 //   Jason Diamond (jason@injektilo.org)
6 //   Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
7 //
8 // (C) 2002 Jason Diamond  http://injektilo.org/
9 // (C) 2002 Atsushi Enomoto
10 //
11
12 using System;
13 using System.Collections;
14 using System.Xml.XPath;
15 using System.IO;
16 using System.Text;
17
18 namespace System.Xml
19 {
20         public class XmlElement : XmlLinkedNode
21         {
22                 #region Fields
23
24                 private XmlAttributeCollection attributes;
25                 private string localName;
26                 private string namespaceURI;
27                 private string prefix;
28                 private bool isEmpty;
29
30                 #endregion
31
32                 #region Constructor
33
34                 protected internal XmlElement (
35                         string prefix, 
36                         string localName, 
37                         string namespaceURI, 
38                         XmlDocument doc) : base (doc)
39                 {
40                         this.prefix = prefix;
41                         this.localName = localName;
42                         this.namespaceURI = namespaceURI;
43
44                         attributes = new XmlAttributeCollection (this);
45
46                         // TODO: Adds default attributes
47                         if(doc.DocumentType != null)
48                         {
49                         }
50                 }
51
52                 #endregion
53
54                 #region Properties
55
56                 public override XmlAttributeCollection Attributes {
57                         get { return attributes; }
58                 }
59
60                 public virtual bool HasAttributes {
61                         get { return attributes.Count > 0; }
62                 }
63
64                 public override string InnerText {
65                         get {
66                                 return base.InnerText;
67                         }
68                         set {
69                                 // Why its behavior (of MS FCL) is different from InnerXml...?
70                                 if (FirstChild != null && FirstChild.NodeType == XmlNodeType.Text)
71                                         FirstChild.Value = value;
72                                 else {
73                                         if(FirstChild != null) {
74                                                 foreach (XmlNode n in ChildNodes)
75                                                         this.RemoveChild (n);
76                                         }
77                                         // creates new Text node
78                                         AppendChild(OwnerDocument.CreateTextNode(value));
79                                 }
80                         }
81                 }
82
83                 public override string InnerXml {
84                         get {
85                                 return base.InnerXml;
86                         }
87                         set {
88                                 foreach(XmlNode n in ChildNodes)
89                                         this.RemoveChild(n);
90
91                                 // I hope there are any well-performance logic...
92                                 XmlNameTable nt = this.OwnerDocument.NameTable;
93                                 XmlNamespaceManager nsmgr = this.ConstructNamespaceManager ();
94                                 XmlParserContext ctx = new XmlParserContext (nt, nsmgr, XmlLang, this.XmlSpace);
95                                 XmlTextReader xmlReader = OwnerDocument.ReusableReader;
96                                 xmlReader.SetReaderContext (String.Empty, ctx);
97                                 xmlReader.SetReaderFragment (new StringReader (value), XmlNodeType.Element);
98
99                                 do {
100                                         XmlNode n = OwnerDocument.ReadNode (xmlReader);
101                                         if(n == null) break;
102                                         AppendChild (n);
103                                 } while (true);
104                         }
105                 }
106
107                 public bool IsEmpty {
108                         get { return isEmpty; }
109
110                         set {
111                                 if(value)
112                                         RemoveAll();
113                                 isEmpty = value;
114                         }
115                 }
116
117                 public override string LocalName {
118                         get { return localName; }
119                 }
120
121                 public override string Name {
122                         get { 
123                                 return prefix != String.Empty ? prefix + ":" + localName : localName; 
124                         }
125                 }
126
127                 public override string NamespaceURI {
128                         get { return namespaceURI; }
129                 }
130
131                 [MonoTODO]
132                 public override XmlNode NextSibling {
133                         get { 
134                                 return base.NextSibling; 
135                         }
136                 }
137
138                 public override XmlNodeType NodeType {
139                         get { 
140                                 return XmlNodeType.Element; 
141                         }
142                 }
143
144                 internal override XPathNodeType XPathNodeType {
145                         get {
146                                 return XPathNodeType.Element;
147                         }
148                 }
149
150                 [MonoTODO]
151                 public override XmlDocument OwnerDocument {
152                         get { 
153                                 return base.OwnerDocument; 
154                         }
155                 }
156
157                 public override string Prefix {
158                         get { return prefix; }
159                         set { prefix = value; }
160                 }
161
162                 #endregion
163
164                 #region Methods
165                 
166                 [MonoTODO]
167                 public override XmlNode CloneNode (bool deep)
168                 {
169                         XmlNode node =  new XmlElement (prefix, localName, namespaceURI,
170                                                         OwnerDocument);
171
172                         for (int i = 0; i < node.Attributes.Count; i++)
173                                 node.AppendChild (node.Attributes [i].CloneNode (false));
174                         
175                         if (deep) {
176                                 while ((node != null) && (node.HasChildNodes)) {                                        
177                                         AppendChild (node.NextSibling.CloneNode (true));
178                                         node = node.NextSibling;
179                                 }
180                         } // shallow cloning
181                                 
182                         //
183                         // Reminder: Also look into Default attributes.
184                         //
185                         return node;
186                 }
187
188                 [MonoTODO]
189                 public virtual string GetAttribute (string name)
190                 {
191                         XmlNode attributeNode = Attributes.GetNamedItem (name);
192                         return attributeNode != null ? attributeNode.Value : String.Empty;
193                 }
194
195                 [MonoTODO]
196                 public virtual string GetAttribute (string localName, string namespaceURI)
197                 {
198                         XmlNode attributeNode = Attributes.GetNamedItem (localName, namespaceURI);
199                         return attributeNode != null ? attributeNode.Value : String.Empty;
200                 }
201
202                 [MonoTODO]
203                 public virtual XmlAttribute GetAttributeNode (string name)
204                 {
205                         XmlNode attributeNode = Attributes.GetNamedItem (name);
206                         return attributeNode != null ? attributeNode as XmlAttribute : null;
207                 }
208
209                 [MonoTODO]
210                 public virtual XmlAttribute GetAttributeNode (string localName, string namespaceURI)
211                 {
212                         XmlNode attributeNode = Attributes.GetNamedItem (localName, namespaceURI);
213                         return attributeNode != null ? attributeNode as XmlAttribute : null;
214                 }
215
216                 public virtual XmlNodeList GetElementsByTagName (string name)
217                 {
218                         ArrayList nodeArrayList = new ArrayList ();
219                         this.searchNodesRecursively (this, name, nodeArrayList);
220                         return new XmlNodeArrayList (nodeArrayList);
221                 }
222
223                 private void searchNodesRecursively (XmlNode argNode, string argName, 
224                         ArrayList argArrayList)
225                 {
226                         XmlNodeList xmlNodeList = argNode.ChildNodes;
227                         foreach (XmlNode node in xmlNodeList){
228                                 if (node.Name.Equals (argName))
229                                         argArrayList.Add (node);
230                                 else    
231                                         this.searchNodesRecursively (node, argName, argArrayList);
232                         }
233                 }
234
235                 private void searchNodesRecursively (XmlNode argNode, string argName, string argNamespaceURI, 
236                         ArrayList argArrayList)
237                 {
238                         XmlNodeList xmlNodeList = argNode.ChildNodes;
239                         foreach (XmlNode node in xmlNodeList)
240                         {
241                                 if (node.LocalName.Equals (argName) && node.NamespaceURI.Equals (argNamespaceURI))
242                                         argArrayList.Add (node);
243                                 else    
244                                         this.searchNodesRecursively (node, argName, argNamespaceURI, argArrayList);
245                         }
246                 }
247
248                 public virtual XmlNodeList GetElementsByTagName (string localName, string namespaceURI)
249                 {
250                         ArrayList nodeArrayList = new ArrayList ();
251                         this.searchNodesRecursively (this, localName, namespaceURI, nodeArrayList);
252                         return new XmlNodeArrayList (nodeArrayList);
253                 }
254
255                 [MonoTODO]
256                 public virtual bool HasAttribute (string name)
257                 {
258                         XmlNode attributeNode = Attributes.GetNamedItem (name);
259                         return attributeNode != null;
260                 }
261
262                 [MonoTODO]
263                 public virtual bool HasAttribute (string localName, string namespaceURI)
264                 {
265                         XmlNode attributeNode = Attributes.GetNamedItem (localName, namespaceURI);
266                         return attributeNode != null;
267                 }
268
269                 [MonoTODO ("confirm not removing default attributes [when DTD feature was implemented.")]
270                 public override void RemoveAll ()
271                 {
272                         // Remove the child nodes.
273                         base.RemoveAll ();
274
275                         // Remove all attributes.
276                         attributes.RemoveAll ();
277                 }
278
279                 [MonoTODO ("confirm not removing default attributes [when DTD feature was implemented.")]
280                 public virtual void RemoveAllAttributes ()
281                 {
282                         attributes.RemoveAll ();
283                 }
284
285                 [MonoTODO ("confirm not resetting default attributes [when DTD feature was implemented.")]
286                 public virtual void RemoveAttribute (string name)
287                 {
288                         attributes.Remove((XmlAttribute)attributes.GetNamedItem(name));
289                 }
290
291                 [MonoTODO ("confirm not resetting default attributes [when DTD feature was implemented.")]
292                 public virtual void RemoveAttribute (string localName, string namespaceURI)
293                 {
294                         attributes.Remove((XmlAttribute)attributes.GetNamedItem(localName, namespaceURI));
295                 }
296
297                 [MonoTODO ("confirm not resetting default attributes [when DTD feature was implemented.")]
298                 public virtual XmlNode RemoveAttributeAt (int i)
299                 {
300                         return attributes.Remove(attributes[i]);
301                 }
302
303                 [MonoTODO ("confirm not resetting default attributes [when DTD feature was implemented.")]
304                 public virtual XmlAttribute RemoveAttributeNode (XmlAttribute oldAttr)
305                 {
306                         return attributes.Remove(oldAttr);
307                 }
308
309                 [MonoTODO ("confirm not resetting default attributes [when DTD feature was implemented.")]
310                 public virtual XmlAttribute RemoveAttributeNode (string localName, string namespaceURI)
311                 {
312                         return attributes.Remove(attributes[localName, namespaceURI]);
313                 }
314
315                 [MonoTODO]
316                 public virtual void SetAttribute (string name, string value)
317                 {
318                         XmlAttribute attribute = OwnerDocument.CreateAttribute (name);
319                         attribute.SetOwnerElement(this);
320                         attribute.Value = value;
321                         Attributes.SetNamedItem (attribute);
322                 }
323
324 //              [MonoTODO]
325                 public virtual string SetAttribute (string localName, string namespaceURI, string value)
326                 {
327                         XmlAttribute attr = attributes[localName, namespaceURI];
328                         if(attr == null)
329                         {
330                                 attr = OwnerDocument.CreateAttribute(localName, namespaceURI);
331                                 attr.Value = value;
332                                 attributes.SetNamedItem(attr);
333                         }
334                         else
335                                 attr.Value = value;
336                         return attr.Value;
337                 }
338
339 //              [MonoTODO]
340                 public virtual XmlAttribute SetAttributeNode (XmlAttribute newAttr)
341                 {
342                         newAttr.SetOwnerElement(this);
343                         XmlNode oldAttr = Attributes.SetNamedItem(newAttr);
344                         return oldAttr != null ? oldAttr as XmlAttribute : null;
345                 }
346
347                 public virtual XmlAttribute SetAttributeNode (string localName, string namespaceURI)
348                 {
349                         XmlDocument xmlDoc = this.OwnerDocument;
350                         XmlAttribute xmlAttribute = new XmlAttribute (String.Empty, localName, namespaceURI, xmlDoc);
351                         return this.attributes.Append (xmlAttribute);
352                 }
353
354                 public override void WriteContentTo (XmlWriter w)
355                 {
356                         foreach(XmlNode childNode in ChildNodes)
357                                 childNode.WriteTo(w);
358                 }
359
360                 [MonoTODO]
361                 public override void WriteTo (XmlWriter w)
362                 {
363                         w.WriteStartElement(Prefix, LocalName, NamespaceURI);
364
365                         foreach(XmlNode attributeNode in Attributes)
366                                 attributeNode.WriteTo(w);
367
368                         // write namespace declarations(if not exist)
369                         foreach(XmlNode attributeNode in Attributes) {
370                                 if(attributeNode.Prefix != null && attributeNode.Prefix != String.Empty &&\r
371                                         w.LookupPrefix(attributeNode.Prefix) != attributeNode.NamespaceURI &&\r
372                                         attributeNode.Prefix != "xmlns")\r
373                                         w.WriteAttributeString("xmlns", attributeNode.Prefix, "http://www.w3.org/2000/xmlns/", attributeNode.NamespaceURI);
374                         }
375
376                         WriteContentTo(w);
377
378                         w.WriteEndElement();
379                 }
380
381                 #endregion
382         }
383 }