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 // 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:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
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.
34 using System
.Collections
;
40 public sealed class XmlAttributeCollection
: XmlNamedNodeMap
, ICollection
42 public class XmlAttributeCollection
: XmlNamedNodeMap
, ICollection
45 XmlElement ownerElement
;
46 XmlDocument ownerDocument
;
48 internal XmlAttributeCollection (XmlNode parent
) : base (parent
)
50 ownerElement
= parent
as XmlElement
;
51 ownerDocument
= parent
.OwnerDocument
;
52 if(ownerElement
== null)
53 throw new XmlException ("invalid construction for XmlAttributeCollection.");
56 bool ICollection
.IsSynchronized
{
61 get { return ownerElement.IsReadOnly; }
64 [System
.Runtime
.CompilerServices
.IndexerName ("ItemOf")]
66 public XmlAttribute
this [string name
] {
68 public virtual XmlAttribute
this [string name
] {
71 return (XmlAttribute
) GetNamedItem (name
);
75 [System
.Runtime
.CompilerServices
.IndexerName ("ItemOf")]
77 public XmlAttribute
this [int i
] {
79 public virtual XmlAttribute
this [int i
] {
82 return (XmlAttribute
) Nodes
[i
];
86 [System
.Runtime
.CompilerServices
.IndexerName ("ItemOf")]
88 public XmlAttribute
this [string localName
, string namespaceURI
] {
90 public virtual XmlAttribute
this [string localName
, string namespaceURI
] {
93 return (XmlAttribute
) GetNamedItem (localName
, namespaceURI
);
97 object ICollection
.SyncRoot
{
102 public XmlAttribute
Append (XmlAttribute node
)
104 public virtual XmlAttribute
Append (XmlAttribute node
)
107 XmlNode xmlNode
= this.SetNamedItem (node
);
111 public void CopyTo (XmlAttribute
[] array
, int index
)
113 // assuming that Nodes is a correct collection.
114 for(int i
=0; i
<Nodes
.Count
; i
++)
115 array
[index
+ i
] = Nodes
[i
] as XmlAttribute
;
118 void ICollection
.CopyTo (Array array
, int index
)
120 // assuming that Nodes is a correct collection.
121 array
.CopyTo (Nodes
.ToArray (typeof(XmlAttribute
)), index
);
125 public XmlAttribute
InsertAfter (XmlAttribute newNode
, XmlAttribute refNode
)
127 public virtual XmlAttribute
InsertAfter (XmlAttribute newNode
, XmlAttribute refNode
)
130 if (refNode
== null) {
131 if (Nodes
.Count
== 0)
132 return InsertBefore (newNode
, null);
134 return InsertBefore (newNode
, this [0]);
136 for (int i
= 0; i
< Nodes
.Count
; i
++)
137 if (refNode
== Nodes
[i
])
138 return InsertBefore (newNode
, Nodes
.Count
== i
+ 1 ? null : this [i
+ 1]);
140 throw new ArgumentException ("refNode not found in this collection.");
144 public XmlAttribute
InsertBefore (XmlAttribute newNode
, XmlAttribute refNode
)
146 public virtual XmlAttribute
InsertBefore (XmlAttribute newNode
, XmlAttribute refNode
)
149 if (newNode
.OwnerDocument
!= ownerDocument
)
150 throw new ArgumentException ("different document created this newNode.");
152 ownerDocument
.onNodeInserting (newNode
, null);
154 int pos
= Nodes
.Count
;
155 if (refNode
!= null) {
156 for (int i
= 0; i
< Nodes
.Count
; i
++) {
157 XmlNode n
= Nodes
[i
] as XmlNode
;
163 if (pos
== Nodes
.Count
)
164 throw new ArgumentException ("refNode not found in this collection.");
166 SetNamedItem (newNode
, pos
, false);
168 ownerDocument
.onNodeInserted (newNode
, null);
174 public XmlAttribute
Prepend (XmlAttribute node
)
176 public virtual XmlAttribute
Prepend (XmlAttribute node
)
179 return this.InsertAfter (node
, null);
183 public XmlAttribute
Remove (XmlAttribute node
)
185 public virtual XmlAttribute
Remove (XmlAttribute node
)
189 throw new ArgumentException ("This attribute collection is read-only.");
191 throw new ArgumentException ("Specified node is null.");
192 if (node
.OwnerDocument
!= ownerDocument
)
193 throw new ArgumentException ("Specified node is in a different document.");
194 if (node
.OwnerElement
!= this.ownerElement
)
195 throw new ArgumentException ("The specified attribute is not contained in the element.");
197 XmlAttribute retAttr
= null;
198 for (int i
= 0; i
< Nodes
.Count
; i
++) {
199 XmlAttribute attr
= (XmlAttribute
) Nodes
[i
];
206 if(retAttr
!= null) {
207 ownerDocument
.onNodeRemoving (node
, ownerElement
);
208 base.RemoveNamedItem (retAttr
.LocalName
, retAttr
.NamespaceURI
);
209 RemoveIdenticalAttribute (retAttr
);
210 ownerDocument
.onNodeRemoved (node
, ownerElement
);
212 // If it is default, then directly create new attribute.
213 DTDAttributeDefinition def
= retAttr
.GetAttributeDefinition ();
214 if (def
!= null && def
.DefaultValue
!= null) {
215 XmlAttribute attr
= ownerDocument
.CreateAttribute (
216 retAttr
.Prefix
, retAttr
.LocalName
, retAttr
.NamespaceURI
);
217 attr
.Value
= def
.DefaultValue
;
219 this.SetNamedItem (attr
);
221 retAttr
.SetOwnerElement (null);
226 public void RemoveAll ()
228 public virtual void RemoveAll ()
232 while (current
< Count
) {
233 XmlAttribute attr
= this [current
];
236 // It is called for the purpose of event support.
242 public XmlAttribute
RemoveAt (int i
)
244 public virtual XmlAttribute
RemoveAt (int i
)
249 return Remove ((XmlAttribute
)Nodes
[i
]);
252 public override XmlNode
SetNamedItem (XmlNode node
)
255 throw new ArgumentException ("this AttributeCollection is read only.");
257 XmlAttribute attr
= node
as XmlAttribute
;
258 if (attr
.OwnerElement
!= null)
259 throw new ArgumentException ("This attribute is already set to another element.");
261 ownerElement
.OwnerDocument
.onNodeInserting (node
, ownerElement
);
263 attr
.SetOwnerElement (ownerElement
);
264 XmlNode n
= AdjustIdenticalAttributes (node
as XmlAttribute
, base.SetNamedItem (node
, -1, false));
266 ownerElement
.OwnerDocument
.onNodeInserted (node
, ownerElement
);
268 return n
as XmlAttribute
;
271 internal void AddIdenticalAttribute ()
273 SetIdenticalAttribute (false);
276 internal void RemoveIdenticalAttribute ()
278 SetIdenticalAttribute (true);
281 private void SetIdenticalAttribute (bool remove)
283 if (ownerElement
== null)
286 // Check if new attribute's datatype is ID.
287 XmlDocumentType doctype
= ownerDocument
.DocumentType
;
288 if (doctype
== null || doctype
.DTD
== null)
290 DTDElementDeclaration elem
= doctype
.DTD
.ElementDecls
[ownerElement
.Name
];
291 for (int i
= 0; i
< Nodes
.Count
; i
++) {
292 XmlAttribute node
= (XmlAttribute
) Nodes
[i
];
293 DTDAttributeDefinition attdef
= elem
== null ? null : elem
.Attributes
[node
.Name
];
294 if (attdef
== null || attdef
.Datatype
.TokenizedType
!= XmlTokenizedType
.ID
)
298 if (ownerDocument
.GetIdenticalAttribute (node
.Value
) != null) {
299 ownerDocument
.RemoveIdenticalAttribute (node
.Value
);
303 // adding new identical attribute, but
304 // MS.NET is pity for ID support, so I'm wondering how to correct it...
305 if (ownerDocument
.GetIdenticalAttribute (node
.Value
) != null)
306 throw new XmlException (String
.Format (
307 "ID value {0} already exists in this document.", node
.Value
));
308 ownerDocument
.AddIdenticalAttribute (node
);
315 private XmlNode
AdjustIdenticalAttributes (XmlAttribute node
, XmlNode existing
)
317 // If owner element is not appended to the document,
318 // ID table should not be filled.
319 if (ownerElement
== null)
322 RemoveIdenticalAttribute (existing
);
324 // Check if new attribute's datatype is ID.
325 XmlDocumentType doctype
= node
.OwnerDocument
.DocumentType
;
326 if (doctype
== null || doctype
.DTD
== null)
328 DTDAttListDeclaration attList
= doctype
.DTD
.AttListDecls
[ownerElement
.Name
];
329 DTDAttributeDefinition attdef
= attList
== null ? null : attList
.Get (node
.Name
);
330 if (attdef
== null || attdef
.Datatype
.TokenizedType
!= XmlTokenizedType
.ID
)
333 // adding new identical attribute, but
334 // MS.NET is pity for ID support, so I'm wondering how to correct it...
335 if (ownerDocument
.GetIdenticalAttribute (node
.Value
) != null)
336 throw new XmlException (String
.Format (
337 "ID value {0} already exists in this document.", node
.Value
));
338 ownerDocument
.AddIdenticalAttribute (node
);
343 private XmlNode
RemoveIdenticalAttribute (XmlNode existing
)
345 // If owner element is not appended to the document,
346 // ID table should not be filled.
347 if (ownerElement
== null)
350 if (existing
!= null) {
351 // remove identical attribute (if it is).
352 if (ownerDocument
.GetIdenticalAttribute (existing
.Value
) != null)
353 ownerDocument
.RemoveIdenticalAttribute (existing
.Value
);