XmlElementList.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Xml / System / Xml / Dom / XmlElementList.cs / 1305376 / XmlElementList.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
//-----------------------------------------------------------------------------
 
namespace System.Xml { 
    using System;
    using System.Collections; 
    using System.Diagnostics;

    internal class XmlElementList: XmlNodeList {
        string      asterisk; 
        int         changeCount; //recording the total number that the dom tree has been changed ( insertion and deletetion )
        //the member vars below are saved for further reconstruction 
        string      name;         //only one of 2 string groups will be initialized depends on which constructor is called. 
        string      localName;
        string      namespaceURI; 
        XmlNode     rootNode;
        // the memeber vars belwo serves the optimization of accessing of the elements in the list
        int         curInd;       // -1 means the starting point for a new search round
        XmlNode     curElem;      // if sets to rootNode, means the starting point for a new search round 
        bool        empty;        // whether the list is empty
        bool        atomized;     //whether the localname and namespaceuri are aomized 
        int         matchCount;   // cached list count. -1 means it needs reconstruction 

        XmlElementListListener listener; 

        private XmlElementList( XmlNode parent) {
            Debug.Assert ( parent != null );
            Debug.Assert( parent.NodeType == XmlNodeType.Element || parent.NodeType == XmlNodeType.Document ); 
            this.rootNode = parent;
            Debug.Assert( parent.Document != null ); 
            this.curInd = -1; 
            this.curElem = rootNode;
            this.changeCount = 0; 
            this.empty = false;
            this.atomized = true;
            this.matchCount = -1;
            listener = new XmlElementListListener(parent.Document, this); 
        }
 
        ~XmlElementList() { 
            if ( listener != null ) {
                listener.Unregister(); 
                listener = null;
            }
        }
 
        internal void ConcurrencyCheck(XmlNodeChangedEventArgs args){
            if( atomized == false ) { 
                XmlNameTable nameTable = this.rootNode.Document.NameTable; 
                this.localName = nameTable.Add( this.localName );
                this.namespaceURI = nameTable.Add( this.namespaceURI ); 
                this.atomized = true;
            }
            if ( IsMatch( args.Node ) ) {
                this.changeCount++ ; 
                this.curInd = -1;
                this.curElem = rootNode; 
                if( args.Action == XmlNodeChangedAction.Insert ) 
                    this.empty = false;
            } 
            this.matchCount = -1;
        }

        internal XmlElementList( XmlNode parent, string name ): this( parent ) { 
            Debug.Assert( parent.Document != null );
            XmlNameTable nt = parent.Document.NameTable; 
            Debug.Assert( nt != null ); 
            asterisk = nt.Add("*");
            this.name = nt.Add( name ); 
            this.localName = null;
            this.namespaceURI = null;
        }
 
        internal XmlElementList( XmlNode parent, string localName, string namespaceURI ): this( parent ) {
            Debug.Assert( parent.Document != null ); 
            XmlNameTable nt = parent.Document.NameTable; 
            Debug.Assert( nt != null );
            asterisk = nt.Add("*"); 
            this.localName = nt.Get( localName );
            this.namespaceURI = nt.Get( namespaceURI );
            if( (this.localName == null) || (this.namespaceURI== null) ) {
                this.empty = true; 
                this.atomized = false;
                this.localName = localName; 
                this.namespaceURI = namespaceURI; 
            }
                this.name = null; 
        }

        internal int ChangeCount {
            get { return changeCount; } 
        }
 
        // return the next element node that is in PreOrder 
        private XmlNode NextElemInPreOrder( XmlNode curNode ) {
            Debug.Assert( curNode != null ); 
            //For preorder walking, first try its child
            XmlNode retNode = curNode.FirstChild;
            if ( retNode == null ) {
                //if no child, the next node forward will the be the NextSibling of the first ancestor which has NextSibling 
                //so, first while-loop find out such an ancestor (until no more ancestor or the ancestor is the rootNode
                retNode = curNode; 
                while ( retNode != null 
                        && retNode != rootNode
                        && retNode.NextSibling == null ) { 
                    retNode = retNode.ParentNode;
                }
                //then if such ancestor exists, set the retNode to its NextSibling
                if ( retNode != null && retNode != rootNode ) 
                    retNode = retNode.NextSibling;
            } 
            if ( retNode == this.rootNode ) 
                //if reach the rootNode, consider having walked through the whole tree and no more element after the curNode
                retNode = null; 
            return retNode;
        }

        // return the previous element node that is in PreOrder 
        private XmlNode PrevElemInPreOrder( XmlNode curNode ) {
            Debug.Assert( curNode != null ); 
            //For preorder walking, the previous node will be the right-most node in the tree of PreviousSibling of the curNode 
            XmlNode retNode = curNode.PreviousSibling;
            // so if the PreviousSibling is not null, going through the tree down to find the right-most node 
            while ( retNode != null ) {
                if ( retNode.LastChild == null )
                    break;
                retNode = retNode.LastChild; 
            }
            // if no PreviousSibling, the previous node will be the curNode's parentNode 
            if ( retNode == null ) 
                retNode = curNode.ParentNode;
            // if the final retNode is rootNode, consider having walked through the tree and no more previous node 
            if ( retNode == this.rootNode )
                retNode = null;
            return retNode;
        } 

        // if the current node a matching element node 
        private bool IsMatch ( XmlNode curNode ) { 
            if (curNode.NodeType == XmlNodeType.Element) {
                if ( this.name != null ) { 
                    if ( Ref.Equal(this.name, asterisk) || Ref.Equal(curNode.Name, this.name) )
                        return true;
                }
                else { 
                    if (
                        (Ref.Equal(this.localName, asterisk) || Ref.Equal(curNode.LocalName, this.localName) ) && 
                        (Ref.Equal(this.namespaceURI, asterisk) || curNode.NamespaceURI == this.namespaceURI ) 
                    ) {
                        return true; 
                    }
                }
            }
            return false; 
        }
 
        private XmlNode GetMatchingNode( XmlNode n, bool bNext ) { 
            Debug.Assert( n!= null );
            XmlNode node = n; 
            do {
                if ( bNext )
                    node = NextElemInPreOrder( node );
                else 
                    node = PrevElemInPreOrder( node );
            } while ( node != null && !IsMatch( node ) ); 
            return node; 
        }
 
        private XmlNode GetNthMatchingNode( XmlNode n, bool bNext, int nCount ) {
            Debug.Assert( n!= null );
            XmlNode node = n;
            for ( int ind = 0 ; ind < nCount; ind++ ) { 
                node = GetMatchingNode( node, bNext );
                if ( node == null ) 
                    return null; 
            }
            return node; 
        }

        //the function is for the enumerator to find out the next available matching element node
        public XmlNode GetNextNode( XmlNode n ) { 
            if( this.empty == true )
                return null; 
            XmlNode node = ( n == null ) ? rootNode : n; 
            return GetMatchingNode( node, true );
        } 

        public override XmlNode Item(int index) {
            if ( rootNode == null || index < 0 )
                return null; 

            if( this.empty == true ) 
                return null; 
            if ( curInd == index )
                return curElem; 
            int nDiff = index - curInd;
            bool bForward = ( nDiff > 0 );
            if ( nDiff < 0 )
                nDiff = -nDiff; 
            XmlNode node;
            if ( ( node = GetNthMatchingNode( curElem, bForward, nDiff ) ) != null ) { 
                curInd = index; 
                curElem = node;
                return curElem; 
            }
            return null;
        }
 
        public override int Count {
            get { 
                if( this.empty == true ) 
                    return 0;
                if (this.matchCount < 0) { 
                    int currMatchCount = 0;
                    int currChangeCount = this.changeCount;
                    XmlNode node = rootNode;
                    while ((node = GetMatchingNode(node, true)) != null) { 
                        currMatchCount++;
                    } 
                    if (currChangeCount != this.changeCount) { 
                        return currMatchCount;
                    } 
                    this.matchCount = currMatchCount;
                }
                return this.matchCount;
            } 
        }
 
        public override IEnumerator GetEnumerator() { 
            if( this.empty == true )
                return new XmlEmptyElementListEnumerator(this);; 
            return new XmlElementListEnumerator(this);
        }
    }
 
     internal class XmlElementListEnumerator : IEnumerator {
        XmlElementList  list; 
        XmlNode         curElem; 
        int             changeCount; //save the total number that the dom tree has been changed ( insertion and deletetion ) when this enumerator is created
 
        public XmlElementListEnumerator( XmlElementList list ) {
            this.list = list;
            this.curElem = null;
            this.changeCount = list.ChangeCount; 
        }
 
        public bool MoveNext() { 
            if ( list.ChangeCount != this.changeCount ) {
                //the number mismatch, there is new change(s) happened since last MoveNext() is called. 
                throw new InvalidOperationException( Res.GetString(Res.Xdom_Enum_ElementList) );
            }
            else  {
                curElem = list.GetNextNode( curElem ); 
            }
            return curElem != null; 
        } 

        public void Reset() { 
            curElem = null;
            //reset the number of changes to be synced with current dom tree as well
            this.changeCount = list.ChangeCount;
        } 

        public object Current { 
            get { return curElem; } 
        }
    } 

    internal class XmlEmptyElementListEnumerator : IEnumerator {
        public XmlEmptyElementListEnumerator( XmlElementList list ) {
        } 

        public bool MoveNext() { 
            return false; 
        }
 
        public void Reset() {
        }

        public object Current { 
            get { return null; }
        } 
    } 

    internal class XmlElementListListener { 
        WeakReference elemList;
        XmlDocument doc;
        XmlNodeChangedEventHandler nodeChangeHandler = null;
 
        internal XmlElementListListener(XmlDocument doc, XmlElementList elemList) {
            this.doc = doc; 
            this.elemList = new WeakReference(elemList); 
            this.nodeChangeHandler = new XmlNodeChangedEventHandler( this.OnListChanged );
            doc.NodeInserted += this.nodeChangeHandler; 
            doc.NodeRemoved += this.nodeChangeHandler;
        }

        private void OnListChanged( object sender, XmlNodeChangedEventArgs args ) { 
            lock (this) {
                if (this.elemList != null) { 
                    XmlElementList el = (XmlElementList)this.elemList.Target; 
                    if (null != el) {
                        el.ConcurrencyCheck(args); 
                    } else {
                        this.doc.NodeInserted -= this.nodeChangeHandler;
                        this.doc.NodeRemoved -= this.nodeChangeHandler;
                        this.elemList = null; 
                    }
                } 
            } 
        }
 
        // This method is called from the finalizer of XmlElementList
        internal void Unregister() {
            lock (this) {
                if (elemList != null) { 
                    this.doc.NodeInserted -= this.nodeChangeHandler;
                    this.doc.NodeRemoved -= this.nodeChangeHandler; 
                    this.elemList = null; 
                }
            } 
        }
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

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