2003-03-23 Atsushi Enomoto <ginga@kit.hi-ho.ne.jp>
[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                                 while (FirstChild != null)
89                                         this.RemoveChild (FirstChild);
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.Initialize (String.Empty, ctx, new StringReader (value), XmlNodeType.Element);
97
98                                 do {
99                                         XmlNode n = OwnerDocument.ReadNode (xmlReader);
100                                         if(n == null) break;
101                                         AppendChild (n);
102                                 } while (true);
103                         }
104                 }
105
106                 public bool IsEmpty {
107                         get { return isEmpty; }
108
109                         set {
110                                 if(value)
111                                         RemoveAll();
112                                 isEmpty = value;
113                         }
114                 }
115
116                 public override string LocalName {
117                         get { return localName; }
118                 }
119
120                 public override string Name {
121                         get {
122                                 if (prefix == String.Empty || prefix == null)
123                                         return localName;
124                                 else
125                                         return prefix + ":" + localName;
126                         }
127                 }
128
129                 public override string NamespaceURI {
130                         get { return namespaceURI; }
131                 }
132
133                 [MonoTODO]
134                 public override XmlNode NextSibling {
135                         get { 
136                                 return base.NextSibling; 
137                         }
138                 }
139
140                 public override XmlNodeType NodeType {
141                         get { 
142                                 return XmlNodeType.Element; 
143                         }
144                 }
145
146                 internal override XPathNodeType XPathNodeType {
147                         get {
148                                 return XPathNodeType.Element;
149                         }
150                 }
151
152                 [MonoTODO]
153                 public override XmlDocument OwnerDocument {
154                         get { 
155                                 return base.OwnerDocument; 
156                         }
157                 }
158
159                 public override string Prefix {
160                         get { return prefix; }
161                         set { prefix = value; }
162                 }
163
164                 #endregion
165
166                 #region Methods
167                 
168                 [MonoTODO]
169                 public override XmlNode CloneNode (bool deep)
170                 {
171                         XmlNode node =  new XmlElement (prefix, localName, namespaceURI,
172                                                         OwnerDocument);
173
174                         for (int i = 0; i < node.Attributes.Count; i++)
175                                 node.AppendChild (node.Attributes [i].CloneNode (false));
176                         
177                         if (deep) {
178                                 while ((node != null) && (node.HasChildNodes)) {                                        
179                                         AppendChild (node.NextSibling.CloneNode (true));
180                                         node = node.NextSibling;
181                                 }
182                         } // shallow cloning
183                                 
184                         //
185                         // Reminder: Also look into Default attributes.
186                         //
187                         return node;
188                 }
189
190                 [MonoTODO]
191                 public virtual string GetAttribute (string name)
192                 {
193                         XmlNode attributeNode = Attributes.GetNamedItem (name);
194                         return attributeNode != null ? attributeNode.Value : String.Empty;
195                 }
196
197                 [MonoTODO]
198                 public virtual string GetAttribute (string localName, string namespaceURI)
199                 {
200                         XmlNode attributeNode = Attributes.GetNamedItem (localName, namespaceURI);
201                         return attributeNode != null ? attributeNode.Value : String.Empty;
202                 }
203
204                 [MonoTODO]
205                 public virtual XmlAttribute GetAttributeNode (string name)
206                 {
207                         XmlNode attributeNode = Attributes.GetNamedItem (name);
208                         return attributeNode != null ? attributeNode as XmlAttribute : null;
209                 }
210
211                 [MonoTODO]
212                 public virtual XmlAttribute GetAttributeNode (string localName, string namespaceURI)
213                 {
214                         XmlNode attributeNode = Attributes.GetNamedItem (localName, namespaceURI);
215                         return attributeNode != null ? attributeNode as XmlAttribute : null;
216                 }
217
218                 public virtual XmlNodeList GetElementsByTagName (string name)
219                 {
220                         ArrayList nodeArrayList = new ArrayList ();
221                         this.searchNodesRecursively (this, name, nodeArrayList);
222                         return new XmlNodeArrayList (nodeArrayList);
223                 }
224
225                 private void searchNodesRecursively (XmlNode argNode, string argName, 
226                         ArrayList argArrayList)
227                 {
228                         XmlNodeList xmlNodeList = argNode.ChildNodes;
229                         foreach (XmlNode node in xmlNodeList){
230                                 if (node.Name.Equals (argName))
231                                         argArrayList.Add (node);
232                                 else    
233                                         this.searchNodesRecursively (node, argName, argArrayList);
234                         }
235                 }
236
237                 private void searchNodesRecursively (XmlNode argNode, string argName, string argNamespaceURI, 
238                         ArrayList argArrayList)
239                 {
240                         XmlNodeList xmlNodeList = argNode.ChildNodes;
241                         foreach (XmlNode node in xmlNodeList)
242                         {
243                                 if (node.LocalName.Equals (argName) && node.NamespaceURI.Equals (argNamespaceURI))
244                                         argArrayList.Add (node);
245                                 else    
246                                         this.searchNodesRecursively (node, argName, argNamespaceURI, argArrayList);
247                         }
248                 }
249
250                 public virtual XmlNodeList GetElementsByTagName (string localName, string namespaceURI)
251                 {
252                         ArrayList nodeArrayList = new ArrayList ();
253                         this.searchNodesRecursively (this, localName, namespaceURI, nodeArrayList);
254                         return new XmlNodeArrayList (nodeArrayList);
255                 }
256
257                 [MonoTODO]
258                 public virtual bool HasAttribute (string name)
259                 {
260                         XmlNode attributeNode = Attributes.GetNamedItem (name);
261                         return attributeNode != null;
262                 }
263
264                 [MonoTODO]
265                 public virtual bool HasAttribute (string localName, string namespaceURI)
266                 {
267                         XmlNode attributeNode = Attributes.GetNamedItem (localName, namespaceURI);
268                         return attributeNode != null;
269                 }
270
271                 [MonoTODO ("confirm not removing default attributes [when DTD feature was implemented.")]
272                 public override void RemoveAll ()
273                 {
274                         // Remove the child nodes.
275                         base.RemoveAll ();
276
277                         // Remove all attributes.
278                         attributes.RemoveAll ();
279                 }
280
281                 [MonoTODO ("confirm not removing default attributes [when DTD feature was implemented.")]
282                 public virtual void RemoveAllAttributes ()
283                 {
284                         attributes.RemoveAll ();
285                 }
286
287                 [MonoTODO ("confirm not resetting default attributes [when DTD feature was implemented.")]
288                 public virtual void RemoveAttribute (string name)
289                 {
290                         XmlAttribute attr = attributes.GetNamedItem (name) as XmlAttribute;
291                         if (attr != null)
292                                 attributes.Remove(attr);
293                 }
294
295                 [MonoTODO ("confirm not resetting default attributes [when DTD feature was implemented.")]
296                 public virtual void RemoveAttribute (string localName, string namespaceURI)
297                 {
298                         XmlAttribute attr = attributes.GetNamedItem(localName, namespaceURI) as XmlAttribute;
299                         if (attr != null)
300                                 attributes.Remove(attr);
301                 }
302
303                 [MonoTODO ("confirm not resetting default attributes [when DTD feature was implemented.")]
304                 public virtual XmlNode RemoveAttributeAt (int i)
305                 {
306                         return attributes.RemoveAt (i);
307                 }
308
309                 [MonoTODO ("confirm not resetting default attributes [when DTD feature was implemented.")]
310                 public virtual XmlAttribute RemoveAttributeNode (XmlAttribute oldAttr)
311                 {
312                         return attributes.Remove(oldAttr);
313                 }
314
315                 [MonoTODO ("confirm not resetting default attributes [when DTD feature was implemented.")]
316                 public virtual XmlAttribute RemoveAttributeNode (string localName, string namespaceURI)
317                 {
318                         return attributes.Remove(attributes[localName, namespaceURI]);
319                 }
320
321                 [MonoTODO]
322                 public virtual void SetAttribute (string name, string value)
323                 {
324                         XmlAttribute attribute = OwnerDocument.CreateAttribute (name);
325                         attribute.SetOwnerElement(this);
326                         attribute.Value = value;
327                         Attributes.SetNamedItem (attribute);
328                 }
329
330 //              [MonoTODO]
331                 public virtual string SetAttribute (string localName, string namespaceURI, string value)
332                 {
333                         XmlAttribute attr = attributes[localName, namespaceURI];
334                         if(attr == null)
335                         {
336                                 attr = OwnerDocument.CreateAttribute(localName, namespaceURI);
337                                 attr.Value = value;
338                                 attributes.SetNamedItem(attr);
339                         }
340                         else
341                                 attr.Value = value;
342                         return attr.Value;
343                 }
344
345 //              [MonoTODO]
346                 public virtual XmlAttribute SetAttributeNode (XmlAttribute newAttr)
347                 {
348                         newAttr.SetOwnerElement(this);
349                         XmlNode oldAttr = Attributes.SetNamedItem(newAttr);
350                         return oldAttr != null ? oldAttr as XmlAttribute : null;
351                 }
352
353                 public virtual XmlAttribute SetAttributeNode (string localName, string namespaceURI)
354                 {
355                         XmlDocument xmlDoc = this.OwnerDocument;
356                         XmlAttribute xmlAttribute = new XmlAttribute (String.Empty, localName, namespaceURI, xmlDoc);
357                         return this.attributes.Append (xmlAttribute);
358                 }
359
360                 public override void WriteContentTo (XmlWriter w)
361                 {
362                         foreach(XmlNode childNode in ChildNodes)
363                                 childNode.WriteTo(w);
364                 }
365
366                 [MonoTODO]
367                 public override void WriteTo (XmlWriter w)
368                 {
369                         w.WriteStartElement(Prefix, LocalName, NamespaceURI);
370
371                         foreach(XmlNode attributeNode in Attributes)
372                                 attributeNode.WriteTo(w);
373
374                         // write namespace declarations(if not exist)
375                         foreach(XmlNode attributeNode in Attributes) {
376                                 if(attributeNode.Prefix != null && attributeNode.Prefix != String.Empty &&\r
377                                         w.LookupPrefix(attributeNode.NamespaceURI) != attributeNode.Prefix &&
378                                         attributeNode.Prefix != "xmlns")\r
379                                         w.WriteAttributeString("xmlns", attributeNode.Prefix, "http://www.w3.org/2000/xmlns/", attributeNode.NamespaceURI);
380                         }
381
382                         WriteContentTo(w);
383
384                         w.WriteEndElement();
385                 }
386
387                 #endregion
388         }
389 }