2 // System.Xml.XmlAttributeCollection
5 // Jason Diamond (jason@injektilo.org)
6 // Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
8 // (C) 2002 Jason Diamond http://injektilo.org/
9 // (C) 2002 Atsushi Enomoto
13 using System.Collections;
18 public class XmlAttributeCollection : XmlNamedNodeMap, ICollection
20 XmlElement ownerElement;
21 XmlDocument ownerDocument;
23 internal XmlAttributeCollection (XmlNode parent) : base (parent)
25 ownerElement = parent as XmlElement;
26 ownerDocument = parent.OwnerDocument;
27 if(ownerElement == null)
28 throw new XmlException ("invalid construction for XmlAttributeCollection.");
31 bool ICollection.IsSynchronized {
33 throw new NotImplementedException ();
39 return ownerElement.IsReadOnly;
43 [System.Runtime.CompilerServices.IndexerName ("ItemOf")]
44 public virtual XmlAttribute this [string name] {
46 return (XmlAttribute) GetNamedItem (name);
50 [System.Runtime.CompilerServices.IndexerName ("ItemOf")]
51 public virtual XmlAttribute this [int i] {
53 return (XmlAttribute) Nodes [i];
57 [System.Runtime.CompilerServices.IndexerName ("ItemOf")]
58 public virtual XmlAttribute this [string localName, string namespaceURI] {
60 return (XmlAttribute) GetNamedItem (localName, namespaceURI);
64 object ICollection.SyncRoot {
66 throw new NotImplementedException ();
71 public virtual XmlAttribute Append (XmlAttribute node)
73 XmlNode xmlNode = this.SetNamedItem (node);
77 public void CopyTo (XmlAttribute[] array, int index)
79 // assuming that Nodes is a correct collection.
80 for(int i=0; i<Nodes.Count; i++)
81 array [index + i] = Nodes [i] as XmlAttribute;
84 void ICollection.CopyTo (Array array, int index)
86 // assuming that Nodes is a correct collection.
87 array.CopyTo (Nodes.ToArray (typeof(XmlAttribute)), index);
90 public virtual XmlAttribute InsertAfter (XmlAttribute newNode, XmlAttribute refNode)
92 if(newNode.OwnerDocument != this.ownerDocument)
93 throw new ArgumentException ("different document created this newNode.");
95 ownerDocument.onNodeInserting (newNode, null);
97 int pos = Nodes.Count + 1;
100 for(int i=0; i<Nodes.Count; i++)
102 XmlNode n = Nodes [i] as XmlNode;
109 if(pos > Nodes.Count)
110 throw new XmlException ("refNode not found in this collection.");
114 SetNamedItem (newNode, pos);
116 ownerDocument.onNodeInserted (newNode, null);
121 public virtual XmlAttribute InsertBefore (XmlAttribute newNode, XmlAttribute refNode)
123 if(newNode.OwnerDocument != ownerDocument)
124 throw new ArgumentException ("different document created this newNode.");
126 ownerDocument.onNodeInserting (newNode, null);
128 int pos = Nodes.Count;
131 for(int i=0; i<Nodes.Count; i++)
133 XmlNode n = Nodes [i] as XmlNode;
140 if(pos == Nodes.Count)
141 throw new XmlException ("refNode not found in this collection.");
143 SetNamedItem (newNode, pos);
145 ownerDocument.onNodeInserted (newNode, null);
150 public virtual XmlAttribute Prepend (XmlAttribute node)
152 return this.InsertAfter (node, null);
155 public virtual XmlAttribute Remove (XmlAttribute node)
158 throw new ArgumentException ("Specified node is null.");
159 if (node.OwnerDocument != ownerDocument)
160 throw new ArgumentException ("Specified node is in a different document.");
162 XmlAttribute retAttr = null;
163 foreach (XmlAttribute attr in Nodes) {
170 if(retAttr != null) {
171 ownerDocument.onNodeRemoving (node, null);
172 base.RemoveNamedItem (retAttr.LocalName, retAttr.NamespaceURI);
173 RemoveIdenticalAttribute (retAttr);
174 ownerDocument.onNodeRemoved (node, null);
176 // If it is default, then directly create new attribute.
177 if (!retAttr.Specified) {
178 XmlAttribute attr = ownerDocument.CreateAttribute (retAttr.Prefix,
179 retAttr.LocalName, retAttr.NamespaceURI);
181 foreach (XmlNode child in retAttr.ChildNodes)
182 attr.AppendChild (child);
183 this.SetNamedItem (attr);
188 public virtual void RemoveAll ()
191 while (current < Count) {
192 XmlAttribute attr = this [current];
195 // It is called for the purpose of event support.
200 public virtual XmlAttribute RemoveAt (int i)
204 return Remove ((XmlAttribute)Nodes [i]);
207 public override XmlNode SetNamedItem (XmlNode node)
210 throw new XmlException ("this AttributeCollection is read only.");
212 return AdjustIdenticalAttributes (node as XmlAttribute, base.SetNamedItem (node, -1) as XmlAttribute);
215 internal void AddIdenticalAttribute ()
217 SetIdenticalAttribute (false);
220 internal void RemoveIdenticalAttribute ()
222 SetIdenticalAttribute (true);
225 private void SetIdenticalAttribute (bool remove)
227 if (ownerElement == null)
230 // Check if new attribute's datatype is ID.
231 XmlDocumentType doctype = ownerDocument.DocumentType;
232 if (doctype == null || doctype.DTD == null)
234 DTDElementDeclaration elem = doctype.DTD.ElementDecls [ownerElement.Name];
235 foreach (XmlAttribute node in this) {
236 DTDAttributeDefinition attdef = elem == null ? null : elem.Attributes [node.Name];
237 if (attdef == null || attdef.Datatype.TokenizedType != XmlTokenizedType.ID)
241 if (ownerDocument.GetIdenticalAttribute (node.Value) != null) {
242 ownerDocument.RemoveIdenticalAttribute (node.Value);
246 // adding new identical attribute, but
247 // MS.NET is pity for ID support, so I'm wondering how to correct it...
248 if (ownerDocument.GetIdenticalAttribute (node.Value) != null)
249 throw new XmlException (String.Format (
250 "ID value {0} already exists in this document.", node.Value));
251 ownerDocument.AddIdenticalAttribute (node);
258 private XmlNode AdjustIdenticalAttributes (XmlNode node, XmlNode existing)
260 // If owner element is not appended to the document,
261 // ID table should not be filled.
262 if (ownerElement == null)
265 RemoveIdenticalAttribute (existing);
267 // Check if new attribute's datatype is ID.
268 XmlDocumentType doctype = node.OwnerDocument.DocumentType;
269 if (doctype == null || doctype.DTD == null)
271 DTDAttListDeclaration attList = doctype.DTD.AttListDecls [ownerElement.Name];
272 DTDAttributeDefinition attdef = attList == null ? null : attList.Get (node.Name);
273 if (attdef == null || attdef.Datatype.TokenizedType != XmlTokenizedType.ID)
276 // adding new identical attribute, but
277 // MS.NET is pity for ID support, so I'm wondering how to correct it...
278 if (ownerDocument.GetIdenticalAttribute (node.Value) != null)
279 throw new XmlException (String.Format (
280 "ID value {0} already exists in this document.", node.Value));
281 ownerDocument.AddIdenticalAttribute (node as XmlAttribute);
286 private XmlNode RemoveIdenticalAttribute (XmlNode existing)
288 // If owner element is not appended to the document,
289 // ID table should not be filled.
290 if (ownerElement == null)
293 if (existing != null) {
294 // remove identical attribute (if it is).
295 if (ownerDocument.GetIdenticalAttribute (existing.Value) != null)
296 ownerDocument.RemoveIdenticalAttribute (existing.Value);