-// -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-\r
-//\r
-// System.Xml.XmlNode\r
-//\r
-// Author:\r
-// Daniel Weber (daniel-weber@austin.rr.com)\r
-//\r
-// (C) 2001 Daniel Weber\r
-\r
-using System;\r
-using System.Collections;\r
-using System.Xml.XPath;\r
-\r
-namespace System.Xml \r
-{\r
- public abstract class XmlNode : ICloneable, IEnumerable, IXPathNavigable \r
- {\r
- //======= Private data members ==============================================\r
- private XmlNodeListAsArrayList _childNodes;\r
- protected XmlDocument FOwnerDocument;\r
- protected XmlNode _parent;\r
-\r
- // Names of node\r
- // for <foo:bar xmlns:foo="http://www.foobar.com/schema/foobar">... </foo:bar>\r
- // qualified name: foo:bar\r
- // namespaceURI = "http://www.foobar.com/schema/foobar"\r
- // localName = bar\r
- // prefix = foo\r
- // Note that namespaces can be nested (child namespace != parent namespace)\r
- // namespaces are optional\r
- protected string Fname;\r
- protected string FnamespaceURI;\r
- protected string Fprefix;\r
- protected string FlocalName;\r
-\r
- // baseURI holds the location from which the document was loaded\r
- // If the node was created from a document at c:\tmp.xml, then that's what will be here\r
- protected string FbaseURI;\r
-\r
- // value of the node (overriden in classes that do something different)\r
- // default behavior is just to store it\r
- protected string Fvalue;\r
- \r
- //=====================================================================\r
- // ============ Properties ============================================\r
- //=====================================================================\r
- /// <summary>\r
- /// Get the XmlAttributeCollection representing the attributes\r
- /// on the node type. Returns null if the node type is not XmlElement.\r
- /// </summary>\r
- public virtual XmlAttributeCollection Attributes \r
- {\r
- get \r
- {\r
- return null;\r
- }\r
- }\r
- /// <summary>\r
- /// Return the base Uniform Resource Indicator (URI) used to resolve\r
- /// this node, or String.Empty.\r
- /// </summary>\r
- public virtual string BaseURI \r
- {\r
- get \r
- {\r
- return FbaseURI;\r
- }\r
-\r
- }\r
- /// <summary>\r
- /// Return all child nodes of this node. If there are no children,\r
- /// return an empty XmlNodeList;\r
- /// </summary>\r
- public virtual XmlNodeList ChildNodes \r
- {\r
- get \r
- {\r
- if (_childNodes == null)\r
- _childNodes = new XmlNodeListAsArrayList();\r
-\r
- return _childNodes as XmlNodeList;\r
- }\r
- }\r
- \r
- /// <summary>\r
- /// Return first child node as XmlNode or null\r
- /// if the node has no children\r
- /// </summary>\r
- public virtual XmlNode FirstChild \r
- {\r
- get\r
- {\r
- if (ChildNodes.Count == 0)\r
- return null;\r
- else\r
- return ChildNodes[0];\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// Return true if the node has children\r
- /// </summary>\r
- public virtual bool HasChildNodes \r
- {\r
- get \r
- {\r
- if (ChildNodes.Count == 0)\r
- return true;\r
- else\r
- return false;\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// Get or Set the concatenated values of node and children\r
- /// </summary>\r
- public virtual string InnerText\r
- {\r
- get\r
- {\r
- // TODO - implement set InnerText()\r
- throw new NotImplementedException();\r
- }\r
-\r
- set \r
- {\r
- // TODO - implement set InnerText()\r
- throw new NotImplementedException();\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// Get/Set the XML representing just the child nodes of this node\r
- /// </summary>\r
- public virtual string InnerXml\r
- {\r
- get\r
- {\r
- // TODO - implement set InnerXml()\r
- throw new NotImplementedException();\r
- }\r
-\r
- set \r
- {\r
- // TODO - implement set InnerXml()\r
- throw new NotImplementedException();\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// Property Get - true if node is read-only\r
- /// </summary>\r
- public virtual bool IsReadOnly\r
- {\r
- get\r
- {\r
- return OwnerDocument.IsReadOnly;\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// Return the child element named [string]. Returns XmlElement\r
- /// Indexer for XmlNode class.\r
- /// </summary>\r
- [System.Runtime.CompilerServices.CSharp.IndexerName("Item")]\r
- public virtual XmlElement this [String index]\r
- {\r
- get \r
- {\r
- // TODO - implement XmlNode.Item(string)\r
- throw new NotImplementedException();\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// Get the last child node, or null if there are no nodes\r
- /// </summary>\r
- public virtual XmlNode LastChild\r
- {\r
- get\r
- {\r
- if (_childNodes.Count == 0)\r
- return null;\r
- else\r
- return _childNodes.Item(_childNodes.Count - 1);\r
- }\r
-\r
- }\r
-\r
- /// <summary>\r
- /// Returns the local name of the node with qualifiers removed\r
- /// LocalName of ns:elementName = "elementName"\r
- /// </summary>\r
- public abstract string LocalName {get;}\r
-\r
- /// <summary>\r
- /// Get the qualified node name\r
- /// derived classes must implement as behavior varies\r
- /// by tag type.\r
- /// </summary>\r
- public abstract string Name { get; }\r
-\r
- /// <summary>\r
- /// Get the namespace URI or String.Empty if none\r
- /// </summary>\r
- public virtual string NamespaceURI\r
- {\r
- get\r
- {\r
- // TODO - implement Namespace URI, or determine abstractness\r
- throw new NotImplementedException("XmlNode.NamespaceURI not implemented");\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// Get the node immediatelly following this node, or null\r
- /// </summary>\r
- public virtual XmlNode NextSibling \r
- {\r
- get\r
- {\r
- \r
- if (_parent != null)\r
- {\r
- XmlNodeListAsArrayList children = _parent.ChildNodes as XmlNodeListAsArrayList;\r
- int ourIndex = children.data.IndexOf(this);\r
- return children[ourIndex + 1];\r
- }\r
- else\r
- return null;\r
- }\r
- }\r
-\r
- public virtual XmlNodeType NodeType \r
- {\r
- get\r
- {\r
- return XmlNodeType.None;\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// Return the string representing this node and all it's children\r
- /// </summary>\r
- public virtual string OuterXml\r
- {\r
- get\r
- {\r
- // TODO - implement OuterXml {get;}\r
- throw new NotImplementedException();\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// Return owning document.\r
- /// If this nodeType is a document, return null\r
- /// </summary>\r
- public virtual XmlDocument OwnerDocument\r
- {\r
- get\r
- {\r
- return FOwnerDocument;\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// Returns the parent node, or null\r
- /// Return value depends on superclass node type\r
- /// </summary>\r
- public virtual XmlNode ParentNode\r
- {\r
- get\r
- {\r
- return _parent;\r
- }\r
- }\r
- \r
- /// <summary>\r
- /// set/get the namespace prefix for this node, or \r
- /// string.empty if it does not exist\r
- /// </summary>\r
- public virtual string Prefix \r
- {\r
- get\r
- {\r
- return Fprefix;\r
- }\r
- \r
- set\r
- {\r
- // TODO - validation on XmlNode.Prefix {set;}? (no)\r
- Fprefix = value;\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// The preceding XmlNode or null\r
- /// </summary>\r
- public virtual XmlNode PreviousSibling {\r
- get\r
- {\r
- if (_parent != null)\r
- {\r
- XmlNodeListAsArrayList children = _parent.ChildNodes as XmlNodeListAsArrayList;\r
- int ourIndex = children.data.IndexOf(this);\r
- return children[ourIndex - 1];\r
- }\r
- else\r
- return null;\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// Get/Set the value for this node\r
- /// </summary>\r
- public virtual string Value \r
- {\r
- get\r
- {\r
- return Fvalue;\r
- }\r
- \r
- set\r
- {\r
- Fvalue = value;\r
- }\r
- }\r
-\r
- //=====================================================================\r
- //======= Methods =====================================================\r
- //=====================================================================\r
- /// <summary>\r
- /// Appends the specified node to the end of the child node list\r
- /// </summary>\r
- /// <param name="newChild"></param>\r
- /// <returns></returns>\r
- public virtual XmlNode AppendChild (XmlNode newChild)\r
- {\r
- return InsertBefore(newChild, null);\r
- }\r
-\r
- /// <summary>\r
- /// Return a clone of this node\r
- /// </summary>\r
- /// <returns></returns>\r
- public virtual object Clone()\r
- {\r
- // TODO - implement XmlNode.Clone() as object\r
- throw new NotImplementedException("object XmlNode.Clone() not implmented");\r
- }\r
-\r
- /// <summary>\r
- /// Return a clone of the node\r
- /// </summary>\r
- /// <param name="deep">Make copy of all children</param>\r
- /// <returns>Cloned node</returns>\r
- public abstract XmlNode CloneNode( bool deep);\r
-\r
- /// <summary>\r
- /// Return an XPathNavigator for navigating this node\r
- /// </summary>\r
- /// <returns></returns>\r
- public System.Xml.XPath.XPathNavigator CreateNavigator()\r
- {\r
- // TODO - implement CreateNavigator()\r
- throw new NotImplementedException();\r
- }\r
-\r
- /// <summary>\r
- /// Provide support for "for each" \r
- /// </summary>\r
- /// <returns></returns>\r
- public IEnumerator GetEnumerator()\r
- {\r
- return _childNodes.data.GetEnumerator();\r
- }\r
-\r
- /// <summary>\r
- /// Look up the closest namespace for this node that is in scope for the given prefix\r
- /// </summary>\r
- /// <param name="prefix"></param>\r
- /// <returns>Namespace URI</returns>\r
- public virtual string GetNamespaceOfPrefix(string prefix)\r
- {\r
- // TODO - implement GetNamespaceOfPrefix()\r
- throw new NotImplementedException();\r
- }\r
-\r
- /// <summary>\r
- /// Get the closest xmlns declaration for the given namespace URI that is in scope.\r
- /// Returns the prefix defined in that declaration.\r
- /// </summary>\r
- /// <param name="namespaceURI"></param>\r
- /// <returns></returns>\r
- public virtual string GetPrefixOfNamespace(string namespaceURI)\r
- {\r
- // TODO - implement GetPrefixOfNamespace\r
- throw new NotImplementedException();\r
- }\r
- \r
- /// <summary>\r
- /// Insert newChild directly after the reference node.\r
- /// If refChild is null, newChild is inserted at the beginning of childnodes.\r
- /// If newChild is a document fragment, all nodes are inserted after refChild.\r
- /// If newChild is already in the tree, it is first removed.\r
- /// </summary>\r
- /// <exception cref="ArgumentException">NewChild was created from differant document.\r
- /// RefChild not a child of this node or null.\r
- /// Node is read-only</exception>\r
- /// <exception cref="InvalidOperationException">Node is of type that does not have children\r
- /// Node to insert is an ancestor of this node.</exception>\r
- /// <param name="newChild">Child node to insert.</param>\r
- /// <param name="refChild">Reference node to insert after</param>\r
- /// <returns>Removed node, or null if no node removed.</returns>\r
- public virtual XmlNode InsertAfter(XmlNode newChild, XmlNode refChild)\r
- {\r
- // Checks parent not ancestor, arguments valid, etc. Throws exception on error\r
- InsertionCheck(newChild, refChild);\r
-\r
- // Scan the node list, looking for refChild and seeing if newChild is in the list\r
- // Note that if refNode is null (prepend), we don't want to do the .Equals(null)\r
- XmlNode retval = null;\r
- int refNodeIndex = -1;\r
- \r
- for (int i = 0; i < _childNodes.Count; i++)\r
- {\r
- XmlNode e = _childNodes.data[i] as XmlNode;\r
- if (e.Equals(newChild))\r
- {\r
- retval = e;\r
- FOwnerDocument.onNodeRemoving(newChild, newChild.ParentNode);\r
- _childNodes.data.RemoveAt(i);\r
- newChild.setParent(null);\r
- FOwnerDocument.onNodeRemoved(newChild, null);\r
- break;\r
- \r
- }\r
-\r
- if ( (refChild != null ) & ( e.Equals(refChild) ) )\r
- {\r
- refNodeIndex = i;\r
-\r
- if (retval != null)\r
- break;\r
- }\r
- }\r
-\r
- if ( ( refNodeIndex == -1 ) & (refChild != null) )\r
- throw new ArgumentException("Reference node not found (and not null) in call to XmlNode.InsertAfter()");\r
-\r
- FOwnerDocument.onNodeInserting(newChild, this);\r
-\r
- if (refChild == null)\r
- refNodeIndex = 0;\r
- else\r
- refNodeIndex++; // insert after reference...\r
-\r
- if (newChild.NodeType == XmlNodeType.DocumentFragment)\r
- {\r
- // Insert all children, starting from refNodeIndex (0,1,2...n)\r
- for (int i = 0; i < newChild.ChildNodes.Count; i++)\r
- {\r
- XmlNode e = newChild.ChildNodes[i] as XmlNode;\r
- FOwnerDocument.onNodeInserting(e, this);\r
- _childNodes.data.Insert(refNodeIndex, newChild.ChildNodes[i]);\r
- e.setParent(this);\r
- FOwnerDocument.onNodeInserted(newChild, this);\r
- refNodeIndex ++;\r
- }\r
- }\r
- else\r
- {\r
- FOwnerDocument.onNodeInserting(newChild, this);\r
- _childNodes.data.Insert(refNodeIndex, newChild);\r
- newChild.setParent(this);\r
- FOwnerDocument.onNodeInserted(newChild, this);\r
- }\r
-\r
- return retval;\r
- }\r
- \r
- /// <summary>\r
- /// Insert newChild directly before the reference node.\r
- /// If refChild is null, newChild is inserted at the end of childnodes.\r
- /// If newChild is a document fragment, all nodes are inserted before refChild.\r
- /// If newChild is already in the tree, it is first removed.\r
- /// </summary>\r
- /// <exception cref="ArgumentException">NewChild was created from different document.\r
- /// RefChild not a child of this node, or is null.\r
- /// Node is read-only</exception>\r
- /// <exception cref="InvalidOperationException">Node is of type that does not have children.\r
- /// Node to insert is an ancestor of this node.</exception>\r
- /// <param name="newChild">Child node to insert.</param>\r
- /// <param name="refChild">Reference node to insert after</param>\r
- /// <returns>Removed node, or null if no node removed.</returns>\r
- public virtual XmlNode InsertBefore(XmlNode newChild, XmlNode refChild)\r
- {\r
- // Checks parent not ancestor, arguments valid, etc. Throws exception on error\r
- InsertionCheck(newChild, refChild);\r
-\r
- // Scan the node list, looking for refChild and seeing if newChild is in the list\r
- XmlNode retval = null;\r
- int refNodeIndex = -1;\r
- \r
- for (int i = 0; i < _childNodes.Count; i++)\r
- {\r
- XmlNode e = _childNodes.data[i] as XmlNode;\r
- if (e.Equals(newChild))\r
- {\r
- retval = e;\r
- FOwnerDocument.onNodeRemoving(newChild, newChild.ParentNode);\r
- _childNodes.data.RemoveAt(i);\r
- newChild.setParent(null);\r
- FOwnerDocument.onNodeRemoved(newChild, null);\r
- break;\r
- }\r
-\r
- if ( (refChild != null ) & ( e.Equals(refChild) ) )\r
- {\r
- refNodeIndex = i;\r
-\r
- if (retval != null)\r
- break;\r
- }\r
- }\r
-\r
- if ( ( refNodeIndex == -1 ) & (refChild != null) )\r
- throw new ArgumentException("Reference node not found (and not null) in call to XmlNode.InsertAfter()");\r
-\r
- if (refChild == null)\r
- refNodeIndex = _childNodes.Count;\r
-\r
- if (newChild.NodeType == XmlNodeType.DocumentFragment)\r
- {\r
- // Insert all children, starting from refNodeIndex (0,1,2...n)\r
- for (int i = 0; i < newChild.ChildNodes.Count; i++)\r
- {\r
- XmlNode e = newChild.ChildNodes[i] as XmlNode;\r
- FOwnerDocument.onNodeInserting(e, this);\r
- _childNodes.data.Insert(refNodeIndex, newChild.ChildNodes[i]);\r
- e.setParent(this);\r
- FOwnerDocument.onNodeInserted(newChild, this);\r
- refNodeIndex ++;\r
- }\r
- }\r
- else\r
- {\r
- FOwnerDocument.onNodeInserting(newChild, this);\r
- _childNodes.data.Insert(refNodeIndex, newChild);\r
- newChild.setParent(this);\r
- FOwnerDocument.onNodeInserted(newChild, this);\r
- }\r
-\r
- return retval;\r
- \r
- }\r
-\r
- /// <summary>\r
- /// Put all nodes under this node in "normal" form\r
- /// Whatever that means...\r
- /// </summary>\r
- public virtual void Normalize()\r
- {\r
- // TODO - Implement Normalize()\r
- throw new NotImplementedException();\r
- }\r
-\r
- /// <summary>\r
- /// Add the specified child to the beginning of the child node list\r
- /// </summary>\r
- /// <param name="newChild">Node to add</param>\r
- /// <returns>The node added</returns>\r
- public virtual XmlNode PrependChild(XmlNode newChild)\r
- {\r
- return InsertAfter(newChild, null);\r
- }\r
-\r
- /// <summary>\r
- /// Remove all children and attributes\r
- /// </summary>\r
- public virtual void RemoveAll()\r
- {\r
- if (_childNodes == null)\r
- return;\r
- else\r
- {\r
- // Remove in order, 0..n\r
- while (_childNodes.Count > 0)\r
- {\r
- XmlNode e = _childNodes[0];\r
- FOwnerDocument.onNodeRemoving(e, this);\r
- e.setParent(null);\r
- _childNodes.data.RemoveAt(0);\r
- FOwnerDocument.onNodeRemoved(e, null);\r
- }\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// Remove specified child node\r
- /// </summary>\r
- /// <param name="oldChild"></param>\r
- /// <returns>Removed node</returns>\r
- public virtual XmlNode RemoveChild(XmlNode oldChild)\r
- {\r
- // TODO - implement RemoveChild(oldChild)\r
- throw new NotImplementedException();\r
- }\r
-\r
- /// <summary>\r
- /// Select a list of nodes matching the xpath\r
- /// </summary>\r
- /// <param name="xpath"></param>\r
- /// <returns>matching nodes</returns>\r
- public XmlNodeList SelectNodes( string xpath)\r
- {\r
- // TODO - imlement SelectNodes(xpath)\r
- throw new NotImplementedException();\r
- }\r
-\r
- /// <summary>\r
- /// Select a list of nodes matching the xpath. Any prefixes are resolved\r
- /// using the passed namespace manager\r
- /// </summary>\r
- /// <param name="xpath"></param>\r
- /// <param name="nsmgr"></param>\r
- /// <returns></returns>\r
- public XmlNodeList SelectNodes(string xpath, XmlNamespaceManager nsmgr)\r
- {\r
- // TODO - implement SelectNodes(xpath, nsmgr)\r
- throw new NotImplementedException();\r
- }\r
-\r
- /// <summary>\r
- /// Selects the first node that matches xpath\r
- /// </summary>\r
- /// <param name="?"></param>\r
- /// <returns></returns>\r
- public XmlNode SelectSingleNode(string xpatch)\r
- {\r
- // TODO - implement SelectSingeNode(xpath)\r
- throw new NotImplementedException();\r
- }\r
-\r
- /// <summary>\r
- /// Returns the first node that matches xpath\r
- /// Uses the passed namespace manager to resolve namespace URI's\r
- /// </summary>\r
- /// <param name="xpath"></param>\r
- /// <param name="nsmgr"></param>\r
- /// <returns></returns>\r
- public XmlNode SelectSingleNode(string xpath, XmlNamespaceManager nsmgr)\r
- {\r
- // Implement SelectSingleNode(xpath, nsmgr)\r
- throw new NotImplementedException();\r
- }\r
-\r
- /// <summary>\r
- /// Tests if the DOM implementation supports the passed feature\r
- /// </summary>\r
- /// <param name="feature"></param>\r
- /// <param name="version"></param>\r
- /// <returns></returns>\r
- public virtual bool Supports(string feature, string version)\r
- {\r
- //TODO - implement Supports(feature, version)\r
- throw new NotImplementedException();\r
- }\r
-\r
- /// <summary>\r
- /// Returns a string representation of the current node and it's children\r
- /// </summary>\r
- /// <returns></returns>\r
- public override string ToString()\r
- {\r
- // TODO - implement ToString()\r
- throw new NotImplementedException();\r
- }\r
-\r
- /// <summary>\r
- /// Saves all children of the current node to the passed writer\r
- /// </summary>\r
- /// <param name="w"></param>\r
- public abstract void WriteContentTo(XmlWriter w);\r
- \r
- /// <summary>\r
- /// Saves the current node to writer w\r
- /// </summary>\r
- /// <param name="w"></param>\r
- public abstract void WriteTo(XmlWriter w);\r
-\r
- //======= Internal methods ===============================================\r
- /// <summary>\r
- /// accessor {set;} for parentNode only visible internally.\r
- /// </summary>\r
- /// <param name="newParent">new parent node.</param>\r
- internal void setParent( XmlNode newParent)\r
- {\r
- if (newParent.OwnerDocument.Equals( FOwnerDocument) )\r
- _parent = newParent;\r
- else\r
- throw new ArgumentException("New parent node owner does not match");\r
- }\r
- \r
-\r
- //======= Protected methods ==============================================\r
-\r
- //======= Private Methods ===================================================\r
- /// <summary>\r
- /// Helper function to perform checks required before insrting a node.\r
- /// Throws applicable exceptions on error.\r
- /// </summary>\r
- /// <param name="newChild"></param>\r
- /// <param name="refChild"></param>\r
- private void InsertionCheck( XmlNode newChild, XmlNode refChild)\r
- {\r
- if (newChild == null)\r
- throw new ArgumentNullException("Null newNode passed to InsertAfter()");\r
-\r
- if (newChild.Equals(this))\r
- throw new ArgumentException("Cannot insert node onto itself");\r
-\r
- if (! FOwnerDocument.Equals( newChild.OwnerDocument) )\r
- throw new ArgumentException("Reference node has different owner document than this node");\r
- \r
- if ( FOwnerDocument.IsReadOnly )\r
- throw new ArgumentException("Operation not supported - tree is read-only");\r
-\r
- //Check that insert node is not in our path to the root\r
- XmlNode curParent = _parent;\r
- while ( (curParent != null) & (! FOwnerDocument.Equals(curParent) ))\r
- {\r
- if (curParent.Equals(newChild) )\r
- throw new ArgumentException("Cannot insert ancestor a node");\r
- curParent = curParent.ParentNode;\r
- }\r
-\r
- }\r
-\r
- // Constructors\r
- //===========================================================================\r
- //When we're first created, we won't know parent, etc.\r
- internal XmlNode( XmlDocument aOwnerDoc )\r
- {\r
- // Don't create childnodes object, since not all derived classes have children\r
- FOwnerDocument = aOwnerDoc;\r
- }\r
-\r
- } // XmlNode\r
-} // using namespace System.Xml\r
-\r
-
\ No newline at end of file
+//
+// System.Xml.XmlNode
+//
+// Author:
+// Kral Ferch <kral_ferch@hotmail.com>
+// Atsushi Enomoto <ginga@kit.hi-ho.ne.jp>
+//
+// (C) 2002 Kral Ferch
+// (C) 2002 Atsushi Enomoto
+//
+
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+using System.Xml.XPath;
+
+namespace System.Xml
+{
+ public abstract class XmlNode : ICloneable, IEnumerable, IXPathNavigable
+ {
+ #region Fields
+
+ XmlDocument ownerDocument;
+ XmlNode parentNode;
+
+ #endregion
+
+ #region Constructors
+
+ internal XmlNode (XmlDocument ownerDocument)
+ {
+ this.ownerDocument = ownerDocument;
+ }
+
+ #endregion
+
+ #region Properties
+
+ public virtual XmlAttributeCollection Attributes {
+ get { return null; }
+ }
+
+ public virtual string BaseURI {
+ get {
+ // Isn't it conformant to W3C XML Base Recommendation?
+ // As far as I tested, there are not...
+ return (ParentNode != null) ? ParentNode.BaseURI : OwnerDocument.BaseURI;
+ }
+ }
+
+ public virtual XmlNodeList ChildNodes {
+ get {
+ return new XmlNodeListChildren (this);
+ }
+ }
+
+ public virtual XmlNode FirstChild {
+ get {
+ if (LastChild != null) {
+ return LastLinkedChild.NextLinkedSibling;
+ }
+ else {
+ return null;
+ }
+ }
+ }
+
+ public virtual bool HasChildNodes {
+ get { return LastChild != null; }
+ }
+
+ [MonoTODO("confirm whether this way is right for each not-overriden types.")]
+ public virtual string InnerText {
+ get {
+ StringBuilder builder = new StringBuilder ();
+ AppendChildValues (this, builder);
+ return builder.ToString ();
+ }
+
+ set { throw new NotImplementedException (); }
+ }
+
+ private void AppendChildValues (XmlNode parent, StringBuilder builder)
+ {
+ XmlNode node = parent.FirstChild;
+
+ while (node != null) {
+ if (node.NodeType == XmlNodeType.Text)
+ builder.Append (node.Value);
+ AppendChildValues (node, builder);
+ node = node.NextSibling;
+ }
+ }
+
+ [MonoTODO("Setter.")]
+ public virtual string InnerXml {
+ get {
+ StringWriter sw = new StringWriter ();
+ XmlTextWriter xtw = new XmlTextWriter (sw);
+
+ WriteContentTo (xtw);
+
+ return sw.GetStringBuilder ().ToString ();
+ }
+
+ set { throw new NotImplementedException (); }
+ }
+
+ public virtual bool IsReadOnly {
+ get { return false; }
+ }
+
+ [System.Runtime.CompilerServices.IndexerName("Item")]
+ public virtual XmlElement this [string name] {
+ get {
+ foreach (XmlNode node in ChildNodes) {
+ if ((node.NodeType == XmlNodeType.Element) &&
+ (node.Name == name)) {
+ return (XmlElement) node;
+ }
+ }
+
+ return null;
+ }
+ }
+
+ [System.Runtime.CompilerServices.IndexerName("Item")]
+ public virtual XmlElement this [string localname, string ns] {
+ get {
+ foreach (XmlNode node in ChildNodes) {
+ if ((node.NodeType == XmlNodeType.Element) &&
+ (node.LocalName == localname) &&
+ (node.NamespaceURI == ns)) {
+ return (XmlElement) node;
+ }
+ }
+
+ return null;
+ }
+ }
+
+ public virtual XmlNode LastChild {
+ get { return LastLinkedChild; }
+ }
+
+ internal virtual XmlLinkedNode LastLinkedChild {
+ get { return null; }
+ set { }
+ }
+
+ public abstract string LocalName { get; }
+
+ public abstract string Name { get; }
+
+ public virtual string NamespaceURI {
+ get { return String.Empty; }
+ }
+
+ public virtual XmlNode NextSibling {
+ get { return null; }
+ }
+
+ public abstract XmlNodeType NodeType { get; }
+
+ internal virtual XPathNodeType XPathNodeType {
+ get {
+ return (XPathNodeType) (-1);
+ }
+ }
+
+ public virtual string OuterXml {
+ get {
+ StringWriter sw = new StringWriter ();
+ XmlTextWriter xtw = new XmlTextWriter (sw);
+
+ WriteTo (xtw);
+
+ return sw.GetStringBuilder ().ToString ();
+ }
+ }
+
+ public virtual XmlDocument OwnerDocument {
+ get { return ownerDocument; }
+ }
+
+ public virtual XmlNode ParentNode {
+ get { return parentNode; }
+ }
+
+ public virtual string Prefix {
+ get { return String.Empty; }
+ set {}
+ }
+
+ public virtual XmlNode PreviousSibling {
+ get { return null; }
+ }
+
+ public virtual string Value {
+ get { return null; }
+ set { throw new InvalidOperationException ("This node does not have a value"); }
+ }
+
+ internal virtual string XmlLang {
+ get {
+ if(Attributes != null)
+ foreach(XmlAttribute attr in Attributes)
+ if(attr.Name == "xml:lang")
+ return attr.Value;
+ return (ParentNode != null) ? ParentNode.XmlLang : OwnerDocument.XmlLang;
+ }
+ }
+
+ internal virtual XmlSpace XmlSpace {
+ get {
+ if(Attributes != null) {
+ foreach(XmlAttribute attr in Attributes) {
+ if(attr.Name == "xml:space") {
+ switch(attr.Value) {
+ case "preserve": return XmlSpace.Preserve;
+ case "default": return XmlSpace.Default;
+ }
+ break;
+ }
+ }
+ }
+ return (ParentNode != null) ? ParentNode.XmlSpace : OwnerDocument.XmlSpace;
+ }
+ }
+
+ #endregion
+
+ #region Methods
+
+ public virtual XmlNode AppendChild (XmlNode newChild)
+ {
+ // I assume that AppendChild(n) equals to InsertAfter(n, this.LastChild) or InsertBefore(n, null)
+ return InsertBefore (newChild, null);
+ }
+
+ public virtual XmlNode Clone ()
+ {
+ // By MS document, it is equivalent to CloneNode(true).
+ return this.CloneNode (true);
+ }
+
+ public abstract XmlNode CloneNode (bool deep);
+
+ [MonoTODO]
+ public XPathNavigator CreateNavigator ()
+ {
+ return new XmlDocumentNavigator (this);
+ }
+
+ public IEnumerator GetEnumerator ()
+ {
+ return new XmlNodeListChildren (this).GetEnumerator ();
+ }
+
+ [MonoTODO("performance problem.")]
+ public virtual string GetNamespaceOfPrefix (string prefix)
+ {
+ XmlNamespaceManager nsmgr = ConstructNamespaceManager ();
+ return nsmgr.LookupNamespace (prefix);
+ }
+
+ [MonoTODO("performance problem.")]
+ public virtual string GetPrefixOfNamespace (string namespaceURI)
+ {
+ XmlNamespaceManager nsmgr = ConstructNamespaceManager ();
+ string ns = nsmgr.LookupPrefix (namespaceURI);
+ return (ns != null) ? ns : String.Empty;
+ }
+
+ object ICloneable.Clone ()
+ {
+ return Clone ();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator ()
+ {
+ return GetEnumerator ();
+ }
+
+ public virtual XmlNode InsertAfter (XmlNode newChild, XmlNode refChild)
+ {
+ // I assume that insertAfter(n1, n2) equals to InsertBefore(n1, n2.PreviousSibling).
+
+ // I took this way because rather than calling InsertAfter() from InsertBefore()
+ // because current implementation of 'NextSibling' looks faster than 'PreviousSibling'.
+ XmlNode argNode = null;
+ if(refChild != null)
+ argNode = refChild.NextSibling;
+ else if(ChildNodes.Count > 0)
+ argNode = FirstChild;
+ return InsertBefore (newChild, argNode);
+ }
+
+ [MonoTODO("If inserted node is entity reference, then check conforming entity. Wait for DTD implementation.")]
+ public virtual XmlNode InsertBefore (XmlNode newChild, XmlNode refChild)
+ {
+ XmlDocument ownerDoc = (NodeType == XmlNodeType.Document) ? (XmlDocument)this : OwnerDocument;
+
+ if (NodeType == XmlNodeType.Document ||
+ NodeType == XmlNodeType.Element ||
+ NodeType == XmlNodeType.Attribute ||
+ NodeType == XmlNodeType.DocumentFragment) {
+ if (IsReadOnly)
+ throw new ArgumentException ("The specified node is readonly.");
+
+ if (newChild.OwnerDocument != ownerDoc)
+ throw new ArgumentException ("Can't append a node created by another document.");
+
+ if (refChild != null && newChild.OwnerDocument != refChild.OwnerDocument)
+ throw new ArgumentException ("argument nodes are on the different documents.");
+
+ // This check is done by MS.NET 1.0, but isn't done for MS.NET 1.1.
+ // Skip this check in the meantime...
+// if(this == ownerDoc && ownerDoc.DocumentElement != null && (newChild is XmlElement))
+// throw new XmlException ("multiple document element not allowed.");
+
+ // checking validity finished. then appending...
+
+ ownerDoc.onNodeInserting (newChild, this);
+
+ if(newChild.ParentNode != null)
+ newChild.ParentNode.RemoveChild (newChild);
+
+ if(newChild.NodeType == XmlNodeType.DocumentFragment) {
+ int x = newChild.ChildNodes.Count;
+ for(int i=0; i<x; i++) {
+ XmlNode n = newChild.ChildNodes [0];
+ this.InsertBefore (n, refChild); // recursively invokes events. (It is compatible with MS implementation.)
+ }
+ }
+ else {
+ XmlLinkedNode newLinkedChild = (XmlLinkedNode) newChild;
+ XmlLinkedNode lastLinkedChild = LastLinkedChild;
+
+ newLinkedChild.parentNode = this;
+
+ if(refChild == null) {
+ // append last, so:
+ // * set nextSibling of previous lastchild to newChild
+ // * set lastchild = newChild
+ // * set next of newChild to firstChild
+ if(LastLinkedChild != null) {
+ XmlLinkedNode formerFirst = FirstChild as XmlLinkedNode;
+ LastLinkedChild.NextLinkedSibling = newLinkedChild;
+ LastLinkedChild = newLinkedChild;
+ newLinkedChild.NextLinkedSibling = formerFirst;
+ }
+ else {
+ LastLinkedChild = newLinkedChild;
+ LastLinkedChild.NextLinkedSibling = newLinkedChild; // FirstChild
+ }
+ }
+ else {
+ // append not last, so:
+ // * if newchild is first, then set next of lastchild is newChild.
+ // otherwise, set next of previous sibling to newChild
+ // * set next of newChild to refChild
+ XmlLinkedNode prev = refChild.PreviousSibling as XmlLinkedNode;
+ if(prev == null)
+ LastLinkedChild.NextLinkedSibling = newLinkedChild;
+ else
+ prev.NextLinkedSibling = newLinkedChild;
+ newLinkedChild.NextLinkedSibling = refChild as XmlLinkedNode;
+ }
+ ownerDoc.onNodeInserted (newChild, newChild.ParentNode);
+ }
+ return newChild;
+ }
+ else
+ throw new InvalidOperationException ();
+ }
+
+ [MonoTODO]
+ public virtual void Normalize ()
+ {
+ throw new NotImplementedException ();
+ }
+
+ public virtual XmlNode PrependChild (XmlNode newChild)
+ {
+ return InsertAfter (newChild, null);
+ }
+
+ public virtual void RemoveAll ()
+ {
+ XmlNode next = null;
+ for (XmlNode node = FirstChild; node != null; node = next) {
+ next = node.NextSibling;
+ RemoveChild (node);
+ }
+ }
+
+ public virtual XmlNode RemoveChild (XmlNode oldChild)
+ {
+ XmlDocument ownerDoc = (NodeType == XmlNodeType.Document) ? (XmlDocument)this : OwnerDocument;
+ if(oldChild.ParentNode != this)
+ throw new XmlException ("specified child is not child of this node.");
+
+ ownerDoc.onNodeRemoving (oldChild, oldChild.ParentNode);
+
+ if (NodeType == XmlNodeType.Document || NodeType == XmlNodeType.Element || NodeType == XmlNodeType.Attribute || NodeType == XmlNodeType.DocumentFragment) {
+ if (IsReadOnly)
+ throw new ArgumentException ();
+
+ if (Object.ReferenceEquals (LastLinkedChild, LastLinkedChild.NextLinkedSibling) && Object.ReferenceEquals (LastLinkedChild, oldChild))
+ LastLinkedChild = null;
+ else {
+ XmlLinkedNode oldLinkedChild = (XmlLinkedNode)oldChild;
+ XmlLinkedNode beforeLinkedChild = LastLinkedChild;
+
+ while (!Object.ReferenceEquals (beforeLinkedChild.NextLinkedSibling, LastLinkedChild) && !Object.ReferenceEquals (beforeLinkedChild.NextLinkedSibling, oldLinkedChild))
+ beforeLinkedChild = beforeLinkedChild.NextLinkedSibling;
+
+ if (!Object.ReferenceEquals (beforeLinkedChild.NextLinkedSibling, oldLinkedChild))
+ throw new ArgumentException ();
+
+ beforeLinkedChild.NextLinkedSibling = oldLinkedChild.NextLinkedSibling;
+ oldLinkedChild.NextLinkedSibling = null;
+ }
+
+ ownerDoc.onNodeRemoved (oldChild, oldChild.ParentNode);
+ oldChild.parentNode = null; // clear parent 'after' above logic.
+
+ return oldChild;
+ }
+ else
+ throw new ArgumentException ();
+ }
+
+ public virtual XmlNode ReplaceChild (XmlNode newChild, XmlNode oldChild)
+ {
+ if(oldChild.ParentNode != this)
+ throw new InvalidOperationException ("oldChild is not a child of this node.");
+ XmlNode parent = this.ParentNode;
+ while(parent != null) {
+ if(newChild == parent)
+ throw new InvalidOperationException ("newChild is ancestor of this node.");
+ parent = parent.ParentNode;
+ }
+ foreach(XmlNode n in ChildNodes) {
+ if(n == oldChild) {
+ XmlNode prev = oldChild.PreviousSibling;
+ RemoveChild (oldChild);
+ InsertAfter (newChild, prev);
+ break;
+ }
+ }
+ return oldChild;
+ }
+
+ public XmlNodeList SelectNodes (string xpath)
+ {
+ return SelectNodes (xpath, null);
+ }
+
+ [MonoTODO]
+ public XmlNodeList SelectNodes (string xpath, XmlNamespaceManager nsmgr)
+ {
+ XPathNavigator nav = CreateNavigator ();
+ XPathExpression expr = nav.Compile (xpath);
+ if (nsmgr != null)
+ expr.SetContext (nsmgr);
+ XPathNodeIterator iter = nav.Select (expr);
+ ArrayList rgNodes = new ArrayList ();
+ while (iter.MoveNext ())
+ {
+ rgNodes.Add (((XmlDocumentNavigator) iter.Current).Node);
+ }
+ return new XmlNodeArrayList (rgNodes);
+ }
+
+ public XmlNode SelectSingleNode (string xpath)
+ {
+ return SelectSingleNode (xpath, null);
+ }
+
+ [MonoTODO]
+ public XmlNode SelectSingleNode (string xpath, XmlNamespaceManager nsmgr)
+ {
+ XPathNavigator nav = CreateNavigator ();
+ XPathExpression expr = nav.Compile (xpath);
+ if (nsmgr != null)
+ expr.SetContext (nsmgr);
+ XPathNodeIterator iter = nav.Select (expr);
+ if (!iter.MoveNext ())
+ return null;
+ return ((XmlDocumentNavigator) iter.Current).Node;
+ }
+
+ internal void SetParentNode (XmlNode parent)
+ {
+ parentNode = parent;
+ }
+
+ [MonoTODO]
+ public virtual bool Supports (string feature, string version)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public abstract void WriteContentTo (XmlWriter w);
+
+ public abstract void WriteTo (XmlWriter w);
+
+ // It parses this and all the ancestor elements,
+ // find 'xmlns' declarations, stores and then return them.
+ // TODO: tests
+ internal XmlNamespaceManager ConstructNamespaceManager ()
+ {
+ XmlDocument doc = this is XmlDocument ? (XmlDocument)this : this.OwnerDocument;
+ XmlNamespaceManager nsmgr = new XmlNamespaceManager (doc.NameTable);
+ XmlElement el = null;
+ switch(this.NodeType) {
+ case XmlNodeType.Attribute:
+ el = ((XmlAttribute)this).OwnerElement;
+ break;
+ case XmlNodeType.Element:
+ el = this as XmlElement;
+ break;
+ default:
+ el = this.ParentNode as XmlElement;
+ break;
+ }
+
+ while(el != null) {
+ foreach(XmlAttribute attr in el.Attributes) {
+ if(attr.Prefix == "xmlns" || (attr.Name == "xmlns" && attr.Prefix == String.Empty)) {
+ if(nsmgr.LookupNamespace (attr.LocalName) == null )
+ nsmgr.AddNamespace (attr.LocalName, attr.Value);
+ }
+ }
+ // When reached to document, then it will set null value :)
+ el = el.ParentNode as XmlElement;
+ }
+ return nsmgr;
+ }
+ #endregion
+ }
+}