Merge pull request #93 from konrad-kruczynski/dispatcher_timer_fix
[mono.git] / mcs / class / System.XML / System.Xml / XmlNamedNodeMap.cs
1 //
2 // System.Xml.XmlNamedNodeMap
3 //
4 // Author:
5 //   Jason Diamond (jason@injektilo.org)
6 //   Duncan Mak  (duncan@ximian.com)
7 //
8 // (C) 2002 Jason Diamond  http://injektilo.org/
9 //
10
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 using System;
33 using System.Collections;
34 using Mono.Xml;
35
36 namespace System.Xml
37 {
38         public class XmlNamedNodeMap : IEnumerable
39         {
40                 static readonly IEnumerator emptyEnumerator = new XmlNode [0].GetEnumerator ();
41
42                 XmlNode parent;
43                 ArrayList nodeList;
44                 bool readOnly = false;
45
46                 internal XmlNamedNodeMap (XmlNode parent)
47                 {
48                         this.parent = parent;
49                 }
50
51                 private ArrayList NodeList {
52                         get {
53                                 if (nodeList == null)
54                                         nodeList = new ArrayList ();
55                                 return nodeList;
56                         }
57                 }
58
59                 public virtual int Count {
60                         get { return nodeList == null ? 0 : nodeList.Count; }
61                 }
62
63                 public virtual IEnumerator GetEnumerator () 
64                 {
65                         if (nodeList == null)
66                                 return emptyEnumerator;
67                         return nodeList.GetEnumerator ();
68                 }
69
70                 public virtual XmlNode GetNamedItem (string name)
71                 {
72                         if (nodeList == null)
73                                 return null;
74
75                         for (int i = 0; i < nodeList.Count; i++) {
76                                 XmlNode node = (XmlNode) nodeList [i];
77                                 if (node.Name == name)
78                                         return node;
79                         }
80                         return null;
81                 }
82
83                 public virtual XmlNode GetNamedItem (string localName, string namespaceURI)
84                 {
85                         if (nodeList == null)
86                                 return null;
87
88                         for (int i = 0; i < nodeList.Count; i++) {
89                                 XmlNode node = (XmlNode) nodeList [i];
90                                 if ((node.LocalName == localName)
91                                     && (node.NamespaceURI == namespaceURI))
92                                         return node;
93                         }
94
95                         return null;
96                 }
97                 
98                 public virtual XmlNode Item (int index)
99                 {
100                         if (nodeList == null || index < 0 || index >= nodeList.Count)
101                                 return null;
102                         else
103                                 return (XmlNode) nodeList [index];
104                 }
105
106                 public virtual XmlNode RemoveNamedItem (string name)
107                 {
108                         if (nodeList == null)
109                                 return null;
110
111                         for (int i = 0; i < nodeList.Count; i++) {
112                                 XmlNode node = (XmlNode) nodeList [i];
113                                 if (node.Name == name) {
114                                         if (node.IsReadOnly)
115                                                 throw new InvalidOperationException ("Cannot remove. This node is read only: " + name);
116                                         nodeList.Remove (node);
117                                         // Since XmlAttributeCollection does not override
118                                         // it while attribute have to keep it in the
119                                         // collection, it adds to the collection immediately.
120                                         XmlAttribute attr = node as XmlAttribute;
121                                         if (attr != null) {
122                                                 DTDAttributeDefinition def = attr.GetAttributeDefinition ();
123                                                 if (def != null && def.DefaultValue != null) {
124                                                         XmlAttribute newAttr = attr.OwnerDocument.CreateAttribute (attr.Prefix, attr.LocalName, attr.NamespaceURI, true, false);
125                                                         newAttr.Value = def.DefaultValue;
126                                                         newAttr.SetDefault ();
127                                                         attr.OwnerElement.SetAttributeNode (newAttr);
128                                                 }
129                                         }
130                                         return node;
131                                 }
132                         }
133                         return null;
134                 }
135
136                 public virtual XmlNode RemoveNamedItem (string localName, string namespaceURI)
137                 {
138                         if (nodeList == null)
139                                 return null;
140
141                         for (int i = 0; i < nodeList.Count; i++) {
142                                 XmlNode node = (XmlNode) nodeList [i];
143                                 if ((node.LocalName == localName)
144                                     && (node.NamespaceURI == namespaceURI)) {
145                                         nodeList.Remove (node);
146                                         return node;
147                                 }
148                         }
149                         return null;
150                 }
151
152                 public virtual XmlNode SetNamedItem (XmlNode node)
153                 {
154                         return SetNamedItem (node, -1, true);
155                 }
156
157                 internal XmlNode SetNamedItem (XmlNode node, bool raiseEvent)
158                 {
159                         return SetNamedItem (node, -1, raiseEvent);
160                 }
161
162                 internal XmlNode SetNamedItem (XmlNode node, int pos, bool raiseEvent)
163                 {
164                         if (readOnly || (node.OwnerDocument != parent.OwnerDocument))
165                                 throw new ArgumentException ("Cannot add to NodeMap.");
166
167                         if (raiseEvent)
168                                 parent.OwnerDocument.onNodeInserting (node, parent);
169
170                         try {
171                                 for (int i = 0; i < NodeList.Count; i++) {
172                                         XmlNode x = (XmlNode) nodeList [i];
173                                         if(x.LocalName == node.LocalName && x.NamespaceURI == node.NamespaceURI) {
174                                                 nodeList.Remove (x);
175                                                 if (pos < 0)
176                                                         nodeList.Add (node);
177                                                 else
178                                                         nodeList.Insert (pos, node);
179                                                 return x;
180                                         }
181                                 }
182                         
183                                 if(pos < 0)
184                                         nodeList.Add (node);
185                                 else
186                                         nodeList.Insert (pos, node);
187
188                                 // LAMESPEC: It should return null here, but
189                                 // it just returns the input node.
190                                 return node;
191                         } finally {
192                                 if (raiseEvent)
193                                         parent.OwnerDocument.onNodeInserted (node, parent);
194                         }
195
196                 }
197
198                 internal ArrayList Nodes { get { return NodeList; } }
199         }
200 }