Implement MachineKey.Protect and MachineKey.Unprotect
[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 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33 using System;
34 using System.Collections;
35 using System.Xml.XPath;
36 using System.IO;
37 using System.Text;
38 using Mono.Xml;
39 using System.Xml.Schema;
40
41 namespace System.Xml
42 {
43         public class XmlElement : XmlLinkedNode, IHasXmlChildNode
44         {
45                 #region Fields
46
47                 private XmlAttributeCollection attributes;
48                 private XmlNameEntry name;
49                 XmlLinkedNode lastLinkedChild;
50
51                 private bool isNotEmpty;
52                 IXmlSchemaInfo schemaInfo;
53
54                 #endregion
55
56                 #region Constructor
57
58                 protected internal XmlElement (
59                         string prefix, 
60                         string localName, 
61                         string namespaceURI, 
62                         XmlDocument doc) : this (prefix, localName, namespaceURI, doc, false)
63                 {
64                 }
65
66                 internal XmlElement (
67                         string prefix, 
68                         string localName, 
69                         string namespaceURI, 
70                         XmlDocument doc,
71                         bool atomizedNames) : base (doc)
72                 {
73                         if (!atomizedNames) {
74                                 if (prefix == null)
75                                         prefix = String.Empty;
76                                 if (namespaceURI == null)
77                                         namespaceURI = String.Empty;
78
79                                 XmlConvert.VerifyName (localName);
80
81                                 prefix = doc.NameTable.Add (prefix);
82                                 localName = doc.NameTable.Add (localName);
83                                 namespaceURI = doc.NameTable.Add (namespaceURI);
84                         }
85                         name = doc.NameCache.Add (prefix, localName, namespaceURI, true);
86
87                         if(doc.DocumentType != null)
88                         {
89                                 DTDAttListDeclaration attlist = doc.DocumentType.DTD.AttListDecls [localName];
90                                 if (attlist != null) {
91                                         for (int i = 0; i < attlist.Definitions.Count; i++) {
92                                                 DTDAttributeDefinition def = attlist [i];
93                                                 if (def.DefaultValue != null) {
94                                                         SetAttribute (def.Name, def.DefaultValue);
95                                                         Attributes [def.Name].SetDefault ();
96                                                 }
97                                         }
98                                 }
99                         }
100                 }
101
102                 #endregion
103
104                 #region Properties
105
106                 XmlLinkedNode IHasXmlChildNode.LastLinkedChild {
107                         get { return lastLinkedChild; }
108                         set { lastLinkedChild = value; }
109                 }
110
111                 public override XmlAttributeCollection Attributes {
112                         get {
113                                 if (attributes == null)
114                                         attributes = new XmlAttributeCollection (this);
115                                 return attributes;
116                         }
117                 }
118
119                 public virtual bool HasAttributes {
120                         get { return attributes != null && attributes.Count > 0; }
121                 }
122
123                 public override string InnerText {
124                         get {
125                                 return base.InnerText;
126                         }
127                         set {
128                                 // Why its behavior (of MS FCL) is different from InnerXml...?
129                                 if (FirstChild != null && FirstChild.NextSibling == null && FirstChild.NodeType == XmlNodeType.Text)
130                                         FirstChild.Value = value;
131                                 else {
132                                         while (FirstChild != null)
133                                                 this.RemoveChild (FirstChild);
134                                         // creates new Text node
135                                         AppendChild (OwnerDocument.CreateTextNode (value), false);
136                                 }
137                         }
138                 }
139
140                 public override string InnerXml {
141                         get {
142                                 return base.InnerXml;
143                         }
144                         set {
145                                 while (FirstChild != null)
146                                         this.RemoveChild (FirstChild);
147
148                                 XmlNamespaceManager nsmgr = this.ConstructNamespaceManager ();
149                                 XmlParserContext ctx = new XmlParserContext (OwnerDocument.NameTable, nsmgr,
150                                         OwnerDocument.DocumentType != null ? OwnerDocument.DocumentType.DTD : null,
151                                         BaseURI, XmlLang, XmlSpace, null);
152                                 XmlTextReader xmlReader = new XmlTextReader (value, XmlNodeType.Element, ctx);
153                                 xmlReader.XmlResolver = OwnerDocument.Resolver;
154
155                                 do {
156                                         XmlNode n = OwnerDocument.ReadNode (xmlReader);
157                                         if(n == null) break;
158                                         AppendChild (n);
159                                 } while (true);
160                         }
161                 }
162
163                 public bool IsEmpty {
164                         get {
165                                 return !isNotEmpty && (FirstChild == null);
166                         }
167
168                         set {
169                                 isNotEmpty = !value;
170                                 if(value) {
171                                         while (FirstChild != null)
172                                                 RemoveChild (FirstChild);
173                                 }
174                         }
175                 }
176
177                 public override string LocalName {
178                         get { return name.LocalName; }
179                 }
180
181                 public override string Name {
182                         get { return name.GetPrefixedName (OwnerDocument.NameCache); }
183                 }
184
185                 public override string NamespaceURI {
186                         get { return name.NS; }
187                 }
188
189                 public override XmlNode NextSibling {
190                         get { return ParentNode == null || ((IHasXmlChildNode) ParentNode).LastLinkedChild == this ? null : NextLinkedSibling; }
191                 }
192
193                 public override XmlNodeType NodeType {
194                         get { 
195                                 return XmlNodeType.Element; 
196                         }
197                 }
198
199                 internal override XPathNodeType XPathNodeType {
200                         get {
201                                 return XPathNodeType.Element;
202                         }
203                 }
204
205                 public override XmlDocument OwnerDocument {
206                         get { 
207                                 return base.OwnerDocument; 
208                         }
209                 }
210
211                 public override string Prefix {
212                         get { return name.Prefix; }
213                         set {
214                                 if (IsReadOnly)
215                                         throw new ArgumentException ("This node is readonly.");
216                                 if (value == null) {
217                                         value = string.Empty;
218                                 }
219                                 if ((!String.Empty.Equals(value))&&(!XmlChar.IsNCName (value)))
220                                         throw new ArgumentException ("Specified name is not a valid NCName: " + value);
221
222                                 value = OwnerDocument.NameTable.Add (value);
223                                 name = OwnerDocument.NameCache.Add (value,
224                                         name.LocalName, name.NS, true);
225                         }
226                 }
227
228                 public override XmlNode ParentNode {
229                         get { return base.ParentNode; }
230                 }
231
232                 public override IXmlSchemaInfo SchemaInfo {
233                         get { return schemaInfo; }
234                         internal set { schemaInfo = value; }
235                 }
236
237                 #endregion
238
239                 #region Methods
240                 
241                 public override XmlNode CloneNode (bool deep)
242                 {
243                         XmlElement node = OwnerDocument.CreateElement (
244                                 name.Prefix, name.LocalName, name.NS, true);
245
246                         for (int i = 0; i < Attributes.Count; i++)
247                                 node.SetAttributeNode ((XmlAttribute) 
248                                         Attributes [i].CloneNode (true));
249
250                         if (deep) {
251                                 for (int i = 0; i < ChildNodes.Count; i++)
252                                         node.AppendChild (ChildNodes [i].CloneNode (true), false);
253                         }
254
255                         return node;
256                 }
257
258                 public virtual string GetAttribute (string name)
259                 {
260                         XmlNode attributeNode = Attributes.GetNamedItem (name);
261                         return attributeNode != null ? attributeNode.Value : String.Empty;
262                 }
263
264                 public virtual string GetAttribute (string localName, string namespaceURI)
265                 {
266                         XmlNode attributeNode = Attributes.GetNamedItem (localName, namespaceURI);
267                         return attributeNode != null ? attributeNode.Value : String.Empty;
268                 }
269
270                 public virtual XmlAttribute GetAttributeNode (string name)
271                 {
272                         XmlNode attributeNode = Attributes.GetNamedItem (name);
273                         return attributeNode != null ? attributeNode as XmlAttribute : null;
274                 }
275
276                 public virtual XmlAttribute GetAttributeNode (string localName, string namespaceURI)
277                 {
278                         XmlNode attributeNode = Attributes.GetNamedItem (localName, namespaceURI);
279                         return attributeNode != null ? attributeNode as XmlAttribute : null;
280                 }
281
282                 public virtual XmlNodeList GetElementsByTagName (string name)
283                 {
284                         ArrayList nodeArrayList = new ArrayList ();
285                         this.SearchDescendantElements (name, name == "*", nodeArrayList);
286                         return new XmlNodeArrayList (nodeArrayList);
287                 }
288
289                 public virtual XmlNodeList GetElementsByTagName (string localName, string namespaceURI)
290                 {
291                         ArrayList nodeArrayList = new ArrayList ();
292                         this.SearchDescendantElements (localName, localName == "*", namespaceURI, namespaceURI == "*", nodeArrayList);
293                         return new XmlNodeArrayList (nodeArrayList);
294                 }
295
296                 public virtual bool HasAttribute (string name)
297                 {
298                         XmlNode attributeNode = Attributes.GetNamedItem (name);
299                         return attributeNode != null;
300                 }
301
302                 public virtual bool HasAttribute (string localName, string namespaceURI)
303                 {
304                         XmlNode attributeNode = Attributes.GetNamedItem (localName, namespaceURI);
305                         return attributeNode != null;
306                 }
307
308                 public override void RemoveAll ()
309                 {
310                         // Remove all attributes and child nodes.
311                         base.RemoveAll ();
312                 }
313
314                 public virtual void RemoveAllAttributes ()
315                 {
316                         if (attributes != null)
317                                 attributes.RemoveAll ();
318                 }
319
320                 public virtual void RemoveAttribute (string name)
321                 {
322                         if (attributes == null)
323                                 return;
324                         XmlAttribute attr = Attributes.GetNamedItem (name) as XmlAttribute;
325                         if (attr != null)
326                                 Attributes.Remove(attr);
327                 }
328
329                 public virtual void RemoveAttribute (string localName, string namespaceURI)
330                 {
331                         if (attributes == null)
332                                 return;
333
334                         XmlAttribute attr = attributes.GetNamedItem(localName, namespaceURI) as XmlAttribute;
335                         if (attr != null)
336                                 Attributes.Remove(attr);
337                 }
338
339                 public virtual XmlNode RemoveAttributeAt (int i)
340                 {
341                         if (attributes == null || attributes.Count <= i)
342                                 return null;
343                         return Attributes.RemoveAt (i);
344                 }
345
346                 public virtual XmlAttribute RemoveAttributeNode (XmlAttribute oldAttr)
347                 {
348                         if (attributes == null)
349                                 return null;
350                         return Attributes.Remove (oldAttr);
351                 }
352
353                 public virtual XmlAttribute RemoveAttributeNode (string localName, string namespaceURI)
354                 {
355                         if (attributes == null)
356                                 return null;
357                         return Attributes.Remove (attributes [localName, namespaceURI]);
358                 }
359
360                 public virtual void SetAttribute (string name, string value)
361                 {
362                         XmlAttribute attr = Attributes [name];
363                         if (attr == null) {
364                                 attr = OwnerDocument.CreateAttribute (name);
365                                 attr.Value = value;
366                                 Attributes.SetNamedItem (attr);
367                         }
368                         else
369                                 attr.Value = value;
370                 }
371
372                 public virtual string SetAttribute (string localName, string namespaceURI, string value)
373                 {
374                         XmlAttribute attr = Attributes [localName, namespaceURI];
375                         if (attr == null) {
376                                 attr = OwnerDocument.CreateAttribute (localName, namespaceURI);
377                                 attr.Value = value;
378                                 Attributes.SetNamedItem (attr);
379                         }
380                         else
381                                 attr.Value = value;
382                         return attr.Value;
383                 }
384
385                 public virtual XmlAttribute SetAttributeNode (XmlAttribute newAttr)
386                 {
387                         if (newAttr.OwnerElement != null)
388                                 throw new InvalidOperationException (
389                                         "Specified attribute is already an attribute of another element.");
390
391                         XmlAttribute ret = Attributes.SetNamedItem (newAttr) as XmlAttribute;
392                         return ret == newAttr ? null : ret;
393                 }
394
395                 public virtual XmlAttribute SetAttributeNode (string localName, string namespaceURI)
396                 {
397                         // Note that this constraint is only for this method.
398                         // SetAttribute() allows prefixed name.
399                         XmlConvert.VerifyNCName (localName);
400
401                         return Attributes.Append (OwnerDocument.CreateAttribute (String.Empty, localName, namespaceURI, false, true));
402                 }
403
404                 public override void WriteContentTo (XmlWriter w)
405                 {
406                         for (XmlNode n = FirstChild; n != null; n = n.NextSibling)
407                                 n.WriteTo (w);
408                 }
409
410                 public override void WriteTo (XmlWriter w)
411                 {
412                         w.WriteStartElement (
413                                 name.NS == null || name.NS.Length == 0 ? String.Empty : name.Prefix,
414                                 name.LocalName,
415                                 name.NS);
416
417                         if (HasAttributes)
418                                 for (int i = 0; i < Attributes.Count; i++)
419                                         Attributes [i].WriteTo (w);
420
421                         WriteContentTo (w);
422
423                         if (IsEmpty)
424                                 w.WriteEndElement ();
425                         else
426                                 w.WriteFullEndElement ();
427                 }
428
429                 #endregion
430         }
431 }