XmlNode.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ FXUpdate3074 / FXUpdate3074 / 1.1 / untmp / whidbey / QFE / ndp / fx / src / Xml / System / Xml / Dom / XmlNode.cs / 4 / 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 thisAsDoc = this as XmlDocument; 
            if ( thisAsDoc != null ) { 
                return thisAsDoc.CreateNavigator( this );
            } 
            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