//
// 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
- ///////////////////////////////////////////////////////////////////////
- //
- // Fields
- //
- ///////////////////////////////////////////////////////////////////////
XmlDocument ownerDocument;
XmlNode parentNode;
+ StringBuilder tmpBuilder;
+ XmlLinkedNode lastLinkedChild;
#endregion
#region Constructors
- ///////////////////////////////////////////////////////////////////////
- //
- // Constructors
- //
- ///////////////////////////////////////////////////////////////////////
- protected internal XmlNode(XmlDocument ownerDocument)
+ internal XmlNode (XmlDocument ownerDocument)
{
this.ownerDocument = ownerDocument;
}
#endregion
#region Properties
- ///////////////////////////////////////////////////////////////////////
- //
- // Properties
- //
- ///////////////////////////////////////////////////////////////////////
- public virtual XmlAttributeCollection Attributes
- {
+ public virtual XmlAttributeCollection Attributes {
get { return null; }
}
- [MonoTODO]
- public virtual string BaseURI
- {
- get { throw new NotImplementedException (); }
+ 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(LastLinkedChild);
+ return new XmlNodeListChildren (this);
}
}
get { return LastChild != null; }
}
- [MonoTODO]
public virtual string InnerText {
- get { throw new NotImplementedException (); }
- set { throw new NotImplementedException (); }
+ get {
+ StringBuilder builder = new StringBuilder ();
+ AppendChildValues (this, builder);
+ return builder.ToString ();
+ }
+
+ set { throw new InvalidOperationException ("This node is read only. Cannot be modified."); }
+ }
+
+ private void AppendChildValues (XmlNode parent, StringBuilder builder)
+ {
+ XmlNode node = parent.FirstChild;
+
+ while (node != null) {
+ switch (node.NodeType) {
+ case XmlNodeType.Text:
+ case XmlNodeType.CDATA:
+ case XmlNodeType.SignificantWhitespace:
+ case XmlNodeType.Whitespace:
+ builder.Append (node.Value);
+ break;
+ }
+ AppendChildValues (node, builder);
+ node = node.NextSibling;
+ }
}
- [MonoTODO]
public virtual string InnerXml {
- get { throw new NotImplementedException (); }
- set { throw new NotImplementedException (); }
+ get {
+ StringWriter sw = new StringWriter ();
+ XmlTextWriter xtw = new XmlTextWriter (sw);
+
+ WriteContentTo (xtw);
+
+ return sw.GetStringBuilder ().ToString ();
+ }
+
+ set {
+ throw new InvalidOperationException ("This node is readonly or doesn't have any children.");
+ }
}
- [MonoTODO]
public virtual bool IsReadOnly {
- get { throw new NotImplementedException (); }
+ get { return false; }
}
- [MonoTODO]
[System.Runtime.CompilerServices.IndexerName("Item")]
public virtual XmlElement this [string name] {
- get { throw new NotImplementedException (); }
+ get {
+ foreach (XmlNode node in ChildNodes) {
+ if ((node.NodeType == XmlNodeType.Element) &&
+ (node.Name == name)) {
+ return (XmlElement) node;
+ }
+ }
+
+ return null;
+ }
}
- [MonoTODO]
[System.Runtime.CompilerServices.IndexerName("Item")]
public virtual XmlElement this [string localname, string ns] {
- get { throw new NotImplementedException (); }
+ 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 {
}
internal virtual XmlLinkedNode LastLinkedChild {
- get { return null; }
- set { }
+ get { return lastLinkedChild; }
+ set { lastLinkedChild = value; }
}
- [MonoTODO]
public abstract string LocalName { get; }
- [MonoTODO]
public abstract string Name { get; }
- [MonoTODO]
public virtual string NamespaceURI {
- get { throw new NotImplementedException (); }
+ get { return String.Empty; }
}
public virtual XmlNode NextSibling {
get { return null; }
}
- [MonoTODO]
public abstract XmlNodeType NodeType { get; }
- [MonoTODO]
+ internal virtual XPathNodeType XPathNodeType {
+ get {
+ throw new InvalidOperationException ("Can not get XPath node type from " + this.GetType ().ToString ());
+ }
+ }
+
public virtual string OuterXml {
- get { throw new NotImplementedException (); }
+ get {
+ StringWriter sw = new StringWriter ();
+ XmlTextWriter xtw = new XmlTextWriter (sw);
+
+ WriteTo (xtw);
+
+ return sw.ToString ();
+ }
}
public virtual XmlDocument OwnerDocument {
get { return parentNode; }
}
- [MonoTODO]
public virtual string Prefix {
- get { throw new NotImplementedException (); }
- set { throw new NotImplementedException (); }
+ get { return String.Empty; }
+ set {}
}
public virtual XmlNode PreviousSibling {
get { return null; }
}
- [MonoTODO]
public virtual string Value {
- get { throw new NotImplementedException (); }
- set { throw new NotImplementedException (); }
+ 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
- ///////////////////////////////////////////////////////////////////////
- //
- // Methods
- //
- ///////////////////////////////////////////////////////////////////////
public virtual XmlNode AppendChild (XmlNode newChild)
{
- if ((NodeType == XmlNodeType.Document) || (NodeType == XmlNodeType.Element)) {
- LastLinkedChild = (XmlLinkedNode) newChild;
- return LastChild;
- }
- else {
- throw new InvalidOperationException();
- }
+ // I assume that AppendChild(n) equals to InsertAfter(n, this.LastChild) or InsertBefore(n, null)
+ return InsertBefore (newChild, null);
}
- [MonoTODO]
public virtual XmlNode Clone ()
{
- throw new NotImplementedException ();
+ // By MS document, it is equivalent to CloneNode(true).
+ return this.CloneNode (true);
}
public abstract XmlNode CloneNode (bool deep);
- [MonoTODO]
public XPathNavigator CreateNavigator ()
{
- throw new NotImplementedException ();
+ XmlDocument document = this.NodeType == XmlNodeType.Document ?
+ this as XmlDocument : this.ownerDocument;
+ return document.CreateNavigator (this);
}
- [MonoTODO]
public IEnumerator GetEnumerator ()
{
- throw new NotImplementedException ();
+ return new XmlNodeListChildren (this).GetEnumerator ();
}
- [MonoTODO]
public virtual string GetNamespaceOfPrefix (string prefix)
{
- throw new NotImplementedException ();
+ if (prefix == null)
+ throw new ArgumentNullException ("prefix");
+
+ XmlNode node;
+ switch (NodeType) {
+ case XmlNodeType.Attribute:
+ node = ((XmlAttribute) this).OwnerElement;
+ if (node == null)
+ return String.Empty;
+ break;
+ case XmlNodeType.Element:
+ node = this;
+ break;
+ default:
+ node = ParentNode;
+ break;
+ }
+
+ while (node != null) {
+ if (node.Prefix == prefix)
+ return node.NamespaceURI;
+ if (node.Attributes != null) {
+ int count = node.Attributes.Count;
+ for (int i = 0; i < count; i++) {
+ XmlAttribute attr = node.Attributes [i];
+ if (prefix == attr.LocalName && attr.Prefix == "xmlns"
+ || attr.Name == "xmlns" && prefix == String.Empty)
+ return attr.Value;
+ }
+ }
+ node = node.ParentNode;
+ }
+ return String.Empty;
}
- [MonoTODO]
public virtual string GetPrefixOfNamespace (string namespaceURI)
{
- throw new NotImplementedException ();
+ XmlNode node;
+ switch (NodeType) {
+ case XmlNodeType.Attribute:
+ node = ((XmlAttribute) this).OwnerElement;
+ break;
+ case XmlNodeType.Element:
+ node = this;
+ break;
+ default:
+ node = ParentNode;
+ break;
+ }
+
+ while (node != null && node.Attributes != null) {
+ foreach (XmlAttribute attr in node.Attributes) {
+ if (attr.Prefix == "xmlns" && attr.Value == namespaceURI)
+ return attr.LocalName;
+ else if (attr.Name == "xmlns" && attr.Value == namespaceURI)
+ return String.Empty;
+ }
+ node = node.ParentNode;
+ }
+ return String.Empty;
}
object ICloneable.Clone ()
return GetEnumerator ();
}
- [MonoTODO]
public virtual XmlNode InsertAfter (XmlNode newChild, XmlNode refChild)
{
- throw new NotImplementedException ();
+ // InsertAfter(n1, n2) is equivalent to InsertBefore(n1, n2.PreviousSibling).
+
+ // I took this way because current implementation
+ // Calling InsertBefore() in this method is faster than
+ // the counterpart, since NextSibling is faster than
+ // PreviousSibling (these children are forward-only list).
+ XmlNode argNode = null;
+ if (refChild != null)
+ argNode = refChild.NextSibling;
+ else if (ChildNodes.Count > 0)
+ argNode = FirstChild;
+ return InsertBefore (newChild, argNode);
}
- [MonoTODO]
public virtual XmlNode InsertBefore (XmlNode newChild, XmlNode refChild)
{
- throw new NotImplementedException ();
+ return InsertBefore (newChild, refChild, true, true);
+ }
+
+ // check for the node to be one of node ancestors
+ internal bool IsAncestor (XmlNode newChild)
+ {
+ XmlNode currNode = this.ParentNode;
+ while(currNode != null)
+ {
+ if(currNode == newChild)
+ return true;
+ currNode = currNode.ParentNode;
+ }
+ return false;
+ }
+
+ internal XmlNode InsertBefore (XmlNode newChild, XmlNode refChild, bool checkNodeType, bool raiseEvent)
+ {
+ if (checkNodeType)
+ CheckNodeInsertion (newChild, refChild);
+
+ XmlDocument ownerDoc = (NodeType == XmlNodeType.Document) ? (XmlDocument) this : OwnerDocument;
+
+ if (raiseEvent)
+ ownerDoc.onNodeInserting (newChild, this);
+
+ if (newChild.ParentNode != null)
+ newChild.ParentNode.RemoveChild (newChild, checkNodeType);
+
+ 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) {
+ // newChild is the last child:
+ // * set newChild as NextSibling of the existing lastchild
+ // * set LastChild = newChild
+ // * set NextSibling of newChild as FirstChild
+ if (LastLinkedChild != null) {
+ XmlLinkedNode formerFirst = (XmlLinkedNode) FirstChild;
+ LastLinkedChild.NextLinkedSibling = newLinkedChild;
+ LastLinkedChild = newLinkedChild;
+ newLinkedChild.NextLinkedSibling = formerFirst;
+ } else {
+ LastLinkedChild = newLinkedChild;
+ LastLinkedChild.NextLinkedSibling = newLinkedChild; // FirstChild
+ }
+ } else {
+ // newChild is not the last child:
+ // * 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;
+ }
+ switch (newChild.NodeType) {
+ case XmlNodeType.EntityReference:
+ ((XmlEntityReference) newChild).SetReferencedEntityContent ();
+ break;
+ case XmlNodeType.Entity:
+ ((XmlEntity) newChild).SetEntityContent ();
+ break;
+ case XmlNodeType.DocumentType:
+ foreach (XmlEntity ent in ((XmlDocumentType)newChild).Entities)
+ ent.SetEntityContent ();
+ break;
+ }
+
+ if (raiseEvent)
+ ownerDoc.onNodeInserted (newChild, newChild.ParentNode);
+ }
+ return newChild;
+ }
+
+ private void CheckNodeInsertion (XmlNode newChild, XmlNode refChild)
+ {
+ XmlDocument ownerDoc = (NodeType == XmlNodeType.Document) ? (XmlDocument)this : OwnerDocument;
+
+ if (NodeType != XmlNodeType.Element &&
+ NodeType != XmlNodeType.Attribute &&
+ NodeType != XmlNodeType.Document &&
+ NodeType != XmlNodeType.DocumentFragment)
+ throw new InvalidOperationException (String.Format ("current node {0} is not allowed to have any children.", NodeType));
+
+ switch (NodeType) {
+ case XmlNodeType.Attribute:
+ switch (newChild.NodeType) {
+ case XmlNodeType.Text:
+ case XmlNodeType.EntityReference:
+ break;
+ default:
+ throw new ArgumentException (String.Format (
+ "Cannot insert specified type of node {0} as a child of this node {0}.",
+ newChild.NodeType, NodeType));
+ }
+ break;
+ case XmlNodeType.Element:
+ switch (newChild.NodeType) {
+ case XmlNodeType.Attribute:
+ case XmlNodeType.Document:
+ case XmlNodeType.DocumentType:
+ case XmlNodeType.Entity:
+ case XmlNodeType.Notation:
+ case XmlNodeType.XmlDeclaration:
+ throw new ArgumentException ("Cannot insert specified type of node as a child of this node.");
+ }
+ break;
+ }
+
+ 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.");
+
+ if(this == ownerDoc && ownerDoc.DocumentElement != null && (newChild is XmlElement))
+ throw new XmlException ("multiple document element not allowed.");
+
+ // checking validity finished. then appending...
+
+
+ if (newChild == this || IsAncestor (newChild))
+ throw new ArgumentException("Cannot insert a node or any ancestor of that node as a child of itself.");
+
}
- [MonoTODO]
public virtual void Normalize ()
{
- throw new NotImplementedException ();
+// if (tmpBuilder == null)
+ tmpBuilder = new StringBuilder ();
+// tmpBuilder.Length = 0;
+ int count = this.ChildNodes.Count;
+ int start = 0;
+ for (int i = 0; i < count; i++) {
+ XmlNode c = ChildNodes [i];
+ switch (c.NodeType) {
+ case XmlNodeType.Text:
+ case XmlNodeType.Whitespace:
+ case XmlNodeType.SignificantWhitespace:
+ tmpBuilder.Append (c.Value);
+ break;
+ default:
+ c.Normalize ();
+ NormalizeRange (start, i);
+ // Continue to normalize from next node.
+ start = i + 1;
+ break;
+ }
+ }
+ if (start < count) {
+ NormalizeRange (start, count);
+ }
+
+ tmpBuilder = null;
+ }
+
+ private void NormalizeRange (int start, int i)
+ {
+ int keepPos = -1;
+ // If Texts and Whitespaces are mixed, Text takes precedence to remain.
+ // i.e. Whitespace should be removed.
+ for (int j = start; j < i; j++) {
+ XmlNode keep = ChildNodes [j];
+ if (keep.NodeType == XmlNodeType.Text) {
+ keepPos = j;
+ break;
+ }
+ else if (keep.NodeType == XmlNodeType.SignificantWhitespace)
+ keepPos = j;
+ // but don't break up to find Text nodes.
+ }
+ // But if no Texts and one or more Whitespaces, then the first
+ if (keepPos < 0 && i > start)
+ keepPos = 0;
+
+ if (keepPos >= 0) {
+ for (int del = start; del < keepPos; del++)
+ RemoveChild (ChildNodes [del]);
+ for (int del = keepPos + 1; del < i; del++)
+ RemoveChild (ChildNodes [del]);
+ }
+
+ ChildNodes [keepPos].Value = tmpBuilder.ToString ();
+ tmpBuilder.Length = 0;
}
- [MonoTODO]
public virtual XmlNode PrependChild (XmlNode newChild)
{
- throw new NotImplementedException ();
+ return InsertAfter (newChild, null);
}
public virtual void RemoveAll ()
{
- LastLinkedChild = null;
+ if (Attributes != null)
+ Attributes.RemoveAll ();
+ XmlNode next = null;
+ for (XmlNode node = FirstChild; node != null; node = next) {
+ next = node.NextSibling;
+ RemoveChild (node);
+ }
}
- [MonoTODO]
public virtual XmlNode RemoveChild (XmlNode oldChild)
{
- throw new NotImplementedException ();
+ return RemoveChild (oldChild, true);
+ }
+
+ private void CheckNodeRemoval ()
+ {
+ if (NodeType != XmlNodeType.Attribute &&
+ NodeType != XmlNodeType.Element &&
+ NodeType != XmlNodeType.Document &&
+ NodeType != XmlNodeType.DocumentFragment)
+ throw new ArgumentException (String.Format ("This {0} node cannot remove child.", NodeType));
+
+ if (IsReadOnly)
+ throw new ArgumentException (String.Format ("This {0} node is read only.", NodeType));
+ }
+
+ internal XmlNode RemoveChild (XmlNode oldChild, bool checkNodeType)
+ {
+ XmlDocument ownerDoc = (NodeType == XmlNodeType.Document) ? (XmlDocument)this : OwnerDocument;
+ if(oldChild.ParentNode != this)
+ throw new XmlException ("specified child is not child of this node.");
+
+ if (checkNodeType)
+ ownerDoc.onNodeRemoving (oldChild, oldChild.ParentNode);
+
+ if (checkNodeType)
+ CheckNodeRemoval ();
+
+ if (Object.ReferenceEquals (LastLinkedChild, LastLinkedChild.NextLinkedSibling) && Object.ReferenceEquals (LastLinkedChild, oldChild))
+ // If there is only one children, simply clear.
+ LastLinkedChild = null;
+ else {
+ XmlLinkedNode oldLinkedChild = (XmlLinkedNode) oldChild;
+ XmlLinkedNode beforeLinkedChild = LastLinkedChild;
+ XmlLinkedNode firstChild = (XmlLinkedNode) FirstChild;
+
+ while (Object.ReferenceEquals (beforeLinkedChild.NextLinkedSibling, LastLinkedChild) == false &&
+ Object.ReferenceEquals (beforeLinkedChild.NextLinkedSibling, oldLinkedChild) == false)
+ beforeLinkedChild = beforeLinkedChild.NextLinkedSibling;
+
+ if (Object.ReferenceEquals (beforeLinkedChild.NextLinkedSibling, oldLinkedChild) == false)
+ throw new ArgumentException ();
+
+ beforeLinkedChild.NextLinkedSibling = oldLinkedChild.NextLinkedSibling;
+
+ // Each derived class may have its own LastLinkedChild, so we must set it explicitly.
+ if (oldLinkedChild.NextLinkedSibling == firstChild)
+ this.LastLinkedChild = beforeLinkedChild;
+
+ oldLinkedChild.NextLinkedSibling = null;
+ }
+
+ if (checkNodeType)
+ ownerDoc.onNodeRemoved (oldChild, oldChild.ParentNode);
+ oldChild.parentNode = null; // clear parent 'after' above logic.
+
+ return oldChild;
}
- [MonoTODO]
public virtual XmlNode ReplaceChild (XmlNode newChild, XmlNode oldChild)
{
- throw new NotImplementedException ();
+ if(oldChild.ParentNode != this)
+ throw new InvalidOperationException ("oldChild is not a child of this node.");
+
+ if (newChild == this || IsAncestor (newChild))
+ throw new ArgumentException("Cannot insert a node or any ancestor of that node as a child of itself.");
+
+ foreach(XmlNode n in ChildNodes) {
+ if(n == oldChild) {
+ XmlNode prev = oldChild.PreviousSibling;
+ RemoveChild (oldChild);
+ InsertAfter (newChild, prev);
+ break;
+ }
+ }
+ return oldChild;
+ }
+
+ internal void SearchDescendantElements (string name, bool matchAll, ArrayList list)
+ {
+ foreach (XmlNode n in ChildNodes){
+ if (n.NodeType != XmlNodeType.Element)
+ continue;
+ if (matchAll || n.Name == name)
+ list.Add (n);
+ n.SearchDescendantElements (name, matchAll, list);
+ }
}
- [MonoTODO]
- public virtual XmlNodeList SelectNodes (string xpath)
+ internal void SearchDescendantElements (string name, bool matchAllName, string ns, bool matchAllNS, ArrayList list)
{
- throw new NotImplementedException ();
+ foreach (XmlNode n in ChildNodes){
+ if (n.NodeType != XmlNodeType.Element)
+ continue;
+ if ((matchAllName || n.LocalName == name)
+ && (matchAllNS || n.NamespaceURI == ns))
+ list.Add (n);
+ n.SearchDescendantElements (name, matchAllName, ns, matchAllNS, list);
+ }
}
- [MonoTODO]
- public virtual XmlNodeList SelectNodes (string xpath, XmlNamespaceManager nsmgr)
+ public XmlNodeList SelectNodes (string xpath)
{
- throw new NotImplementedException ();
+ return SelectNodes (xpath, null);
}
- [MonoTODO]
- public virtual XmlNode SelectSingleNode (string xpath)
+ public XmlNodeList SelectNodes (string xpath, XmlNamespaceManager nsmgr)
{
- throw new NotImplementedException ();
+ 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);
}
- [MonoTODO]
- public virtual XmlNode SelectSingleNode (string xpath, XmlNamespaceManager nsmgr)
+ public XmlNode SelectSingleNode (string xpath)
{
- throw new NotImplementedException ();
+ return SelectSingleNode (xpath, null);
}
- internal void SetParentNode (XmlNode parent)
+ public XmlNode SelectSingleNode (string xpath, XmlNamespaceManager nsmgr)
{
- parentNode = parent;
+ 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;
}
- [MonoTODO]
public virtual bool Supports (string feature, string version)
{
- throw new NotImplementedException ();
+ if (String.Compare (feature, "xml", true) == 0 // not case-sensitive
+ && (String.Compare (version, "1.0", true) == 0
+ || String.Compare (version, "2.0", true) == 0))
+ return true;
+ else
+ return false;
}
- [MonoTODO]
public abstract void WriteContentTo (XmlWriter w);
- [MonoTODO]
public abstract void WriteTo (XmlWriter w);
+ // It parses this and all the ancestor elements,
+ // find 'xmlns' declarations, stores and then return them.
+ 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") {
+ if (nsmgr.LookupNamespace (attr.LocalName) != attr.Value)
+ nsmgr.AddNamespace (attr.LocalName, attr.Value);
+ } else if(attr.Name == "xmlns") {
+ if(nsmgr.LookupNamespace (String.Empty) != attr.Value)
+ nsmgr.AddNamespace (String.Empty, attr.Value);
+ }
+ }
+ // When reached to document, then it will set null value :)
+ el = el.ParentNode as XmlElement;
+ }
+ return nsmgr;
+ }
#endregion
}
}