-// System.Xml.XmlAttributeCollection.cs\r
-//\r
-// Author: Daniel Weber (daniel-weber@austin.rr.com)\r
-//\r
-// Implementation of abstract Xml.XmlAttributeCollection class\r
-//\r
-\r
-using System;\r
-using System.Collections;\r
-\r
-namespace System.Xml\r
-{\r
- /// <summary>\r
- /// A collection of Attributes that can be accessed by index or name(space)\r
- /// Derived from XmlNamedNodeMap\r
- /// <seealso cref="XmlNamedNodeMap"/>\r
- /// </summary>\r
- public class XmlAttributeCollection : XmlNamedNodeMap, ICollection\r
- {\r
-\r
- // ===== ICollection interface elements ===================================\r
- /// <summary>\r
- /// Private class to provide Synchronzed Access to the attribute list.\r
- /// </summary>\r
- private class SyncAttributes : XmlAttributeCollection\r
- {\r
- private XmlAttributeCollection _attributes;\r
-\r
- public SyncAttributes ( XmlAttributeCollection attributes )\r
- {\r
- _attributes = attributes;\r
- }\r
-\r
- public override bool IsSynchronized \r
- {\r
- get {return true; }\r
- }\r
-\r
- // Override all properties/methods that modify/read items\r
- // and lock them so they are thread-safe\r
- public override void CopyTo(Array array, int index)\r
- {\r
- lock (_attributes )\r
- { _attributes.CopyTo(array, index); }\r
- }\r
- \r
- public override XmlAttribute this[string name] \r
- {\r
- get {\r
- lock (_attributes ) { return _attributes[name]; }\r
- }\r
- }\r
-\r
- public override XmlAttribute this[int i] \r
- {\r
- get {\r
- lock (_attributes) { return _attributes[i]; }\r
- }\r
- }\r
-\r
- public override XmlAttribute Append( XmlAttribute node )\r
- {\r
- lock (_attributes)\r
- { return _attributes.Append( node ); }\r
- }\r
- \r
- public override void CopyTo(XmlAttribute[] array, int index)\r
- {\r
- lock (_attributes)\r
- { _attributes.CopyTo(array, index); }\r
- }\r
-\r
- public override XmlAttribute InsertAfter( \r
- XmlAttribute newNode, \r
- XmlAttribute refNode)\r
- {\r
- lock (_attributes)\r
- { return _attributes.InsertAfter( newNode, refNode ); }\r
- }\r
-\r
- public override XmlAttribute Prepend(XmlAttribute node)\r
- {\r
- lock (_attributes)\r
- { return _attributes.Prepend(node); }\r
- }\r
-\r
- public override XmlAttribute Remove(XmlAttribute node)\r
- {\r
- lock (_attributes)\r
- { return _attributes.Remove( node ); }\r
- }\r
-\r
- public override void RemoveAll()\r
- {\r
- lock (_attributes)\r
- { _attributes.RemoveAll(); }\r
- }\r
-\r
- public override XmlAttribute RemoveAt(int i)\r
- {\r
- lock (_attributes)\r
- { return _attributes.RemoveAt(i); }\r
- }\r
-\r
- public override XmlNode SetNamedItem(XmlNode node)\r
- {\r
- lock (_attributes)\r
- { return _attributes.SetNamedItem(node); }\r
- }\r
-\r
- // Even ToString, since someone could come along and blow away an\r
- // attribute while we're iterating...\r
- public override string ToString()\r
- {\r
- lock (_attributes) \r
- { return _attributes.ToString(); }\r
- }\r
-\r
- } // SynchAttributes\r
-\r
- /// <summary>\r
- /// Return true if access is synchronized (thread-safe)\r
- /// </summary>\r
- public virtual bool IsSynchronized \r
- {\r
- // This version of the class is not synchronized\r
- get\r
- {\r
- return false;\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// Return object used for synchronous access to class\r
- /// </summary>\r
- public object SyncRoot \r
- {\r
- get\r
- {\r
- return this;\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// Returns a thread-safe version of the attribute collection.\r
- /// </summary>\r
- /// <param name="attributes">Attribute collection to make thread-safe.</param>\r
- /// <returns>Thread-safe XmlAttributeCollection.</returns>\r
- public static XmlAttributeCollection Synchronized(XmlAttributeCollection attributes) \r
- {\r
- if (attributes == null) \r
- {\r
- throw new ArgumentNullException("Null XmlAttributeCollection passed to Synchronized()");\r
- }\r
-\r
- return new SyncAttributes(attributes);\r
- }\r
-\r
- /// <summary>\r
- /// Copy the XmlAttributeCollection into the passed array. Index is zero-based.\r
- /// </summary>\r
- /// <param name="array">Array to copy into</param>\r
- /// <param name="index">Index to start copying from</param>\r
- public virtual void CopyTo(Array array, int index)\r
- {\r
- // Let the Array handle all the errors, there's no risk to us\r
-\r
- // TODO - should we set OwnerElement to null in clone() in CopyTo(Array, int)? (yes, using setOwnerElement())\r
- int arrayIndex = 0;\r
- for (int i = index; i < FnodeList.Count; i++)\r
- {\r
- XmlAttribute e = FnodeList[i] as XmlAttribute;\r
- XmlAttribute theClone = e.Clone() as XmlAttribute;\r
- theClone.setOwnerElement(null);\r
- array.SetValue(theClone, arrayIndex);\r
- arrayIndex++;\r
- }\r
- }\r
- // XmlAttributeCollection Properties =================================\r
- /// <summary>\r
- /// Get the attribute with the specified name\r
- /// </summary>\r
- [System.Runtime.CompilerServices.IndexerName("ItemOf")]\r
- public virtual XmlAttribute this[string name] \r
- {\r
- get\r
- {\r
- return GetNamedItem(name) as XmlAttribute;\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// Get the attribute at the specified index. The Collection is zero-based.\r
- /// </summary>\r
- [System.Runtime.CompilerServices.IndexerName("ItemOf")]\r
- public virtual XmlAttribute this[int i] \r
- {\r
- get\r
- {\r
- return base.Item(i) as XmlAttribute;\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// Get the attribute with the specifed (localName, URI)\r
- /// </summary>\r
- [System.Runtime.CompilerServices.IndexerName("ItemOf")]\r
- public virtual XmlAttribute this[string localName, string namespaceURI] \r
- {\r
- get\r
- {\r
- return GetNamedItem(localName, namespaceURI) as XmlAttribute;\r
- }\r
- }\r
-\r
- // ============= Public methods =====================================\r
- /// <summary>\r
- /// Appends the specified node to the attribute list\r
- /// If the node is already in the list, it is moved to the end.\r
- /// If a node is in the list with the same name, the node is removed and the new node is added.\r
- /// </summary>\r
- /// <param name="node">Attribute node to append to the collection</param>\r
- /// <exception cref="ArgumentException">Node was created from a differant document or node is null</exception>\r
- /// <returns></returns>\r
- public virtual XmlAttribute Append( XmlAttribute node )\r
- {\r
- // TODO - node validation? (no)\r
- \r
- XmlAttribute retval = null;\r
-\r
- System.Diagnostics.Debug.Assert(node != null, "Null node passed to Append()");\r
-\r
- if (! FOwner.OwnerDocument.Equals(node.OwnerDocument))\r
- throw new ArgumentException("Cannot append node from another document");\r
-\r
- if (node.OwnerElement != null) \r
- throw new ArgumentException("Cannot append node from another document");\r
-\r
- foreach (XmlAttribute cur in FnodeList)\r
- {\r
- // If node is already in the collection, it is moved to the last position. \r
- if (cur.Equals(node))\r
- {\r
- retval = cur;\r
- FnodeList.Remove(cur);\r
- }\r
-\r
- //If an attribute with the same name is already present in the collection, \r
- // the original attribute is removed from the collection and \r
- // node is added to the end of the collection.\r
- if (cur.Name == node.Name)\r
- FnodeList.Remove(cur);\r
- }\r
-\r
- // add the new node to the end of the collection\r
- // set attribute owner element? (yes)\r
- node.setOwnerElement(FOwnerNode as XmlElement);\r
- FnodeList.Add(node);\r
-\r
- // return the removed item\r
- return retval;\r
- }\r
-\r
- /// <summary>\r
- /// Copies all attributes in collection into the array, starting at index.\r
- /// attribute index is zero-based.\r
- /// </summary>\r
- /// <exception cref="OverflowException">Thrown if insufficient room to copy all elements</exception>\r
- /// <param name="array">Array to copy XlmAttributes into</param>\r
- /// <param name="index">index to start copy</param>\r
- public virtual void CopyTo(XmlAttribute[] array, int index)\r
- {\r
- // Let the array handle all the errors, there's no risk to us\r
-\r
- // TODO - should we set OwnerElement to null in clone() in CopyTo(XmlAttribute[], int)? (yes, using setOwnerElement())\r
- int arrayIndex = 0;\r
- for (int i = index; i < FnodeList.Count; i++)\r
- {\r
- XmlAttribute e = FnodeList[i] as XmlAttribute;\r
- XmlAttribute theClone = e.Clone() as XmlAttribute;\r
- theClone.setOwnerElement(null);\r
- array[arrayIndex] = theClone;\r
- arrayIndex++;\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// Helper function since InsertBefore/After use exact same algorithm\r
- /// </summary>\r
- /// <param name="refNode"></param>\r
- /// <param name="newNode"></param>\r
- /// <param name="offset">offset to add to Insert (0 or 1)</param>\r
- /// <returns>Deleted attribute</returns>\r
- private XmlAttribute InsertHelper(XmlAttribute newNode, XmlAttribute refNode, int offset)\r
- {\r
- // TODO - validation? (no)\r
- if (refNode == null)\r
- throw new ArgumentNullException("Null refNode passed to InsertAfter()");\r
- if (newNode == null)\r
- throw new ArgumentNullException("Null newNode passed to InsertAfter()");\r
-\r
- if (! newNode.OwnerDocument.Equals(refNode.OwnerDocument) )\r
- throw new ArgumentException("Node to insert does not have same owner document as reference");\r
-\r
- // Logically, it makes no sense to insert node "A" after node "A",\r
- // since only one node "A" can be in the list - flag it as an error\r
- if (newNode.Name == refNode.Name)\r
- throw new ArgumentException("Node to insert has same name as reference node");\r
-\r
- // Other bizarre case is if refNode.Equals(newNode)\r
- // We'll flag this error after we check that refNode is in the list\r
- \r
- int refNodeIndex = -1;\r
- // Note that if newNode is in the list, then we'll get a name match\r
- int SameNameIndex = -1;\r
-\r
- for (int i = 0; i < FnodeList.Count; i++)\r
- {\r
- XmlAttribute curListNode = Item(i) as XmlAttribute;\r
- if (curListNode.Name == refNode.Name)\r
- refNodeIndex = i;\r
- \r
- if (curListNode.Name == newNode.Name)\r
- SameNameIndex = i;\r
- }\r
-\r
- if ( refNodeIndex == -1 )\r
- throw new ArgumentException("Attribute [" + refNode.Name + "] is not in Collection for InsertAfter()");\r
-\r
- // Check the obvious, InsertAfter( attr1, attr1);\r
- if (refNode.Equals( newNode ) )\r
- return newNode;\r
-\r
- XmlAttribute retval = null;\r
-\r
- if (SameNameIndex != -1)\r
- {\r
- // If this is newNode in the list, we'll insert it back in the right spot\r
- // If this is another node, just remove it\r
- retval = FnodeList[SameNameIndex] as XmlAttribute;\r
- FnodeList.RemoveAt(SameNameIndex);\r
- if ( SameNameIndex < refNodeIndex )\r
- refNodeIndex--;\r
- }\r
-\r
- FnodeList.Insert(refNodeIndex + offset, newNode);\r
-\r
- // TODO - set OwnerElement? (no)\r
- //node.setOwnerElement(FOwnerNode as XmlElement);\r
-\r
- // TODO - determine which node to return (deleted node)\r
- return retval;\r
- }\r
-\r
- /// <summary>\r
- /// Insert the specifed attribute immediately after the reference node.\r
- /// If an attribute with the same name is already in the collection, that attribute is removed and the new attribute inserted\r
- /// </summary>\r
- /// <exception cref="ArgumentException">Raised if newNode OwnerDocument differs from nodelist owner or refNode is not a member of the collection</exception>\r
- /// <param name="newNode">New attribute to insert</param>\r
- /// <param name="refNode">Reference node to insert new node after</param>\r
- /// <returns>Inserted node</returns>\r
- public virtual XmlAttribute InsertAfter( XmlAttribute newNode, XmlAttribute refNode)\r
- {\r
- return InsertHelper(newNode, refNode, 1);\r
- }\r
-\r
- /// <summary>\r
- /// Inserts newNode into the collection just before refNode.\r
- /// If a node with newNode.Name is already in the list, it is removed.\r
- /// </summary>\r
- /// <exception cref="ArgumentException">Thrown if inserted attribute created from different document, refNode not found in collection or\r
- /// refNode.Name == newNode.Name.</exception>\r
- /// <param name="newNode">Node to insert into list</param>\r
- /// <param name="refNode">Node to insert before</param>\r
- /// <returns>Deleted node, or null if no node was deleted.</returns>\r
- public virtual XmlAttribute InsertBefore(\r
- XmlAttribute newNode,\r
- XmlAttribute refNode\r
- )\r
- {\r
- return InsertHelper(newNode, refNode, 0);\r
- }\r
-\r
- /// <summary>\r
- /// Inserts the specified node as the first node in the collection\r
- /// </summary>\r
- /// <param name="node">XmlAttribute to insert</param>\r
- /// <exception cref="ArgumentException">If node is null, or owner document does not match collection.</exception>\r
- /// <returns>Node that was removed, or null if no node deleted.</returns>\r
- public virtual XmlAttribute Prepend(XmlAttribute node)\r
- {\r
- //TODO - node validation? (no)\r
- // TODO - set attribute owner element? (no)\r
- //node.setOwnerElement(FOwnerNode as XmlElement);\r
-\r
- if (FnodeList.Count > 0)\r
- {\r
- return InsertBefore(node, Item(0) as XmlAttribute);\r
- }\r
-\r
- if (node == null)\r
- throw new ArgumentException("Cannot prepend null node");\r
-\r
- if (! node.OwnerDocument.Equals(FOwner.OwnerDocument) )\r
- throw new ArgumentException("Node to prepend does not have same owner document as reference");\r
-\r
- FnodeList.Add(node); \r
- return node;\r
- }\r
-\r
- /// <summary>\r
- /// Removes the requested node from the collection.\r
- /// </summary>\r
- /// <param name="node">Node to remove</param>\r
- /// <returns>The node removed, or null if the node was not found in the collection.</returns>\r
- public virtual XmlAttribute Remove(XmlAttribute node)\r
- {\r
- for (int i = 0; i < FnodeList.Count; i++)\r
- {\r
- XmlAttribute e = FnodeList[i] as XmlAttribute;\r
- \r
- if (e.Equals(node))\r
- {\r
- FnodeList.RemoveAt(i);\r
- return node;\r
- }\r
- }\r
- // TODO - if node is a default, should we add it back with a default value? (no)\r
- return null;\r
- }\r
-\r
- /// <summary>\r
- /// Removes all attributes from the collection\r
- /// </summary>\r
- public virtual void RemoveAll()\r
- {\r
- // Can this be this easy?\r
- for (int i = FnodeList.Count - 1; i > 0; i--)\r
- {\r
- XmlAttribute e = FnodeList[i] as XmlAttribute;\r
- e.setOwnerElement(null);\r
- FnodeList.RemoveAt(i);\r
- }\r
-\r
- // TODO - Add default attributes back in in RemoveAll()? (no)\r
- }\r
-\r
- /// <summary>\r
- /// Removes the attribute at the specified index\r
- /// </summary>\r
- /// <param name="i">index of attribute to remove.</param>\r
- /// <returns>Removed node, or null if node not in collection</returns>\r
- public virtual XmlAttribute RemoveAt(int i)\r
- {\r
- if ((i < 0) | ( i >= FnodeList.Count))\r
- return null;\r
-\r
- // TODO - if default attribute removed in RemoveAt(), add it back? (no)\r
- XmlAttribute e = FnodeList[i] as XmlAttribute;\r
- FnodeList.RemoveAt(i);\r
- e.setOwnerElement(null);\r
- return e;\r
- }\r
-\r
- /// <summary>\r
- /// Adds a node to the collection using it's name. If a node with the same name exists,\r
- /// it is removed.\r
- /// </summary>\r
- /// <param name="node">XmlAttribute to add.</param>\r
- /// <returns>If a node replaces a named node, the replaced node is deleted and returned. \r
- /// Otherwise, null.</returns>\r
- public override XmlNode SetNamedItem(XmlNode node)\r
- {\r
- return base.SetNamedItem(node);\r
- }\r
-\r
- public override string ToString()\r
- {\r
- string retval = "System.Xml.XmlAttributeCollection ";\r
- if (FOwnerNode != null)\r
- retval += "OwnerElement: " + FOwnerNode.Name;\r
-\r
- foreach (XmlAttribute o in FnodeList)\r
- {\r
- retval += o.Name + "=" + o.Value;\r
- }\r
- return retval;\r
-\r
- }\r
- // ============= Constructors ========================================\r
- // TODO - change constructor to pass in IEnumerator?\r
- internal XmlAttributeCollection(XmlNode aOwner, XmlNode aOwnerNode, ArrayList nodeList) :\r
- base(aOwner, aOwnerNode, nodeList)\r
- {\r
- // Makes no sense to have namespace aware on attributes\r
- NamespaceAware = false;\r
- }\r
-\r
- internal XmlAttributeCollection ()\r
- {\r
- }\r
-\r
- }\r
-}
\ No newline at end of file
+//
+// System.Xml.XmlAttributeCollection
+//
+// Author:
+// Jason Diamond (jason@injektilo.org)
+// Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
+//
+// (C) 2002 Jason Diamond http://injektilo.org/
+// (C) 2002 Atsushi Enomoto
+//
+
+using System;
+using System.Collections;
+using Mono.Xml;
+
+namespace System.Xml
+{
+ public class XmlAttributeCollection : XmlNamedNodeMap, ICollection
+ {
+ XmlElement ownerElement;
+ XmlDocument ownerDocument;
+
+ internal XmlAttributeCollection (XmlNode parent) : base (parent)
+ {
+ ownerElement = parent as XmlElement;
+ ownerDocument = parent.OwnerDocument;
+ if(ownerElement == null)
+ throw new XmlException ("invalid construction for XmlAttributeCollection.");
+ }
+
+ bool ICollection.IsSynchronized {
+ get { return false; }
+ }
+
+ bool IsReadOnly {
+ get { return ownerElement.IsReadOnly; }
+ }
+
+ [System.Runtime.CompilerServices.IndexerName ("ItemOf")]
+ public virtual XmlAttribute this [string name] {
+ get {
+ return (XmlAttribute) GetNamedItem (name);
+ }
+ }
+
+ [System.Runtime.CompilerServices.IndexerName ("ItemOf")]
+ public virtual XmlAttribute this [int i] {
+ get {
+ return (XmlAttribute) Nodes [i];
+ }
+ }
+
+ [System.Runtime.CompilerServices.IndexerName ("ItemOf")]
+ public virtual XmlAttribute this [string localName, string namespaceURI] {
+ get {
+ return (XmlAttribute) GetNamedItem (localName, namespaceURI);
+ }
+ }
+
+ object ICollection.SyncRoot {
+ get { return this; }
+ }
+
+
+ public virtual XmlAttribute Append (XmlAttribute node)
+ {
+ XmlNode xmlNode = this.SetNamedItem (node);
+ return node;
+ }
+
+ public void CopyTo (XmlAttribute[] array, int index)
+ {
+ // assuming that Nodes is a correct collection.
+ for(int i=0; i<Nodes.Count; i++)
+ array [index + i] = Nodes [i] as XmlAttribute;
+ }
+
+ void ICollection.CopyTo (Array array, int index)
+ {
+ // assuming that Nodes is a correct collection.
+ array.CopyTo (Nodes.ToArray (typeof(XmlAttribute)), index);
+ }
+
+ public virtual XmlAttribute InsertAfter (XmlAttribute newNode, XmlAttribute refNode)
+ {
+ if(newNode.OwnerDocument != this.ownerDocument)
+ throw new ArgumentException ("different document created this newNode.");
+
+ ownerDocument.onNodeInserting (newNode, null);
+
+ int pos = Nodes.Count + 1;
+ if(refNode != null)
+ {
+ for(int i=0; i<Nodes.Count; i++)
+ {
+ XmlNode n = Nodes [i] as XmlNode;
+ if(n == refNode)
+ {
+ pos = i + 1;
+ break;
+ }
+ }
+ if(pos > Nodes.Count)
+ throw new XmlException ("refNode not found in this collection.");
+ }
+ else
+ pos = 0;
+ SetNamedItem (newNode, pos);
+
+ ownerDocument.onNodeInserted (newNode, null);
+
+ return newNode;
+ }
+
+ public virtual XmlAttribute InsertBefore (XmlAttribute newNode, XmlAttribute refNode)
+ {
+ if(newNode.OwnerDocument != ownerDocument)
+ throw new ArgumentException ("different document created this newNode.");
+
+ ownerDocument.onNodeInserting (newNode, null);
+
+ int pos = Nodes.Count;
+ if(refNode != null)
+ {
+ for(int i=0; i<Nodes.Count; i++)
+ {
+ XmlNode n = Nodes [i] as XmlNode;
+ if(n == refNode)
+ {
+ pos = i;
+ break;
+ }
+ }
+ if(pos == Nodes.Count)
+ throw new XmlException ("refNode not found in this collection.");
+ }
+ SetNamedItem (newNode, pos);
+
+ ownerDocument.onNodeInserted (newNode, null);
+
+ return newNode;
+ }
+
+ public virtual XmlAttribute Prepend (XmlAttribute node)
+ {
+ return this.InsertAfter (node, null);
+ }
+
+ public virtual XmlAttribute Remove (XmlAttribute node)
+ {
+ if (node == null)
+ throw new ArgumentException ("Specified node is null.");
+ if (node.OwnerDocument != ownerDocument)
+ throw new ArgumentException ("Specified node is in a different document.");
+
+ XmlAttribute retAttr = null;
+ foreach (XmlAttribute attr in Nodes) {
+ if (attr == node) {
+ retAttr = attr;
+ break;
+ }
+ }
+
+ if(retAttr != null) {
+ ownerDocument.onNodeRemoving (node, null);
+ base.RemoveNamedItem (retAttr.LocalName, retAttr.NamespaceURI);
+ RemoveIdenticalAttribute (retAttr);
+ ownerDocument.onNodeRemoved (node, null);
+ }
+ // If it is default, then directly create new attribute.
+ if (!retAttr.Specified) {
+ XmlAttribute attr = ownerDocument.CreateAttribute (retAttr.Prefix,
+ retAttr.LocalName, retAttr.NamespaceURI);
+ attr.SetDefault ();
+ foreach (XmlNode child in retAttr.ChildNodes)
+ attr.AppendChild (child);
+ this.SetNamedItem (attr);
+ }
+ retAttr.SetOwnerElement (null);
+ return retAttr;
+ }
+
+ public virtual void RemoveAll ()
+ {
+ int current = 0;
+ while (current < Count) {
+ XmlAttribute attr = this [current];
+ if (!attr.Specified)
+ current++;
+ // It is called for the purpose of event support.
+ Remove (attr);
+ }
+ }
+
+ public virtual XmlAttribute RemoveAt (int i)
+ {
+ if(Nodes.Count <= i)
+ return null;
+ return Remove ((XmlAttribute)Nodes [i]);
+ }
+
+ public override XmlNode SetNamedItem (XmlNode node)
+ {
+ if(IsReadOnly)
+ throw new XmlException ("this AttributeCollection is read only.");
+
+ XmlAttribute attr = node as XmlAttribute;
+ if (attr.OwnerElement != null)
+ throw new InvalidOperationException ("This attribute is already set to another element.");
+ attr.SetOwnerElement (ownerElement);
+ return AdjustIdenticalAttributes (node as XmlAttribute, base.SetNamedItem (node, -1) as XmlAttribute);
+ }
+
+ internal void AddIdenticalAttribute ()
+ {
+ SetIdenticalAttribute (false);
+ }
+
+ internal void RemoveIdenticalAttribute ()
+ {
+ SetIdenticalAttribute (true);
+ }
+
+ private void SetIdenticalAttribute (bool remove)
+ {
+ if (ownerElement == null)
+ return;
+
+ // Check if new attribute's datatype is ID.
+ XmlDocumentType doctype = ownerDocument.DocumentType;
+ if (doctype == null || doctype.DTD == null)
+ return;
+ DTDElementDeclaration elem = doctype.DTD.ElementDecls [ownerElement.Name];
+ foreach (XmlAttribute node in this) {
+ DTDAttributeDefinition attdef = elem == null ? null : elem.Attributes [node.Name];
+ if (attdef == null || attdef.Datatype.TokenizedType != XmlTokenizedType.ID)
+ continue;
+
+ if (remove) {
+ if (ownerDocument.GetIdenticalAttribute (node.Value) != null) {
+ ownerDocument.RemoveIdenticalAttribute (node.Value);
+ return;
+ }
+ } else {
+ // adding new identical attribute, but
+ // MS.NET is pity for ID support, so I'm wondering how to correct it...
+ if (ownerDocument.GetIdenticalAttribute (node.Value) != null)
+ throw new XmlException (String.Format (
+ "ID value {0} already exists in this document.", node.Value));
+ ownerDocument.AddIdenticalAttribute (node);
+ return;
+ }
+ }
+
+ }
+
+ private XmlNode AdjustIdenticalAttributes (XmlAttribute node, XmlNode existing)
+ {
+ // If owner element is not appended to the document,
+ // ID table should not be filled.
+ if (ownerElement == null)
+ return existing;
+
+ RemoveIdenticalAttribute (existing);
+
+ // Check if new attribute's datatype is ID.
+ XmlDocumentType doctype = node.OwnerDocument.DocumentType;
+ if (doctype == null || doctype.DTD == null)
+ return existing;
+ DTDAttListDeclaration attList = doctype.DTD.AttListDecls [ownerElement.Name];
+ DTDAttributeDefinition attdef = attList == null ? null : attList.Get (node.Name);
+ if (attdef == null || attdef.Datatype.TokenizedType != XmlTokenizedType.ID)
+ return existing;
+
+ // adding new identical attribute, but
+ // MS.NET is pity for ID support, so I'm wondering how to correct it...
+ if (ownerDocument.GetIdenticalAttribute (node.Value) != null)
+ throw new XmlException (String.Format (
+ "ID value {0} already exists in this document.", node.Value));
+ ownerDocument.AddIdenticalAttribute (node);
+
+ return existing;
+ }
+
+ private XmlNode RemoveIdenticalAttribute (XmlNode existing)
+ {
+ // If owner element is not appended to the document,
+ // ID table should not be filled.
+ if (ownerElement == null)
+ return existing;
+
+ if (existing != null) {
+ // remove identical attribute (if it is).
+ if (ownerDocument.GetIdenticalAttribute (existing.Value) != null)
+ ownerDocument.RemoveIdenticalAttribute (existing.Value);
+ }
+
+ return existing;
+ }
+ }
+}