XmlNode.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / whidbey / REDBITS / ndp / fx / src / Xml / System / Xml / Dom / XmlNode.cs / 2 / XmlNode.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
//-----------------------------------------------------------------------------
 
namespace System.Xml { 
    using System;
    using System.IO; 
    using System.Collections;
    using System.Text;
    using System.Diagnostics;
    using System.Xml.Schema; 
    using System.Xml.XPath;
    using MS.Internal.Xml.XPath; 
    using System.Globalization; 

    // Represents a single node in the document. 
    [DebuggerDisplay("{debuggerDisplayProxy}")]
    public abstract class XmlNode : ICloneable, IEnumerable, IXPathNavigable {
        internal XmlNode parentNode; //this pointer is reused to save the userdata information, need to prevent internal user access the pointer directly.
 
        internal XmlNode () {
        } 
 
        internal XmlNode( XmlDocument doc ) {
            if ( doc == null ) 
                throw new ArgumentException(Res.GetString(Res.Xdom_Node_Null_Doc));
            this.parentNode = doc;
        }
 
        public virtual XPathNavigator CreateNavigator() {
            XmlDocument doc = OwnerDocument; 
            Debug.Assert( doc != null ); 
            return doc.CreateNavigator( this );
        } 

        // Selects the first node that matches the xpath expression
        public XmlNode SelectSingleNode( string xpath ) {
            XmlNodeList list = SelectNodes(xpath); 
            //since SelectNodes could return null for certain node types
            if( ( list != null ) && ( list.Count > 0 ) ) 
                return list[0]; 
            else
                return null; 
        }

        // Selects the first node that matches the xpath expression and given namespace context.
        public XmlNode SelectSingleNode( string xpath, XmlNamespaceManager nsmgr ) { 
            XPathNavigator xn = (this).CreateNavigator();
            //if the method is called on node types like DocType, Entity, XmlDeclaration, 
            //the navigator returned is null. So just return null from here for those node types. 
            if( xn == null )
                return null; 
            XPathExpression exp = xn.Compile(xpath);
            exp.SetContext(nsmgr);
            XmlNodeList list = new XPathNodeList( xn.Select(exp) );;
            if( list.Count > 0 ) 
                return list[0];
            else 
                return null; 
        }
 
        // Selects all nodes that match the xpath expression
        public XmlNodeList SelectNodes( string xpath ) {
            XPathNavigator n = (this).CreateNavigator();
            //if the method is called on node types like DocType, Entity, XmlDeclaration, 
            //the navigator returned is null. So just return null from here for those node types.
            if( n == null ) 
                return null; 
            return new XPathNodeList( n.Select(xpath) );
        } 

        // Selects all nodes that match the xpath expression and given namespace context.
        public XmlNodeList SelectNodes( string xpath, XmlNamespaceManager nsmgr ) {
            XPathNavigator xn = (this).CreateNavigator(); 
            //if the method is called on node types like DocType, Entity, XmlDeclaration,
            //the navigator returned is null. So just return null from here for those node types. 
            if( xn == null ) 
                return null;
            XPathExpression exp = xn.Compile(xpath); 
            exp.SetContext(nsmgr);
            return new XPathNodeList( xn.Select(exp) );
        }
 
        // Gets the name of the node.
        public abstract string Name { 
            get; 
        }
 
        // Gets or sets the value of the node.
        public virtual string Value {
            get { return null;}
            set { throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, Res.GetString(Res.Xdom_Node_SetVal), NodeType.ToString()));} 
        }
 
        // Gets the type of the current node. 
        public abstract XmlNodeType NodeType {
            get; 
        }

        // Gets the parent of this node (for nodes that can have parents).
        public virtual XmlNode ParentNode { 
            get {
                Debug.Assert(parentNode != null); 
 
                if (parentNode.NodeType != XmlNodeType.Document) {
                    return parentNode; 
                }

                // Linear lookup through the children of the document
                XmlLinkedNode firstChild = parentNode.FirstChild as XmlLinkedNode; 
                if (firstChild != null) {
                    XmlLinkedNode node = firstChild; 
                    do { 
                        if (node == this) {
                            return parentNode; 
                        }
                        node = node.next;
                    }
                    while (node != null 
                           && node != firstChild);
                } 
                return null; 
            }
        } 

        // Gets all children of this node.
        public virtual XmlNodeList ChildNodes {
            get { return new XmlChildNodes(this);} 
        }
 
        // Gets the node immediately preceding this node. 
        public virtual XmlNode PreviousSibling {
            get { return null;} 
        }

        // Gets the node immediately following this node.
        public virtual XmlNode NextSibling { 
            get { return null;}
        } 
 
        // Gets a XmlAttributeCollection containing the attributes
        // of this node. 
        public virtual XmlAttributeCollection Attributes {
            get { return null;}
        }
 
        // Gets the XmlDocument that contains this node.
        public virtual XmlDocument OwnerDocument { 
            get { 
                Debug.Assert( parentNode != null );
                if ( parentNode.NodeType == XmlNodeType.Document) 
                    return (XmlDocument)parentNode;
                return parentNode.OwnerDocument;
            }
        } 

        // Gets the first child of this node. 
        public virtual XmlNode FirstChild { 
            get {
                XmlLinkedNode linkedNode = LastNode; 
                if (linkedNode != null)
                    return linkedNode.next;

                return null; 
            }
        } 
 
        // Gets the last child of this node.
        public virtual XmlNode LastChild { 
            get { return LastNode;}
        }

        internal virtual bool IsContainer { 
            get { return false;}
        } 
 
        internal virtual XmlLinkedNode LastNode {
            get { return null;} 
            set {}
        }

        internal bool AncestorNode(XmlNode node) { 
            XmlNode n = this.ParentNode;
 
            while (n != null && n != this) { 
                if (n == node)
                    return true; 
                n = n.ParentNode;
            }

            return false; 
        }
 
        //trace to the top to find out its parent node. 
        internal bool IsConnected()
        { 
            XmlNode parent = ParentNode;
            while (parent != null && !( parent.NodeType == XmlNodeType.Document ))
                parent = parent.ParentNode;
            return parent != null; 
        }
 
        // Inserts the specified node immediately before the specified reference node. 
        public virtual XmlNode InsertBefore(XmlNode newChild, XmlNode refChild) {
            if (this == newChild || AncestorNode(newChild)) 
                throw new ArgumentException(Res.GetString(Res.Xdom_Node_Insert_Child));

            if (refChild == null)
                return AppendChild(newChild); 

            if (!IsContainer) 
                throw new InvalidOperationException(Res.GetString(Res.Xdom_Node_Insert_Contain)); 

            if (refChild.ParentNode != this) 
                throw new ArgumentException(Res.GetString(Res.Xdom_Node_Insert_Path));

            if (newChild == refChild)
                return newChild; 

            XmlDocument childDoc = newChild.OwnerDocument; 
            XmlDocument thisDoc = OwnerDocument; 
            if (childDoc != null && childDoc != thisDoc && childDoc != this)
                throw new ArgumentException(Res.GetString(Res.Xdom_Node_Insert_Context)); 

            if (!CanInsertBefore( newChild, refChild ))
                throw new InvalidOperationException(Res.GetString(Res.Xdom_Node_Insert_Location));
 
            if (newChild.ParentNode != null)
                newChild.ParentNode.RemoveChild( newChild ); 
 
            // special case for doc-fragment.
            if (newChild.NodeType == XmlNodeType.DocumentFragment) { 
                XmlNode first = newChild.FirstChild;
                XmlNode node = first;
                if (node != null) {
                    newChild.RemoveChild( node ); 
                    InsertBefore( node, refChild );
                    // insert the rest of the children after this one. 
                    InsertAfter( newChild, node ); 
                }
                return first; 
            }

            if (!(newChild is XmlLinkedNode) || !IsValidChildType(newChild.NodeType))
                throw new InvalidOperationException(Res.GetString(Res.Xdom_Node_Insert_TypeConflict)); 

            XmlLinkedNode newNode = (XmlLinkedNode) newChild; 
            XmlLinkedNode refNode = (XmlLinkedNode) refChild; 

            string newChildValue = newChild.Value; 
            XmlNodeChangedEventArgs args = GetEventArgs( newChild, newChild.ParentNode, this, newChildValue, newChildValue, XmlNodeChangedAction.Insert );

            if (args != null)
                BeforeEvent( args ); 

            if (refNode == FirstChild) { 
                newNode.next = refNode; 
                LastNode.next = newNode;
                newNode.SetParent(this); 

                if (newNode.IsText) {
                    if (refNode.IsText) {
                        NestTextNodes(newNode, refNode); 
                    }
                } 
            } 
            else {
                XmlLinkedNode prevNode = (XmlLinkedNode) refNode.PreviousSibling; 

                newNode.next = refNode;
                prevNode.next = newNode;
                newNode.SetParent(this); 

                if (prevNode.IsText) { 
                    if (newNode.IsText) { 
                        NestTextNodes(prevNode, newNode);
                        if (refNode.IsText) { 
                            NestTextNodes(newNode, refNode);
                        }
                    }
                    else { 
                        if (refNode.IsText) {
                            UnnestTextNodes(prevNode, refNode); 
                        } 
                    }
                } 
                else {
                    if (newNode.IsText) {
                        if (refNode.IsText) {
                            NestTextNodes(newNode, refNode); 
                        }
                    } 
                } 
            }
 
            if (args != null)
                AfterEvent( args );

            return newNode; 
        }
 
        // Inserts the specified node immediately after the specified reference node. 
        public virtual XmlNode InsertAfter(XmlNode newChild, XmlNode refChild) {
            if (this == newChild || AncestorNode(newChild)) 
                throw new ArgumentException(Res.GetString(Res.Xdom_Node_Insert_Child));

            if (refChild == null)
                return PrependChild(newChild); 

            if (!IsContainer) 
                throw new InvalidOperationException(Res.GetString(Res.Xdom_Node_Insert_Contain)); 

            if (refChild.ParentNode != this) 
                throw new ArgumentException(Res.GetString(Res.Xdom_Node_Insert_Path));

            if (newChild == refChild)
                return newChild; 

            XmlDocument childDoc = newChild.OwnerDocument; 
            XmlDocument thisDoc = OwnerDocument; 
            if (childDoc != null && childDoc != thisDoc && childDoc != this)
                throw new ArgumentException(Res.GetString(Res.Xdom_Node_Insert_Context)); 

            if (!CanInsertAfter( newChild, refChild ))
                throw new InvalidOperationException(Res.GetString(Res.Xdom_Node_Insert_Location));
 
            if (newChild.ParentNode != null)
                newChild.ParentNode.RemoveChild( newChild ); 
 
            // special case for doc-fragment.
            if (newChild.NodeType == XmlNodeType.DocumentFragment) { 
                XmlNode last = refChild;
                XmlNode first = newChild.FirstChild;
                XmlNode node = first;
                while (node != null) { 
                    XmlNode next = node.NextSibling;
                    newChild.RemoveChild( node ); 
                    InsertAfter( node, last ); 
                    last = node;
                    node = next; 
                }
                return first;
            }
 
            if (!(newChild is XmlLinkedNode) || !IsValidChildType(newChild.NodeType))
                throw new InvalidOperationException(Res.GetString(Res.Xdom_Node_Insert_TypeConflict)); 
 
            XmlLinkedNode newNode = (XmlLinkedNode) newChild;
            XmlLinkedNode refNode = (XmlLinkedNode) refChild; 

            string newChildValue = newChild.Value;
            XmlNodeChangedEventArgs args = GetEventArgs( newChild, newChild.ParentNode, this, newChildValue, newChildValue, XmlNodeChangedAction.Insert );
 
            if (args != null)
                BeforeEvent( args ); 
 
            if (refNode == LastNode) {
                newNode.next = refNode.next; 
                refNode.next = newNode;
                LastNode = newNode;
                newNode.SetParent(this);
 
                if (refNode.IsText) {
                    if (newNode.IsText) { 
                        NestTextNodes(refNode, newNode); 
                    }
                } 
            }
            else {
                XmlLinkedNode nextNode = refNode.next;
 
                newNode.next = nextNode;
                refNode.next = newNode; 
                newNode.SetParent(this); 

                if (refNode.IsText) { 
                    if (newNode.IsText) {
                        NestTextNodes(refNode, newNode);
                        if (nextNode.IsText) {
                            NestTextNodes(newNode, nextNode); 
                        }
                    } 
                    else { 
                        if (nextNode.IsText) {
                            UnnestTextNodes(refNode, nextNode); 
                        }
                    }
                }
                else { 
                    if (newNode.IsText) {
                        if (nextNode.IsText) { 
                            NestTextNodes(newNode, nextNode); 
                        }
                    } 
                }
            }

 
            if (args != null)
                AfterEvent( args ); 
 
            return newNode;
        } 

        // Replaces the child node oldChild with newChild node.
        public virtual XmlNode ReplaceChild(XmlNode newChild, XmlNode oldChild) {
            XmlNode nextNode = oldChild.NextSibling; 
            RemoveChild(oldChild);
            XmlNode node = InsertBefore( newChild, nextNode ); 
            return oldChild; 
        }
 
        // Removes specified child node.
        public virtual XmlNode RemoveChild(XmlNode oldChild) {
            if (!IsContainer)
                throw new InvalidOperationException(Res.GetString(Res.Xdom_Node_Remove_Contain)); 

            if (oldChild.ParentNode != this) 
                throw new ArgumentException(Res.GetString(Res.Xdom_Node_Remove_Child)); 

            XmlLinkedNode oldNode = (XmlLinkedNode) oldChild; 

            string oldNodeValue = oldNode.Value;
            XmlNodeChangedEventArgs args = GetEventArgs( oldNode, this, null, oldNodeValue, oldNodeValue, XmlNodeChangedAction.Remove );
 
            if (args != null)
                BeforeEvent( args ); 
 
            XmlLinkedNode lastNode = LastNode;
 
            if (oldNode == FirstChild) {
                if (oldNode == lastNode) {
                    LastNode = null;
                    oldNode.next = null; 
                    oldNode.SetParent( null );
                } 
                else { 
                    XmlLinkedNode nextNode = oldNode.next;
 
                    if (nextNode.IsText) {
                        if (oldNode.IsText) {
                            UnnestTextNodes(oldNode, nextNode);
                        } 
                    }
 
                    lastNode.next = nextNode; 
                    oldNode.next = null;
                    oldNode.SetParent( null ); 
                }
            }
            else {
                if (oldNode == lastNode) { 
                    XmlLinkedNode prevNode = (XmlLinkedNode) oldNode.PreviousSibling;
                    prevNode.next = oldNode.next; 
                    LastNode = prevNode; 
                    oldNode.next = null;
                    oldNode.SetParent(null); 
                }
                else {
                    XmlLinkedNode prevNode = (XmlLinkedNode) oldNode.PreviousSibling;
                    XmlLinkedNode nextNode = oldNode.next; 

                    if (nextNode.IsText) { 
                        if (prevNode.IsText) { 
                            NestTextNodes(prevNode, nextNode);
                        } 
                        else {
                            if (oldNode.IsText) {
                                UnnestTextNodes(oldNode, nextNode);
                            } 
                        }
                    } 
 
                    prevNode.next = nextNode;
                    oldNode.next = null; 
                    oldNode.SetParent(null);
                }
            }
 
            if (args != null)
                AfterEvent( args ); 
 
            return oldChild;
        } 

        // Adds the specified node to the beginning of the list of children of this node.
        public virtual XmlNode PrependChild(XmlNode newChild) {
            return InsertBefore(newChild, FirstChild); 
        }
 
        // Adds the specified node to the end of the list of children of this node. 
        public virtual XmlNode AppendChild(XmlNode newChild) {
            XmlDocument thisDoc = OwnerDocument; 
            if ( thisDoc == null ) {
                thisDoc = this as XmlDocument;
            }
            if (!IsContainer) 
                throw new InvalidOperationException(Res.GetString(Res.Xdom_Node_Insert_Contain));
 
            if (this == newChild || AncestorNode(newChild)) 
                throw new ArgumentException(Res.GetString(Res.Xdom_Node_Insert_Child));
 
            if (newChild.ParentNode != null)
                newChild.ParentNode.RemoveChild( newChild );

            XmlDocument childDoc = newChild.OwnerDocument; 
            if (childDoc != null && childDoc != thisDoc && childDoc != this)
                throw new ArgumentException(Res.GetString(Res.Xdom_Node_Insert_Context)); 
 
            // special case for doc-fragment.
            if (newChild.NodeType == XmlNodeType.DocumentFragment) { 
                XmlNode first = newChild.FirstChild;
                XmlNode node = first;
                while (node != null) {
                    XmlNode next = node.NextSibling; 
                    newChild.RemoveChild( node );
                    AppendChild( node ); 
                    node = next; 
                }
                return first; 
            }

            if (!(newChild is XmlLinkedNode) || !IsValidChildType(newChild.NodeType))
                throw new InvalidOperationException(Res.GetString(Res.Xdom_Node_Insert_TypeConflict)); 

 
            if (!CanInsertAfter( newChild, LastChild )) 
                throw new InvalidOperationException(Res.GetString(Res.Xdom_Node_Insert_Location));
 
            string newChildValue = newChild.Value;
            XmlNodeChangedEventArgs args = GetEventArgs( newChild, newChild.ParentNode, this, newChildValue, newChildValue, XmlNodeChangedAction.Insert );

            if (args != null) 
                BeforeEvent( args );
 
            XmlLinkedNode refNode = LastNode; 
            XmlLinkedNode newNode = (XmlLinkedNode) newChild;
 
            if (refNode == null) {
                newNode.next = newNode;
                LastNode = newNode;
                newNode.SetParent(this); 
            }
            else { 
                newNode.next = refNode.next; 
                refNode.next = newNode;
                LastNode = newNode; 
                newNode.SetParent(this);

                if (refNode.IsText) {
                    if (newNode.IsText) { 
                        NestTextNodes(refNode, newNode);
                    } 
                } 
            }
 
            if (args != null)
                AfterEvent( args );

            return newNode; 
        }
 
        //the function is provided only at Load time to speed up Load process 
        internal virtual XmlNode AppendChildForLoad(XmlNode newChild, XmlDocument doc) {
            XmlNodeChangedEventArgs args = doc.GetInsertEventArgsForLoad( newChild, this ); 

            if (args != null)
                doc.BeforeEvent( args );
 
            XmlLinkedNode refNode = LastNode;
            XmlLinkedNode newNode = (XmlLinkedNode) newChild; 
 
            if (refNode == null) {
                newNode.next = newNode; 
                LastNode = newNode;
                newNode.SetParentForLoad(this);
            }
            else { 
                newNode.next = refNode.next;
                refNode.next = newNode; 
                LastNode = newNode; 
                if (refNode.IsText
                    && newNode.IsText) { 
                    NestTextNodes(refNode, newNode);
                }
                else {
                    newNode.SetParentForLoad(this); 
                }
            } 
 
            if (args != null)
                doc.AfterEvent( args ); 

            return newNode;
        }
 
        internal virtual bool IsValidChildType( XmlNodeType type ) {
            return false; 
        } 

        internal virtual bool CanInsertBefore( XmlNode newChild, XmlNode refChild ) { 
            return true;
        }

        internal virtual bool CanInsertAfter( XmlNode newChild, XmlNode refChild ) { 
            return true;
        } 
 
        // Gets a value indicating whether this node has any child nodes.
        public virtual bool HasChildNodes { 
            get { return LastNode != null;}
        }

        // Creates a duplicate of this node. 
        public abstract XmlNode CloneNode(bool deep);
 
        internal virtual void CopyChildren( XmlDocument doc, XmlNode container, bool deep ) { 
            for (XmlNode child = container.FirstChild; child != null; child = child.NextSibling) {
                AppendChildForLoad( child.CloneNode(deep), doc ); 
            }
        }

        // DOM Level 2 

        // Puts all XmlText nodes in the full depth of the sub-tree 
        // underneath this XmlNode into a "normal" form where only 
        // markup (e.g., tags, comments, processing instructions, CDATA sections,
        // and entity references) separates XmlText nodes, that is, there 
        // are no adjacent XmlText nodes.
        public virtual void Normalize() {
            XmlNode firstChildTextLikeNode = null;
            StringBuilder sb = new StringBuilder(); 
            for ( XmlNode crtChild = this.FirstChild; crtChild != null; ) {
                XmlNode nextChild = crtChild.NextSibling; 
                switch ( crtChild.NodeType ) { 
                    case XmlNodeType.Text:
                    case XmlNodeType.Whitespace: 
                    case XmlNodeType.SignificantWhitespace: {
                        sb.Append( crtChild.Value );
                        XmlNode winner = NormalizeWinner( firstChildTextLikeNode, crtChild );
                        if ( winner == firstChildTextLikeNode ) { 
                            this.RemoveChild( crtChild );
                        } 
                        else { 
                            if ( firstChildTextLikeNode != null )
                                this.RemoveChild( firstChildTextLikeNode ); 
                            firstChildTextLikeNode = crtChild;
                        }
                        break;
                    } 
                    case XmlNodeType.Element: {
                        crtChild.Normalize(); 
                        goto default; 
                    }
                    default : { 
                        if ( firstChildTextLikeNode != null ) {
                            firstChildTextLikeNode.Value = sb.ToString();
                            firstChildTextLikeNode = null;
                        } 
                        sb.Remove( 0, sb.Length );
 			break; 
                    } 
                }
                crtChild = nextChild; 
            }
            if ( firstChildTextLikeNode != null && sb.Length > 0 )
                firstChildTextLikeNode.Value = sb.ToString();
        } 

        private XmlNode NormalizeWinner( XmlNode firstNode, XmlNode secondNode ) { 
            //first node has the priority 
            if ( firstNode == null )
                return secondNode; 
            Debug.Assert( firstNode.NodeType == XmlNodeType.Text
                        || firstNode.NodeType == XmlNodeType.SignificantWhitespace
                        || firstNode.NodeType == XmlNodeType.Whitespace
                        || secondNode.NodeType == XmlNodeType.Text 
                        || secondNode.NodeType == XmlNodeType.SignificantWhitespace
                        || secondNode.NodeType == XmlNodeType.Whitespace ); 
            if ( firstNode.NodeType == XmlNodeType.Text ) 
                return firstNode;
            if ( secondNode.NodeType == XmlNodeType.Text ) 
                return secondNode;
            if ( firstNode.NodeType == XmlNodeType.SignificantWhitespace )
                return firstNode;
            if ( secondNode.NodeType == XmlNodeType.SignificantWhitespace ) 
                return secondNode;
            if ( firstNode.NodeType == XmlNodeType.Whitespace ) 
                return firstNode; 
            if ( secondNode.NodeType == XmlNodeType.Whitespace )
                return secondNode; 
            Debug.Assert( true, "shouldn't have fall through here." );
            return null;
        }
 
        // Test if the DOM implementation implements a specific feature.
        public virtual bool Supports(string feature, string version) { 
            if (String.Compare("XML", feature, StringComparison.OrdinalIgnoreCase) == 0) { 
                if (version == null || version == "1.0" || version == "2.0")
                    return true; 
            }
            return false;
        }
 
        // Gets the namespace URI of this node.
        public virtual string NamespaceURI { 
            get { return string.Empty;} 
        }
 
        // Gets or sets the namespace prefix of this node.
        public virtual string Prefix {
            get { return string.Empty;}
            set {} 
        }
 
        // Gets the name of the node without the namespace prefix. 
        public abstract string LocalName {
            get; 
        }

        // Microsoft extensions
 
        // Gets a value indicating whether the node is read-only.
        public virtual bool IsReadOnly { 
            get { 
                XmlDocument doc = OwnerDocument;
                return HasReadOnlyParent( this ); 
            }
        }

        internal static bool HasReadOnlyParent( XmlNode n ) { 
            while (n != null) {
                switch (n.NodeType) { 
                    case XmlNodeType.EntityReference: 
                    case XmlNodeType.Entity:
                        return true; 

                    case XmlNodeType.Attribute:
                    n = ((XmlAttribute)n).OwnerElement;
                        break; 

                    default: 
                    n = n.ParentNode; 
                        break;
                } 
            }
            return false;
        }
 
        // Creates a duplicate of this node.
        public virtual XmlNode Clone() { 
            return this.CloneNode(true); 
        }
 
        object ICloneable.Clone() {
            return this.CloneNode(true);
        }
 
        // Provides a simple ForEach-style iteration over the
        // collection of nodes in this XmlNamedNodeMap. 
        IEnumerator IEnumerable.GetEnumerator() { 
            return new XmlChildEnumerator(this);
        } 

        public IEnumerator GetEnumerator() {
            return new XmlChildEnumerator(this);
        } 

        private void AppendChildText( StringBuilder builder ) { 
            for (XmlNode child = FirstChild; child != null; child = child.NextSibling) { 
                if (child.FirstChild == null) {
                    if (child.NodeType == XmlNodeType.Text || child.NodeType == XmlNodeType.CDATA 
                        || child.NodeType == XmlNodeType.Whitespace || child.NodeType == XmlNodeType.SignificantWhitespace)
                        builder.Append( child.InnerText );
                }
                else { 
                    child.AppendChildText( builder );
                } 
            } 
        }
 
        // Gets or sets the concatenated values of the node and
        // all its children.
        public virtual string InnerText {
            get { 
                XmlNode fc = FirstChild;
                if (fc == null) { 
                    return string.Empty; 
                }
                if (fc.NextSibling == null) { 
                    XmlNodeType nodeType = fc.NodeType;
                    switch (nodeType) {
                        case XmlNodeType.Text:
                        case XmlNodeType.CDATA: 
                        case XmlNodeType.Whitespace:
                        case XmlNodeType.SignificantWhitespace: 
                            return fc.Value; 
                    }
                } 
                StringBuilder builder = new StringBuilder();
                AppendChildText( builder );
                return builder.ToString();
            } 

            set { 
                XmlNode firstChild = FirstChild; 
                if ( firstChild != null  //there is one child
                    && firstChild.NextSibling == null // and exactly one 
                    && firstChild.NodeType == XmlNodeType.Text )//which is a text node
                {
                    //this branch is for perf reason and event fired when TextNode.Value is changed
                    firstChild.Value = value; 
                }
                else { 
                    RemoveAll(); 
                    AppendChild( OwnerDocument.CreateTextNode( value ) );
                } 
            }
        }

        // Gets the markup representing this node and all its children. 
        public virtual string OuterXml {
            get { 
                StringWriter sw = new StringWriter(CultureInfo.InvariantCulture); 
                XmlDOMTextWriter xw = new XmlDOMTextWriter( sw );
                try { 
                    WriteTo( xw );
                }
                finally {
                    xw.Close(); 
                }
                return sw.ToString(); 
            } 
        }
 
        // Gets or sets the markup representing just the children of this node.
        public virtual string InnerXml {
            get {
                StringWriter sw = new StringWriter(CultureInfo.InvariantCulture); 
                XmlDOMTextWriter xw = new XmlDOMTextWriter( sw );
                try { 
                    WriteContentTo( xw ); 
                }
                finally { 
                    xw.Close();
                }
                return sw.ToString();
            } 

            set { 
                throw new InvalidOperationException( Res.GetString(Res.Xdom_Set_InnerXml ) ); 
            }
        } 

        public virtual IXmlSchemaInfo SchemaInfo {
            get {
                return XmlDocument.NotKnownSchemaInfo; 
            }
        } 
 
        public virtual String BaseURI {
            get { 
                XmlNode curNode = this.ParentNode; //save one while loop since if going to here, the nodetype of this node can't be document, entity and entityref
                while ( curNode != null ) {
                    XmlNodeType nt = curNode.NodeType;
                    //EntityReference's children come from the dtd where they are defined. 
                    //we need to investigate the same thing for entity's children if they are defined in an external dtd file.
                    if ( nt == XmlNodeType.EntityReference ) 
                        return ((XmlEntityReference)curNode).ChildBaseURI; 
                    if ( nt == XmlNodeType.Document
                        || nt == XmlNodeType.Entity 
                        || nt == XmlNodeType.Attribute )
                        return curNode.BaseURI;
                    curNode = curNode.ParentNode;
                } 
                return String.Empty;
            } 
        } 

        // Saves the current node to the specified XmlWriter. 
        public abstract void WriteTo(XmlWriter w);

        // Saves all the children of the node to the specified XmlWriter.
        public abstract void WriteContentTo(XmlWriter w); 

        // Removes all the children and/or attributes 
        // of the current node. 
        public virtual void RemoveAll() {
            XmlNode child = FirstChild; 
            XmlNode sibling = null;

            while (child != null) {
                sibling = child.NextSibling; 
                RemoveChild( child );
                child = sibling; 
            } 
        }
 
        internal XmlDocument Document {
            get {
                if (NodeType == XmlNodeType.Document)
                    return (XmlDocument)this; 
                return OwnerDocument;
            } 
        } 

        // Looks up the closest xmlns declaration for the given 
        // prefix that is in scope for the current node and returns
        // the namespace URI in the declaration.
        public virtual string GetNamespaceOfPrefix(string prefix) {
            string namespaceName = GetNamespaceOfPrefixStrict(prefix); 
            return namespaceName != null ? namespaceName : string.Empty;
        } 
 
        internal string GetNamespaceOfPrefixStrict(string prefix) {
            XmlDocument doc = Document; 
            if (doc != null) {
                prefix = doc.NameTable.Get(prefix);
                if (prefix == null)
                    return null; 

                XmlNode node = this; 
                while (node != null) { 
                    if (node.NodeType == XmlNodeType.Element) {
                        XmlElement elem = (XmlElement)node; 
                        if (elem.HasAttributes) {
                            XmlAttributeCollection attrs = elem.Attributes;
                            if (prefix.Length == 0) {
                                for (int iAttr = 0; iAttr < attrs.Count; iAttr++) { 
                                    XmlAttribute attr = attrs[iAttr];
                                    if (attr.Prefix.Length == 0) { 
                                        if (Ref.Equal(attr.LocalName, doc.strXmlns)) { 
                                            return attr.Value; // found xmlns
                                        } 
                                    }
                                }
                            }
                            else { 
                                for (int iAttr = 0; iAttr < attrs.Count; iAttr++) {
                                    XmlAttribute attr = attrs[iAttr]; 
                                    if (Ref.Equal(attr.Prefix, doc.strXmlns)) { 
                                        if (Ref.Equal(attr.LocalName, prefix)) {
                                            return attr.Value; // found xmlns:prefix 
                                        }
                                    }
                                    else if (Ref.Equal(attr.Prefix, prefix)) {
                                        return attr.NamespaceURI; // found prefix:attr 
                                    }
                                } 
                            } 
                        }
                        if (Ref.Equal(node.Prefix, prefix)) { 
                            return node.NamespaceURI;
                        }
                        node = node.ParentNode;
                    } 
                    else if (node.NodeType == XmlNodeType.Attribute) {
                        node = ((XmlAttribute)node).OwnerElement; 
                    } 
                    else {
                        node = node.ParentNode; 
                    }
                }
                if (Ref.Equal(doc.strXml, prefix)) { // xmlns:xml
                    return doc.strReservedXml; 
                }
                else if (Ref.Equal(doc.strXmlns, prefix)) { // xmlns:xmlns 
                    return doc.strReservedXmlns; 
                }
            } 
            return null;
        }

        // Looks up the closest xmlns declaration for the given namespace 
        // URI that is in scope for the current node and returns
        // the prefix defined in that declaration. 
        public virtual string GetPrefixOfNamespace(string namespaceURI) { 
            string prefix = GetPrefixOfNamespaceStrict(namespaceURI);
            return prefix != null ? prefix : string.Empty; 
        }

        internal string GetPrefixOfNamespaceStrict(string namespaceURI) {
            XmlDocument doc = Document; 
            if (doc != null) {
                namespaceURI = doc.NameTable.Add(namespaceURI); 
 
                XmlNode node = this;
                while (node != null) { 
                    if (node.NodeType == XmlNodeType.Element) {
                        XmlElement elem = (XmlElement)node;
                        if (elem.HasAttributes) {
                            XmlAttributeCollection attrs = elem.Attributes; 
                            for (int iAttr = 0; iAttr < attrs.Count; iAttr++) {
                                XmlAttribute attr = attrs[iAttr]; 
                                if (attr.Prefix.Length == 0) { 
                                    if (Ref.Equal(attr.LocalName, doc.strXmlns)) {
                                        if (attr.Value == namespaceURI) { 
                                            return string.Empty; // found xmlns="namespaceURI"
                                        }
                                    }
                                } 
                                else if (Ref.Equal(attr.Prefix, doc.strXmlns)) {
                                    if (attr.Value == namespaceURI) { 
                                        return attr.LocalName; // found xmlns:prefix="namespaceURI" 
                                    }
                                } 
                                else if (Ref.Equal(attr.NamespaceURI, namespaceURI)) {
                                    return attr.Prefix; // found prefix:attr
                                                        // with prefix bound to namespaceURI
                                } 
                            }
                        } 
                        if (Ref.Equal(node.NamespaceURI, namespaceURI)) { 
                            return node.Prefix;
                        } 
                        node = node.ParentNode;
                    }
                    else if (node.NodeType == XmlNodeType.Attribute) {
                        node = ((XmlAttribute)node).OwnerElement; 
                    }
                    else { 
                        node = node.ParentNode; 
                    }
                } 
                if (Ref.Equals(doc.strReservedXml, namespaceURI)) { // xmlns:xml
                    return doc.strXml;
                }
                else if (Ref.Equals(doc.strReservedXmlns, namespaceURI)) { // xmlns:xmlns 
                    return doc.strXmlns;
                } 
            } 
            return null;
        } 

        // Retrieves the first child element with the specified name.
        public virtual XmlElement this[string name]
        { 
            get {
                for (XmlNode n = FirstChild; n != null; n = n.NextSibling) { 
                    if (n.NodeType == XmlNodeType.Element && n.Name == name) 
                        return(XmlElement) n;
                } 
                return null;
            }
        }
 
        // Retrieves the first child element with the specified LocalName and
        // NamespaceURI. 
        public virtual XmlElement this[string localname, string ns] 
        {
            get { 
                for (XmlNode n = FirstChild; n != null; n = n.NextSibling) {
                    if (n.NodeType == XmlNodeType.Element && n.LocalName == localname && n.NamespaceURI == ns)
                        return(XmlElement) n;
                } 
                return null;
            } 
        } 

 
        internal virtual void SetParent( XmlNode node ) {
            if (node == null) {
                this.parentNode = OwnerDocument;
            } 
            else {
                this.parentNode = node; 
            } 
        }
 
        internal virtual void SetParentForLoad( XmlNode node ) {
            this.parentNode = node;
        }
 
        internal static void SplitName( string name, out string prefix, out string localName ) {
            int colonPos = name.IndexOf(':'); // ordinal compare 
            if (-1 == colonPos || 0 == colonPos || name.Length-1 == colonPos) { 
                prefix = string.Empty;
                localName = name; 
            }
            else {
                prefix = name.Substring(0, colonPos);
                localName = name.Substring(colonPos+1); 
            }
        } 
 
        internal virtual XmlNode FindChild( XmlNodeType type ) {
            for (XmlNode child = FirstChild; child != null; child = child.NextSibling) { 
                if (child.NodeType == type) {
                    return child;
                }
            } 
            return null;
        } 
 
        internal virtual XmlNodeChangedEventArgs GetEventArgs( XmlNode node, XmlNode oldParent, XmlNode newParent, string oldValue, string newValue, XmlNodeChangedAction action  ) {
            XmlDocument doc = OwnerDocument; 
            if (doc != null) {
                if ( ! doc.IsLoading ) {
                    if ( ( (newParent != null && newParent.IsReadOnly) || ( oldParent != null && oldParent.IsReadOnly ) ) )
                        throw new InvalidOperationException( Res.GetString(Res.Xdom_Node_Modify_ReadOnly)); 
                }
                return doc.GetEventArgs( node, oldParent, newParent, oldValue, newValue, action ); 
            } 
            return null;
        } 

        internal virtual void BeforeEvent( XmlNodeChangedEventArgs args ) {
            if (args != null)
                OwnerDocument.BeforeEvent( args ); 
        }
 
        internal virtual void AfterEvent( XmlNodeChangedEventArgs args ) { 
            if (args != null)
                OwnerDocument.AfterEvent( args ); 
        }

        internal virtual XmlSpace XmlSpace {
            get { 
                XmlNode node = this;
                XmlElement elem = null; 
                do { 
                    elem = node as XmlElement;
                    if ( elem != null && elem.HasAttribute( "xml:space" ) ) { 
                        String xmlSpaceVal = elem.GetAttribute( "xml:space" );
                        if ( 0 == String.Compare( xmlSpaceVal, "default", StringComparison.OrdinalIgnoreCase ) )
                            return XmlSpace.Default;
                        else if ( 0 == String.Compare( xmlSpaceVal, "preserve", StringComparison.OrdinalIgnoreCase ) ) 
                            return XmlSpace.Preserve;
                        //should we throw exception if value is otherwise? 
                    } 
                    node = node.ParentNode;
                } while ( node != null ); 
                return XmlSpace.None;
            }
        }
 
        internal virtual String XmlLang {
            get { 
                XmlNode node = this; 
                XmlElement elem = null;
                do { 
                    elem = node as XmlElement;
                    if ( elem != null ) {
                        if ( elem.HasAttribute( "xml:lang" ) )
                            return elem.GetAttribute( "xml:lang" ); 
                    }
                    node = node.ParentNode; 
                } while ( node != null ); 
                return String.Empty;
            } 
        }

        internal virtual XPathNodeType XPNodeType {
            get { 
                return (XPathNodeType)(-1);
            } 
        } 

        internal virtual string XPLocalName { 
            get {
                return string.Empty;
            }
        } 

        internal virtual string GetXPAttribute(string localName, string namespaceURI) { 
            return String.Empty; 
        }
 
        internal virtual bool IsText {
            get {
                return false;
            } 
        }
 
        internal virtual XmlNode PreviousText { 
            get {
                return null; 
            }
        }

        internal static void NestTextNodes(XmlNode prevNode, XmlNode nextNode) { 
            Debug.Assert(prevNode.IsText);
            Debug.Assert(nextNode.IsText); 
 
            nextNode.parentNode = prevNode;
        } 

        internal static void UnnestTextNodes(XmlNode prevNode, XmlNode nextNode) {
            Debug.Assert(prevNode.IsText);
            Debug.Assert(nextNode.IsText); 

            nextNode.parentNode = prevNode.ParentNode; 
        } 
        private object debuggerDisplayProxy { get { return new DebuggerDisplayXmlNodeProxy(this); } }
    } 

    [DebuggerDisplay("{ToString()}")]
    internal struct DebuggerDisplayXmlNodeProxy {
        private XmlNode node; 

        public DebuggerDisplayXmlNodeProxy(XmlNode node) { 
            this.node = node; 
        }
 
        public override string ToString() {
            XmlNodeType nodeType = node.NodeType;
            string result = nodeType.ToString();
            switch (nodeType) { 
                case XmlNodeType.Element:
                case XmlNodeType.EntityReference: 
                    result += ", Name=\"" + node.Name + "\""; 
                    break;
                case XmlNodeType.Attribute: 
                case XmlNodeType.ProcessingInstruction:
                    result += ", Name=\"" + node.Name + "\", Value=\"" + XmlConvert.EscapeValueForDebuggerDisplay(node.Value) + "\"";
                    break;
                case XmlNodeType.Text: 
                case XmlNodeType.CDATA:
                case XmlNodeType.Comment: 
                case XmlNodeType.Whitespace: 
                case XmlNodeType.SignificantWhitespace:
                case XmlNodeType.XmlDeclaration: 
                    result += ", Value=\"" + XmlConvert.EscapeValueForDebuggerDisplay(node.Value) + "\"";
                    break;
                case XmlNodeType.DocumentType:
                    XmlDocumentType documentType = (XmlDocumentType)node; 
                    result += ", Name=\"" + documentType.Name + "\", SYSTEM=\"" + documentType.SystemId + "\", PUBLIC=\"" + documentType.PublicId + "\", Value=\"" + XmlConvert.EscapeValueForDebuggerDisplay(documentType.InternalSubset) + "\"";
                    break; 
                default: 
                    break;
            } 
            return result;
        }
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK