//
// 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;
#region Properties
- public virtual XmlAttributeCollection Attributes
- {
+ public virtual XmlAttributeCollection Attributes {
get { return null; }
}
- public virtual string BaseURI
- {
- get { return ParentNode.BaseURI; }
+ 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);
+ return new XmlNodeListChildren (this);
}
}
get { return LastChild != null; }
}
- [MonoTODO]
+ [MonoTODO("confirm whether this way is right for each not-overriden types.")]
public virtual string InnerText {
get {
StringBuilder builder = new StringBuilder ();
StringWriter sw = new StringWriter ();
XmlTextWriter xtw = new XmlTextWriter (sw);
- WriteContentTo(xtw);
+ WriteContentTo (xtw);
- return sw.GetStringBuilder().ToString();
+ return sw.GetStringBuilder ().ToString ();
}
set { throw new NotImplementedException (); }
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);
+ WriteTo (xtw);
- return sw.GetStringBuilder().ToString();
+ return sw.GetStringBuilder ().ToString ();
}
}
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)
{
- XmlDocument ownerDoc = (NodeType == XmlNodeType.Document) ? (XmlDocument)this : OwnerDocument;
-
- ownerDoc.onNodeInserting (newChild, this);
-
- if (NodeType == XmlNodeType.Document || NodeType == XmlNodeType.Element || NodeType == XmlNodeType.Attribute) {
-
- if (newChild.OwnerDocument != ownerDoc)
- throw new ArgumentException ("Can't append a node created by another document.");
-
- XmlLinkedNode newLinkedChild = (XmlLinkedNode) newChild;
- XmlLinkedNode lastLinkedChild = LastLinkedChild;
-
- newLinkedChild.parentNode = this;
-
- if (lastLinkedChild != null) {
- newLinkedChild.NextLinkedSibling = lastLinkedChild.NextLinkedSibling;
- lastLinkedChild.NextLinkedSibling = newLinkedChild;
- } else
- newLinkedChild.NextLinkedSibling = newLinkedChild;
-
- LastLinkedChild = newLinkedChild;
-
- ownerDoc.onNodeInserted (newChild, newChild.ParentNode);
-
- return newChild;
- } 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 ()
{
- return new XmlDocumentNavigator(this);
+ return new XmlDocumentNavigator (this);
}
public IEnumerator GetEnumerator ()
{
- return new XmlNodeListChildren(this).GetEnumerator();
+ return new XmlNodeListChildren (this).GetEnumerator ();
}
- [MonoTODO]
+ [MonoTODO("performance problem.")]
public virtual string GetNamespaceOfPrefix (string prefix)
{
- throw new NotImplementedException ();
+ XmlNamespaceManager nsmgr = ConstructNamespaceManager ();
+ return nsmgr.LookupNamespace (prefix);
}
- [MonoTODO]
+ [MonoTODO("performance problem.")]
public virtual string GetPrefixOfNamespace (string namespaceURI)
{
- throw new NotImplementedException ();
+ XmlNamespaceManager nsmgr = ConstructNamespaceManager ();
+ string ns = nsmgr.LookupPrefix (namespaceURI);
+ return (ns != null) ? ns : String.Empty;
}
object ICloneable.Clone ()
return GetEnumerator ();
}
- [MonoTODO]
public virtual XmlNode InsertAfter (XmlNode newChild, XmlNode refChild)
{
- throw new NotImplementedException ();
+ // 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]
+ [MonoTODO("If inserted node is entity reference, then check conforming entity. Wait for DTD implementation.")]
public virtual XmlNode InsertBefore (XmlNode newChild, XmlNode refChild)
{
- throw new NotImplementedException ();
+ 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]
throw new NotImplementedException ();
}
- [MonoTODO]
public virtual XmlNode PrependChild (XmlNode newChild)
{
- throw new NotImplementedException ();
+ return InsertAfter (newChild, null);
}
public virtual void RemoveAll ()
{
- XmlDocument ownerDoc = (NodeType == XmlNodeType.Document) ? (XmlDocument)this : OwnerDocument;
-
- ownerDoc.onNodeRemoving (this, this.ParentNode);
- LastLinkedChild = null;
- ownerDoc.onNodeRemoved (this, this.ParentNode);
+ XmlNode next = null;
+ for (XmlNode node = FirstChild; node != null; node = next) {
+ next = node.NextSibling;
+ RemoveChild (node);
+ }
}
public virtual XmlNode RemoveChild (XmlNode oldChild)
{
- OwnerDocument.onNodeRemoving (oldChild, oldChild.ParentNode);
+ XmlDocument ownerDoc = (NodeType == XmlNodeType.Document) ? (XmlDocument)this : OwnerDocument;
+ if(oldChild.ParentNode != this)
+ throw new XmlException ("specified child is not child of this node.");
- if (NodeType == XmlNodeType.Document || NodeType == XmlNodeType.Element || NodeType == XmlNodeType.Attribute)
- {
+ ownerDoc.onNodeRemoving (oldChild, oldChild.ParentNode);
+
+ if (NodeType == XmlNodeType.Document || NodeType == XmlNodeType.Element || NodeType == XmlNodeType.Attribute || NodeType == XmlNodeType.DocumentFragment) {
if (IsReadOnly)
- throw new ArgumentException();
+ throw new ArgumentException ();
- if (Object.ReferenceEquals(LastLinkedChild, LastLinkedChild.NextLinkedSibling) && Object.ReferenceEquals(LastLinkedChild, oldChild))
+ 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))
+ while (!Object.ReferenceEquals (beforeLinkedChild.NextLinkedSibling, LastLinkedChild) && !Object.ReferenceEquals (beforeLinkedChild.NextLinkedSibling, oldLinkedChild))
beforeLinkedChild = beforeLinkedChild.NextLinkedSibling;
- if (!Object.ReferenceEquals(beforeLinkedChild.NextLinkedSibling, oldLinkedChild))
- throw new ArgumentException();
+ if (!Object.ReferenceEquals (beforeLinkedChild.NextLinkedSibling, oldLinkedChild))
+ throw new ArgumentException ();
beforeLinkedChild.NextLinkedSibling = oldLinkedChild.NextLinkedSibling;
oldLinkedChild.NextLinkedSibling = null;
}
- OwnerDocument.onNodeRemoved (oldChild, oldChild.ParentNode);
+ ownerDoc.onNodeRemoved (oldChild, oldChild.ParentNode);
+ oldChild.parentNode = null; // clear parent 'after' above logic.
return oldChild;
}
else
- throw new ArgumentException();
+ throw new ArgumentException ();
}
- [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.");
+ 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)
public abstract void WriteTo (XmlWriter w);
- // It parses with XmlReader and then construct DOM of the parsed contents.
- internal protected void ConstructDOM(XmlReader xmlReader, XmlNode currentNode)
- {
- // I am not confident whether this method should be placed in this class or not...
- // Please verify its validity and then erase this comment;-)
- XmlNode newNode;
- XmlDocument doc = currentNode is XmlDocument ? (XmlDocument)currentNode : currentNode.OwnerDocument;
- // Below are 'almost' copied from XmlDocument.Load(XmlReader xmlReader)
- while (xmlReader.Read ())
- {
- switch (xmlReader.NodeType) \r
- {
-
- case XmlNodeType.CDATA:
- newNode = doc.CreateCDataSection(xmlReader.Value);
- currentNode.AppendChild (newNode);
- break;
-
- case XmlNodeType.Comment:
- newNode = doc.CreateComment (xmlReader.Value);
- currentNode.AppendChild (newNode);
- break;
-
- case XmlNodeType.Element:
- XmlElement element = doc.CreateElement (xmlReader.Prefix, xmlReader.LocalName, xmlReader.NamespaceURI);
- currentNode.AppendChild (element);
-
- // set the element's attributes.
- while (xmlReader.MoveToNextAttribute ()) \r
- {
- XmlAttribute attribute = doc.CreateAttribute (xmlReader.Prefix, xmlReader.LocalName, xmlReader.NamespaceURI);
- attribute.Value = xmlReader.Value;
- element.SetAttributeNode (attribute);
- }
-
- xmlReader.MoveToElement ();
-
- // if this element isn't empty, push it onto our "stack".
- if (!xmlReader.IsEmptyElement)
- currentNode = element;
-
- break;
-
- case XmlNodeType.EndElement:
- currentNode = currentNode.ParentNode;
- break;
-
- case XmlNodeType.ProcessingInstruction:
- newNode = doc.CreateProcessingInstruction (xmlReader.Name, xmlReader.Value);
- currentNode.AppendChild (newNode);
- break;
-
- case XmlNodeType.Text:
- newNode = doc.CreateTextNode (xmlReader.Value);
- currentNode.AppendChild (newNode);
- break;
-
- case XmlNodeType.XmlDeclaration:\r
- // String Empties are dummy, then gives over setting value contents to setter.\r
- newNode = doc.CreateNode(XmlNodeType.XmlDeclaration, String.Empty, String.Empty);\r
- ((XmlDeclaration)newNode).Value = xmlReader.Value;\r
- this.AppendChild(newNode);\r
- break;\r
- }
- }
- }
-
// It parses this and all the ancestor elements,
// find 'xmlns' declarations, stores and then return them.
// TODO: tests
- internal protected XmlNamespaceManager ConstructNamespaceManager()
+ internal XmlNamespaceManager ConstructNamespaceManager ()
{
XmlDocument doc = this is XmlDocument ? (XmlDocument)this : this.OwnerDocument;
- XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
+ 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;
+ 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) == null )
- {
- nsmgr.AddNamespace(attr.LocalName, attr.Value);
- }
+ 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 :)