// // System.Xml.XmlNode // // Author: // Kral Ferch // Atsushi Enomoto // // (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); // Below are formerly used logic. /* 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."); // 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 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."); if (refChild != null && this == ownerDoc && ownerDoc.DocumentElement != null && (newChild is XmlElement || newChild is XmlCharacterData || newChild is XmlEntityReference)) throw new XmlException ("cannot insert this node to this position."); // 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