2010-04-07 Jb Evain <jbevain@novell.com>
[mcs.git] / class / System.XML / System.Xml / XmlElement.cs
blob9fc0ce9d74d81b55c801ba6d53615e753053cda5
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
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.
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 #if NET_2_0
40 using System.Xml.Schema;
41 #endif
43 namespace System.Xml
45 public class XmlElement : XmlLinkedNode, IHasXmlChildNode
47 #region Fields
49 private XmlAttributeCollection attributes;
50 private XmlNameEntry name;
51 XmlLinkedNode lastLinkedChild;
53 private bool isNotEmpty;
54 #if NET_2_0
55 IXmlSchemaInfo schemaInfo;
56 #endif
58 #endregion
60 #region Constructor
62 protected internal XmlElement (
63 string prefix,
64 string localName,
65 string namespaceURI,
66 XmlDocument doc) : this (prefix, localName, namespaceURI, doc, false)
70 internal XmlElement (
71 string prefix,
72 string localName,
73 string namespaceURI,
74 XmlDocument doc,
75 bool atomizedNames) : base (doc)
77 if (!atomizedNames) {
78 if (prefix == null)
79 prefix = String.Empty;
80 if (namespaceURI == null)
81 namespaceURI = String.Empty;
83 XmlConvert.VerifyName (localName);
85 prefix = doc.NameTable.Add (prefix);
86 localName = doc.NameTable.Add (localName);
87 namespaceURI = doc.NameTable.Add (namespaceURI);
89 name = doc.NameCache.Add (prefix, localName, namespaceURI, true);
91 if(doc.DocumentType != null)
93 DTDAttListDeclaration attlist = doc.DocumentType.DTD.AttListDecls [localName];
94 if (attlist != null) {
95 for (int i = 0; i < attlist.Definitions.Count; i++) {
96 DTDAttributeDefinition def = attlist [i];
97 if (def.DefaultValue != null) {
98 SetAttribute (def.Name, def.DefaultValue);
99 Attributes [def.Name].SetDefault ();
106 #endregion
108 #region Properties
110 XmlLinkedNode IHasXmlChildNode.LastLinkedChild {
111 get { return lastLinkedChild; }
112 set { lastLinkedChild = value; }
115 public override XmlAttributeCollection Attributes {
116 get {
117 if (attributes == null)
118 attributes = new XmlAttributeCollection (this);
119 return attributes;
123 public virtual bool HasAttributes {
124 get { return attributes != null && attributes.Count > 0; }
127 public override string InnerText {
128 get {
129 return base.InnerText;
131 set {
132 // Why its behavior (of MS FCL) is different from InnerXml...?
133 if (FirstChild != null && FirstChild.NextSibling == null && FirstChild.NodeType == XmlNodeType.Text)
134 FirstChild.Value = value;
135 else {
136 while (FirstChild != null)
137 this.RemoveChild (FirstChild);
138 // creates new Text node
139 AppendChild (OwnerDocument.CreateTextNode (value), false);
144 public override string InnerXml {
145 get {
146 return base.InnerXml;
148 set {
149 while (FirstChild != null)
150 this.RemoveChild (FirstChild);
152 XmlNamespaceManager nsmgr = this.ConstructNamespaceManager ();
153 XmlParserContext ctx = new XmlParserContext (OwnerDocument.NameTable, nsmgr,
154 OwnerDocument.DocumentType != null ? OwnerDocument.DocumentType.DTD : null,
155 BaseURI, XmlLang, XmlSpace, null);
156 XmlTextReader xmlReader = new XmlTextReader (value, XmlNodeType.Element, ctx);
157 xmlReader.XmlResolver = OwnerDocument.Resolver;
159 do {
160 XmlNode n = OwnerDocument.ReadNode (xmlReader);
161 if(n == null) break;
162 AppendChild (n);
163 } while (true);
167 public bool IsEmpty {
168 get {
169 return !isNotEmpty && (FirstChild == null);
172 set {
173 isNotEmpty = !value;
174 if(value) {
175 while (FirstChild != null)
176 RemoveChild (FirstChild);
181 public override string LocalName {
182 get { return name.LocalName; }
185 public override string Name {
186 get { return name.GetPrefixedName (OwnerDocument.NameCache); }
189 public override string NamespaceURI {
190 get { return name.NS; }
193 public override XmlNode NextSibling {
194 get { return ParentNode == null || ((IHasXmlChildNode) ParentNode).LastLinkedChild == this ? null : NextLinkedSibling; }
197 public override XmlNodeType NodeType {
198 get {
199 return XmlNodeType.Element;
203 internal override XPathNodeType XPathNodeType {
204 get {
205 return XPathNodeType.Element;
209 public override XmlDocument OwnerDocument {
210 get {
211 return base.OwnerDocument;
215 public override string Prefix {
216 get { return name.Prefix; }
217 set {
218 if (IsReadOnly)
219 throw new ArgumentException ("This node is readonly.");
220 if (value == null) {
221 #if NET_2_0
222 value = string.Empty;
223 #else
224 throw new ArgumentNullException ("Prefix value is null.");
225 #endif
227 if ((!String.Empty.Equals(value))&&(!XmlChar.IsNCName (value)))
228 throw new ArgumentException ("Specified name is not a valid NCName: " + value);
230 value = OwnerDocument.NameTable.Add (value);
231 name = OwnerDocument.NameCache.Add (value,
232 name.LocalName, name.NS, true);
236 #if NET_2_0
237 public override XmlNode ParentNode {
238 get { return base.ParentNode; }
241 public override IXmlSchemaInfo SchemaInfo {
242 get { return schemaInfo; }
243 internal set { schemaInfo = value; }
245 #endif
247 #endregion
249 #region Methods
251 public override XmlNode CloneNode (bool deep)
253 XmlElement node = OwnerDocument.CreateElement (
254 name.Prefix, name.LocalName, name.NS, true);
256 for (int i = 0; i < Attributes.Count; i++)
257 node.SetAttributeNode ((XmlAttribute)
258 Attributes [i].CloneNode (true));
260 if (deep) {
261 for (int i = 0; i < ChildNodes.Count; i++)
262 node.AppendChild (ChildNodes [i].CloneNode (true), false);
265 return node;
268 public virtual string GetAttribute (string name)
270 XmlNode attributeNode = Attributes.GetNamedItem (name);
271 return attributeNode != null ? attributeNode.Value : String.Empty;
274 public virtual string GetAttribute (string localName, string namespaceURI)
276 XmlNode attributeNode = Attributes.GetNamedItem (localName, namespaceURI);
277 return attributeNode != null ? attributeNode.Value : String.Empty;
280 public virtual XmlAttribute GetAttributeNode (string name)
282 XmlNode attributeNode = Attributes.GetNamedItem (name);
283 return attributeNode != null ? attributeNode as XmlAttribute : null;
286 public virtual XmlAttribute GetAttributeNode (string localName, string namespaceURI)
288 XmlNode attributeNode = Attributes.GetNamedItem (localName, namespaceURI);
289 return attributeNode != null ? attributeNode as XmlAttribute : null;
292 public virtual XmlNodeList GetElementsByTagName (string name)
294 ArrayList nodeArrayList = new ArrayList ();
295 this.SearchDescendantElements (name, name == "*", nodeArrayList);
296 return new XmlNodeArrayList (nodeArrayList);
299 public virtual XmlNodeList GetElementsByTagName (string localName, string namespaceURI)
301 ArrayList nodeArrayList = new ArrayList ();
302 this.SearchDescendantElements (localName, localName == "*", namespaceURI, namespaceURI == "*", nodeArrayList);
303 return new XmlNodeArrayList (nodeArrayList);
306 public virtual bool HasAttribute (string name)
308 XmlNode attributeNode = Attributes.GetNamedItem (name);
309 return attributeNode != null;
312 public virtual bool HasAttribute (string localName, string namespaceURI)
314 XmlNode attributeNode = Attributes.GetNamedItem (localName, namespaceURI);
315 return attributeNode != null;
318 public override void RemoveAll ()
320 // Remove all attributes and child nodes.
321 base.RemoveAll ();
324 public virtual void RemoveAllAttributes ()
326 if (attributes != null)
327 attributes.RemoveAll ();
330 public virtual void RemoveAttribute (string name)
332 if (attributes == null)
333 return;
334 XmlAttribute attr = Attributes.GetNamedItem (name) as XmlAttribute;
335 if (attr != null)
336 Attributes.Remove(attr);
339 public virtual void RemoveAttribute (string localName, string namespaceURI)
341 if (attributes == null)
342 return;
344 XmlAttribute attr = attributes.GetNamedItem(localName, namespaceURI) as XmlAttribute;
345 if (attr != null)
346 Attributes.Remove(attr);
349 public virtual XmlNode RemoveAttributeAt (int i)
351 if (attributes == null || attributes.Count <= i)
352 return null;
353 return Attributes.RemoveAt (i);
356 public virtual XmlAttribute RemoveAttributeNode (XmlAttribute oldAttr)
358 if (attributes == null)
359 return null;
360 return Attributes.Remove (oldAttr);
363 public virtual XmlAttribute RemoveAttributeNode (string localName, string namespaceURI)
365 if (attributes == null)
366 return null;
367 return Attributes.Remove (attributes [localName, namespaceURI]);
370 public virtual void SetAttribute (string name, string value)
372 XmlAttribute attr = Attributes [name];
373 if (attr == null) {
374 attr = OwnerDocument.CreateAttribute (name);
375 attr.Value = value;
376 Attributes.SetNamedItem (attr);
378 else
379 attr.Value = value;
382 public virtual string SetAttribute (string localName, string namespaceURI, string value)
384 XmlAttribute attr = Attributes [localName, namespaceURI];
385 if (attr == null) {
386 attr = OwnerDocument.CreateAttribute (localName, namespaceURI);
387 attr.Value = value;
388 Attributes.SetNamedItem (attr);
390 else
391 attr.Value = value;
392 return attr.Value;
395 public virtual XmlAttribute SetAttributeNode (XmlAttribute newAttr)
397 if (newAttr.OwnerElement != null)
398 throw new InvalidOperationException (
399 "Specified attribute is already an attribute of another element.");
401 XmlAttribute ret = Attributes.SetNamedItem (newAttr) as XmlAttribute;
402 return ret == newAttr ? null : ret;
405 public virtual XmlAttribute SetAttributeNode (string localName, string namespaceURI)
407 // Note that this constraint is only for this method.
408 // SetAttribute() allows prefixed name.
409 XmlConvert.VerifyNCName (localName);
411 return Attributes.Append (OwnerDocument.CreateAttribute (String.Empty, localName, namespaceURI, false, true));
414 public override void WriteContentTo (XmlWriter w)
416 for (XmlNode n = FirstChild; n != null; n = n.NextSibling)
417 n.WriteTo (w);
420 public override void WriteTo (XmlWriter w)
422 w.WriteStartElement (
423 name.NS == null || name.NS.Length == 0 ? String.Empty : name.Prefix,
424 name.LocalName,
425 name.NS);
427 if (HasAttributes)
428 for (int i = 0; i < Attributes.Count; i++)
429 Attributes [i].WriteTo (w);
431 WriteContentTo (w);
433 if (IsEmpty)
434 w.WriteEndElement ();
435 else
436 w.WriteFullEndElement ();
439 #endregion