//
// System.Xml.XmlNamedNodeMap.cs
//
// Author: Daniel Weber (daniel-weber@austin.rr.com)
//
// Implementation of abstract System.Xml.XmlNamedNodeMap class
//
// Credit for source code to Open XML 2.3.17
using System;
using System.Collections;
namespace System.Xml
{
public class XmlNamedNodeMap : IEnumerable
{
//=============== Class data structures ====================================
// Use weak references for owners to prevent circular linkage
protected XmlNode FOwner;
protected XmlNode FOwnerNode;
protected ArrayList FnodeList;
private bool FNamespaceAware;
private bool FIsReadonly;
// ============ Public Properties =====================================
//=====================================================================
///
/// Get the count of nodes in the map
///
public virtual int Count
{
get
{
return FnodeList.Count;
}
}
// ============ Public Methods =====================================
///
/// Get the node at the given index. Index is 0-based, top element is Count - 1
///
/// index into array of XmlNode to get
/// XmlNode at index, or null if index out of range
public virtual XmlNode Item(int index)
{
try
{
return FnodeList[index] as XmlNode; //FnodeList.Item(index);
}
catch (ArgumentOutOfRangeException)
{
return null;
}
}
///
/// Get the node with the given name
/// If the nodes have an associated namespace, use (localName, namespaceURI) instead
///
/// name of the node to return
/// XmlNode, or null if node not found
public virtual XmlNode GetNamedItem(string name)
{
// Can't return without a namespace to lookup
// SDK doesn't specify an exception to throw, so just return null
if (FNamespaceAware)
return null;
foreach (XmlNode cur in FnodeList)
{
if (cur.Name == name)
return cur;
}
return null;
}
///
/// Get the node with localName in given namespaceURI
///
/// localName of node
/// namespace of node
/// XmlNode at location, or null
public virtual XmlNode GetNamedItem(string localName, string namespaceURI)
{
// No namespace data in objects, can't lookup
// SDK doesn't specify an exception to throw, so just return null
if (! FNamespaceAware)
return null;
foreach (XmlNode cur in FnodeList)
{
if ((cur.Name == localName) & (cur.NamespaceURI == namespaceURI))
return cur;
}
return null;
}
///
/// Get the enumerator for the node map
///
/// Enumerator
public virtual IEnumerator GetEnumerator()
{
return FnodeList.GetEnumerator();
}
///
/// Removes the node with given name from the Map and returns it.
/// If the node is namespace aware, use RemoveNamedItem(localName, namespaceURI) instead
///
/// node name
/// Removed node, or null if node not found
public virtual XmlNode RemoveNamedItem(string name)
{
// Can't return without a namespace to lookup
// SDK doesn't specify an exception to throw, so just return null
if (FNamespaceAware)
return null;
for (int i = 0; i < FnodeList.Count; i++)
{
XmlNode cur = FnodeList[i] as XmlNode;
if (cur.Name == name)
{
FnodeList.RemoveAt(i);
return cur;
}
}
return null;
}
///
/// Removes the node with given localName in namespaceURI
/// If this XmlNamedNodeMap is not namespace aware, use RemoveNamedItem(name) instead.
///
/// local node name
/// namespace node is in
/// Node that was removed, or null if no node found
public virtual XmlNode RemoveNamedItem(string localName, string namespaceURI)
{
// No namespace data in objects, can't lookup
// SDK doesn't specify an exception to throw, so just return null
if (! FNamespaceAware) // NOT _namespaceAware
return null;
for (int i = 0; i < FnodeList.Count; i++)
{
XmlNode cur = FnodeList[i] as XmlNode;
if ((cur.Name == localName) & (cur.NamespaceURI == namespaceURI))
{
FnodeList.RemoveAt(i);
return cur;
}
}
return null;
}
///
/// Adds the passed node using the name property
/// If a node with this name exists, it is returned, otherwise null is returned.
///
/// Raised if node was created from another docuement, or XmlNamedNodeMap is read-only
/// Node is an XmlAttribute of another XmlElement
///
///
public virtual XmlNode SetNamedItem(XmlNode node)
{
XmlNode retValue ; // Return value of method
// Can't add to read-only Map
if (FIsReadonly)
throw new ArgumentException("Attempt to add node to read-only Node Map");
//if FOwner.OwnerDocument <> arg.OwnerDocument then raise EWrong_Document_Err
if (! FOwner.OwnerDocument.Equals(node.OwnerDocument))
throw new ArgumentException("Cannot add node from another document");
// if FNamespaceAware then raise ENamespace_Err.create('Namespace error.');
if (FNamespaceAware)
throw new InvalidOperationException("Invalid Operation: Can't add node by name to namespace aware node list");
// Can't assign node that has a parent
// TODO - is this check required/valid in the .NET API?
//if assigned(arg.parentNode) then raise EInuse_Node_Err.create('In use node error.');
if (node.ParentNode != null)
throw new ArgumentException("In use node error");
// XmlAttribute cannot be assigned to an element
//if arg.NodeType = ntAttribute_Node
// then if assigned((arg as TdomAttr).OwnerElement)
// then if (arg as TdomAttr).OwnerElement <> FOwnerNode then raise EInuse_Attribute_Err.create('Inuse attribute error.');
if (node is XmlAttribute)
{
if ((node as XmlAttribute).OwnerElement != null)
{
if (! FOwnerNode.Equals( (node as XmlAttribute).OwnerElement ))
throw new InvalidOperationException("XmlAttribute is assigned to another element");
}
}
/*
if not (arg.NodeType in FAllowedNodeTypes) then raise EHierarchy_Request_Err.create('Hierarchy request error.');
*/
if ( GetNamedItem(node.Name) != null)
{
retValue = RemoveNamedItem(node.Name);
}
else
{
retValue = null;
}
FnodeList.Add(node);
// TODO - check that owner is set properly on adding an attribute node
return retValue;
}
// ============ Constructors =========================================
internal XmlNamedNodeMap(XmlNode aOwner, XmlNode aOwnerNode, ArrayList nodeList)
{
if (nodeList == null)
nodeList = new ArrayList();
else
FnodeList = nodeList;
FOwner = aOwner;
FOwnerNode = aOwnerNode;
FIsReadonly = false;
FNamespaceAware = false;
}
// Add a default costructor to satisfy Visual Studio....
// TODO - figure out a way to get rid of default constructor on XmlNamedNodeMap()
internal XmlNamedNodeMap()
{
FnodeList = new ArrayList();
FOwner = null;
FOwnerNode = null;
FIsReadonly = false;
FNamespaceAware = false;
}
// ============ Internal Properties ===================================
//=====================================================================
internal bool IsReadOnly
{
get
{
return FIsReadonly;
}
set
{
FIsReadonly = value;
}
}
internal bool NamespaceAware
{
get
{
return FNamespaceAware;
}
set
{
FNamespaceAware = value;
}
}
}
}