DocumentXPathNavigator.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / whidbey / NetFXspW7 / ndp / fx / src / Xml / System / Xml / Dom / DocumentXPathNavigator.cs / 1 / DocumentXPathNavigator.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
//-----------------------------------------------------------------------------
 
using System; 
using System.Collections;
using System.Collections.Generic; 
using System.Text;
using System.Xml.Schema;
using System.Xml.XPath;
using System.Diagnostics; 

namespace System.Xml { 
    internal sealed class DocumentXPathNavigator : XPathNavigator, IHasXmlNode { 
        private XmlDocument document; // owner document
        private XmlNode source; // navigator position 
        private int attributeIndex; // index in attribute collection for attribute
        private XmlElement namespaceParent; // parent for namespace

        public DocumentXPathNavigator(XmlDocument document, XmlNode node) { 
            this.document = document;
            ResetPosition(node); 
        } 

        public DocumentXPathNavigator(DocumentXPathNavigator other) { 
            document = other.document;
            source = other.source;
            attributeIndex = other.attributeIndex;
            namespaceParent = other.namespaceParent; 
        }
 
        public override XPathNavigator Clone() { 
            return new DocumentXPathNavigator(this);
        } 

        public override void SetValue(string value) {
            if (value == null) {
                throw new ArgumentNullException("value"); 
            }
 
            XmlNode node = source; 
            XmlNode end;
 
            switch (node.NodeType) {
                case XmlNodeType.Attribute:
                    if (((XmlAttribute)node).IsNamespace) {
                        goto default; 
                    }
                    node.InnerText = value; 
                    break; 
                case XmlNodeType.Text:
                case XmlNodeType.CDATA: 
                case XmlNodeType.Whitespace:
                case XmlNodeType.SignificantWhitespace:
                    CalibrateText();
 
                    node = source;
                    end = TextEnd(node); 
                    if (node != end) { 
                        if (node.IsReadOnly) {
                            throw new InvalidOperationException(Res.GetString(Res.Xdom_Node_Modify_ReadOnly)); 
                        }
                        DeleteToFollowingSibling(node.NextSibling, end);
                    }
                    goto case XmlNodeType.Element; 
                case XmlNodeType.Element:
                case XmlNodeType.ProcessingInstruction: 
                case XmlNodeType.Comment: 
                    node.InnerText = value;
                    break; 
                default:
                    throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition));
            }
        } 

        public override XmlNameTable NameTable { 
            get { 
                return document.NameTable;
            } 
        }

        public override XPathNodeType NodeType {
            get { 
                CalibrateText();
 
                return (XPathNodeType)source.XPNodeType; 
            }
        } 

        public override string LocalName {
            get {
                return source.XPLocalName; 
            }
        } 
 
        public override string NamespaceURI {
            get { 
                XmlAttribute attribute = source as XmlAttribute;
                if (attribute != null
                    && attribute.IsNamespace) {
                    return string.Empty; 
                }
                return source.NamespaceURI; 
            } 
        }
 
        public override string Name {
            get {
                switch (source.NodeType) {
                    case XmlNodeType.Element: 
                    case XmlNodeType.ProcessingInstruction:
                        return source.Name; 
                    case XmlNodeType.Attribute: 
                        if (((XmlAttribute)source).IsNamespace) {
                            string localName = source.LocalName; 
                            if (Ref.Equals(localName, document.strXmlns)) {
                                return string.Empty; // xmlns declaration
                            }
                            return localName; // xmlns:name declaration 
                        }
                        return source.Name; // attribute 
                    default: 
                        return string.Empty;
                } 
            }
        }

        public override string Prefix { 
            get {
                XmlAttribute attribute = source as XmlAttribute; 
                if (attribute != null 
                    && attribute.IsNamespace) {
                    return string.Empty; 
                }
                return source.Prefix;
            }
        } 

        public override string Value { 
            get { 
                switch (source.NodeType) {
                    case XmlNodeType.Element: 
                    case XmlNodeType.DocumentFragment:
                        return source.InnerText;
                    case XmlNodeType.Document:
                        return ValueDocument; 
                    case XmlNodeType.Text:
                    case XmlNodeType.CDATA: 
                    case XmlNodeType.Whitespace: 
                    case XmlNodeType.SignificantWhitespace:
                        return ValueText; 
                    default:
                        return source.Value;
                }
            } 
        }
 
        private string ValueDocument { 
            get {
                XmlElement element = document.DocumentElement; 
                if (element != null) {
                    return element.InnerText;
                }
                return string.Empty; 
            }
        } 
 
        private string ValueText {
            get { 
                CalibrateText();

                string value = source.Value;
                XmlNode nextSibling = NextSibling(source); 
                if (nextSibling != null
                    && nextSibling.IsText) { 
                    StringBuilder builder = new StringBuilder(value); 
                    do {
                        builder.Append(nextSibling.Value); 
                        nextSibling = NextSibling(nextSibling);
                    }
                    while (nextSibling != null
                           && nextSibling.IsText); 
                    value = builder.ToString();
                } 
                return value; 
            }
        } 

        public override string BaseURI {
            get {
                return source.BaseURI; 
            }
        } 
 
        public override bool IsEmptyElement {
            get { 
                XmlElement element = source as XmlElement;
                if (element != null) {
                    return element.IsEmpty;
                } 
                return false;
            } 
        } 

        public override string XmlLang { 
            get {
                return source.XmlLang;
            }
        } 

        public override object UnderlyingObject { 
            get { 
                CalibrateText();
 
                return source;
            }
        }
 
        public override bool HasAttributes {
            get { 
                XmlElement element = source as XmlElement; 
                if (element != null
                    && element.HasAttributes) { 
                    XmlAttributeCollection attributes = element.Attributes;
                    for (int i = 0; i < attributes.Count; i++) {
                        XmlAttribute attribute = attributes[i];
                        if (!attribute.IsNamespace) { 
                            return true;
                        } 
                    } 
                }
                return false; 
            }
        }

        public override string GetAttribute(string localName, string namespaceURI) { 
            return source.GetXPAttribute(localName, namespaceURI);
        } 
 
        public override bool MoveToAttribute(string localName, string namespaceURI) {
            XmlElement element = source as XmlElement; 
            if (element != null
                && element.HasAttributes) {
                XmlAttributeCollection attributes = element.Attributes;
                for (int i = 0; i < attributes.Count; i++) { 
                    XmlAttribute attribute = attributes[i];
                    if (attribute.LocalName == localName 
                        && attribute.NamespaceURI == namespaceURI) { 
                        if (!attribute.IsNamespace) {
                            source = attribute; 
                            attributeIndex = i;
                            return true;
                        }
                        else { 
                            return false;
                        } 
                    } 
                }
            } 
            return false;
        }

        public override bool MoveToFirstAttribute() { 
            XmlElement element = source as XmlElement;
            if (element != null 
                && element.HasAttributes) { 
                XmlAttributeCollection attributes = element.Attributes;
                for (int i = 0; i < attributes.Count; i++) { 
                    XmlAttribute attribute = attributes[i];
                    if (!attribute.IsNamespace) {
                        source = attribute;
                        attributeIndex = i; 
                        return true;
                    } 
                } 
            }
            return false; 
        }

        public override bool MoveToNextAttribute() {
            XmlAttribute attribute = source as XmlAttribute; 
            if (attribute == null
                || attribute.IsNamespace) { 
                return false; 
            }
            XmlAttributeCollection attributes; 
            if (!CheckAttributePosition(attribute, out attributes, attributeIndex)
                && !ResetAttributePosition(attribute, attributes, out attributeIndex)) {
                return false;
            } 
            for (int i = attributeIndex + 1; i < attributes.Count; i++) {
                attribute = attributes[i]; 
                if (!attribute.IsNamespace) { 
                    source = attribute;
                    attributeIndex = i; 
                    return true;
                }
            }
            return false; 
        }
 
        public override string GetNamespace(string name) { 
            XmlNode node = source;
            while (node != null 
                   && node.NodeType != XmlNodeType.Element) {
                XmlAttribute attribute = node as XmlAttribute;
                if (attribute != null) {
                    node = attribute.OwnerElement; 
                }
                else { 
                    node = node.ParentNode; 
                }
            } 

            XmlElement element = node as XmlElement;
            if (element != null) {
                string localName; 
                if (name != null
                    && name.Length != 0) { 
                    localName = name; 
                }
                else { 
                    localName = document.strXmlns;
                }
                string namespaceUri = document.strReservedXmlns;
 
                do
                { 
                    XmlAttribute attribute = element.GetAttributeNode(localName, namespaceUri); 
                    if (attribute != null) {
                        return attribute.Value; 
                    }
                    element = element.ParentNode as XmlElement;
                }
                while (element != null); 
            }
 
            if (name == document.strXml) { 
                return document.strReservedXml;
            } 
            else if (name == document.strXmlns) {
                return document.strReservedXmlns;
            }
            return string.Empty; 
        }
 
        public override bool MoveToNamespace(string name) { 
            if (name == document.strXmlns) {
                return false; 
            }
            XmlElement element = source as XmlElement;
            if (element != null) {
                string localName; 
                if (name != null
                    && name.Length != 0) { 
                    localName = name; 
                }
                else { 
                    localName = document.strXmlns;
                }
                string namespaceUri = document.strReservedXmlns;
 
                do {
                    XmlAttribute attribute = element.GetAttributeNode(localName, namespaceUri); 
                    if (attribute != null) { 
                        namespaceParent = (XmlElement)source;
                        source = attribute; 
                        return true;
                    }
                    element = element.ParentNode as XmlElement;
                } 
                while (element != null);
 
                if (name == document.strXml) { 
                    namespaceParent = (XmlElement)source;
                    source = document.NamespaceXml; 
                    return true;
                }
            }
            return false; 
        }
 
        public override bool MoveToFirstNamespace(XPathNamespaceScope scope) { 
            XmlElement element = source as XmlElement;
            if (element == null) { 
                return false;
            }
            XmlAttributeCollection attributes;
            int index = Int32.MaxValue; 
            switch (scope) {
                case XPathNamespaceScope.Local: 
                    if (!element.HasAttributes) { 
                        return false;
                    } 
                    attributes = element.Attributes;
                    if (!MoveToFirstNamespaceLocal(attributes, ref index)) {
                        return false;
                    } 
                    source = attributes[index];
                    attributeIndex = index; 
                    namespaceParent = element; 
                    break;
                case XPathNamespaceScope.ExcludeXml: 
                    attributes = element.Attributes;
                    if (!MoveToFirstNamespaceGlobal(ref attributes, ref index)) {
                        return false;
                    } 
                    XmlAttribute attribute = attributes[index];
                    while (Ref.Equals(attribute.LocalName, document.strXml)) { 
                        if (!MoveToNextNamespaceGlobal(ref attributes, ref index)) { 
                            return false;
                        } 
                        attribute = attributes[index];
                    }
                    source = attribute;
                    attributeIndex = index; 
                    namespaceParent = element;
                    break; 
                case XPathNamespaceScope.All: 
                    attributes = element.Attributes;
                    if (!MoveToFirstNamespaceGlobal(ref attributes, ref index)) { 
                        source = document.NamespaceXml;
                        // attributeIndex = 0;
                    }
                    else { 
                        source = attributes[index];
                        attributeIndex = index; 
                    } 
                    namespaceParent = element;
                    break; 
                default:
                    Debug.Assert(false);
                    return false;
            } 
            return true;
        } 
 
        private static bool MoveToFirstNamespaceLocal(XmlAttributeCollection attributes, ref int index) {
            Debug.Assert(attributes != null); 
            for (int i = attributes.Count - 1; i >= 0; i--) {
                XmlAttribute attribute = attributes[i];
                if (attribute.IsNamespace) {
                    index = i; 
                    return true;
                } 
            } 
            return false;
        } 

        private static bool MoveToFirstNamespaceGlobal(ref XmlAttributeCollection attributes, ref int index) {
            if (MoveToFirstNamespaceLocal(attributes, ref index)) {
                return true; 
            }
 
            Debug.Assert(attributes != null && attributes.parent != null); 
            XmlElement element = attributes.parent.ParentNode as XmlElement;
            while (element != null) { 
                if (element.HasAttributes) {
                    attributes = element.Attributes;
                    if (MoveToFirstNamespaceLocal(attributes, ref index)) {
                        return true; 
                    }
                } 
                element = element.ParentNode as XmlElement; 
            }
            return false; 
        }

        public override bool MoveToNextNamespace(XPathNamespaceScope scope) {
            XmlAttribute attribute = source as XmlAttribute; 
            if (attribute == null
                || !attribute.IsNamespace) { 
                return false; 
            }
            XmlAttributeCollection attributes; 
            int index = attributeIndex;
            if (!CheckAttributePosition(attribute, out attributes, index)
                && !ResetAttributePosition(attribute, attributes, out index)) {
                return false; 
            }
            Debug.Assert(namespaceParent != null); 
            switch (scope) { 
                case XPathNamespaceScope.Local:
                    if (attribute.OwnerElement != namespaceParent) { 
                        return false;
                    }
                    if (!MoveToNextNamespaceLocal(attributes, ref index)) {
                        return false; 
                    }
                    source = attributes[index]; 
                    attributeIndex = index; 
                    break;
                case XPathNamespaceScope.ExcludeXml: 
                    string localName;
                    do {
                        if (!MoveToNextNamespaceGlobal(ref attributes, ref index)) {
                            return false; 
                        }
                        attribute = attributes[index]; 
                        localName = attribute.LocalName; 
                    }
                    while (PathHasDuplicateNamespace(attribute.OwnerElement, namespaceParent, localName) 
                           || Ref.Equals(localName, document.strXml));
                    source = attribute;
                    attributeIndex = index;
                    break; 
                case XPathNamespaceScope.All:
                    do { 
                        if (!MoveToNextNamespaceGlobal(ref attributes, ref index)) { 
                            if (PathHasDuplicateNamespace(null, namespaceParent, document.strXml)) {
                                return false; 
                            }
                            else {
                                source = document.NamespaceXml;
                                // attributeIndex = 0; 
                                return true;
                            } 
                        } 
                        attribute = attributes[index];
                    } 
                    while (PathHasDuplicateNamespace(attribute.OwnerElement, namespaceParent, attribute.LocalName));
                    source = attribute;
                    attributeIndex = index;
                    break; 
                default:
                    Debug.Assert(false); 
                    return false; 
            }
            return true; 
        }

        private static bool MoveToNextNamespaceLocal(XmlAttributeCollection attributes, ref int index) {
            Debug.Assert(attributes != null); 
            Debug.Assert(0 <= index && index < attributes.Count);
            for (int i = index - 1; i >= 0; i--) { 
                XmlAttribute attribute = attributes[i]; 
                if (attribute.IsNamespace) {
                    index = i; 
                    return true;
                }
            }
            return false; 
        }
 
        private static bool MoveToNextNamespaceGlobal(ref XmlAttributeCollection attributes, ref int index) { 
            if (MoveToNextNamespaceLocal(attributes, ref index)) {
                return true; 
            }

            Debug.Assert(attributes != null && attributes.parent != null);
            XmlElement element = attributes.parent.ParentNode as XmlElement; 
            while (element != null) {
                if (element.HasAttributes) { 
                    attributes = element.Attributes; 
                    if (MoveToFirstNamespaceLocal(attributes, ref index)) {
                        return true; 
                    }
                }
                element = element.ParentNode as XmlElement;
            } 
            return false;
        } 
 
        private bool PathHasDuplicateNamespace(XmlElement top, XmlElement bottom, string localName) {
            string namespaceUri = document.strReservedXmlns; 
            while (bottom != null
                   && bottom != top) {
                XmlAttribute attribute = bottom.GetAttributeNode(localName, namespaceUri);
                if (attribute != null) { 
                    return true;
                } 
                bottom = bottom.ParentNode as XmlElement; 
            }
            return false; 
        }

        public override bool MoveToNext() {
            XmlNode sibling = NextSibling(source); 
            if (sibling == null) {
                return false; 
            } 
            if (sibling.IsText) {
                if (source.IsText) { 
                    sibling = NextSibling(TextEnd(sibling));
                    if (sibling == null) {
                        return false;
                    } 
                }
            } 
            XmlNode parent = ParentNode(sibling); 
            Debug.Assert(parent != null);
            while (!IsValidChild(parent, sibling)) { 
                sibling = NextSibling(sibling);
                if (sibling == null) {
                    return false;
                } 
            }
            source = sibling; 
            return true; 
        }
 
        public override bool MoveToPrevious() {
            XmlNode sibling = PreviousSibling(source);
            if (sibling == null) {
                return false; 
            }
            if (sibling.IsText) { 
                if (source.IsText) { 
                    sibling = PreviousSibling(TextStart(sibling));
                    if (sibling == null) { 
                        return false;
                    }
                }
                else { 
                    sibling = TextStart(sibling);
                } 
            } 
            XmlNode parent = ParentNode(sibling);
            Debug.Assert(parent != null); 
            while (!IsValidChild(parent, sibling)) {
                sibling = PreviousSibling(sibling);
                if (sibling == null) {
                    return false; 
                }
                // if (sibling.IsText) { 
                //     sibling = TextStart(sibling); 
                // }
            } 
            source = sibling;
            return true;
        }
 
        public override bool MoveToFirst() {
            if (source.NodeType == XmlNodeType.Attribute) { 
                return false; 
            }
            XmlNode parent = ParentNode(source); 
            if (parent == null) {
                return false;
            }
            XmlNode sibling = FirstChild(parent); 
            Debug.Assert(sibling != null);
            while (!IsValidChild(parent, sibling)) { 
                sibling = NextSibling(sibling); 
                if (sibling == null) {
                    return false; 
                }
            }
            source = sibling;
            return true; 
        }
 
        public override bool MoveToFirstChild() { 
            XmlNode child;
            switch (source.NodeType) { 
                case XmlNodeType.Element:
                    child = FirstChild(source);
                    if (child == null) {
                        return false; 
                    }
                    break; 
                case XmlNodeType.DocumentFragment: 
                case XmlNodeType.Document:
                    child = FirstChild(source); 
                    if (child == null) {
                        return false;
                    }
                    while (!IsValidChild(source, child)) { 
                        child = NextSibling(child);
                        if (child == null) { 
                            return false; 
                        }
                    } 
                    break;
                default:
                    return false;
 
            }
            source = child; 
            return true; 
        }
 
        public override bool MoveToParent() {
            XmlNode parent = ParentNode(source);
            if (parent != null) {
                source = parent; 
                return true;
            } 
            XmlAttribute attribute = source as XmlAttribute; 
            if (attribute != null) {
                parent = attribute.IsNamespace ? namespaceParent : attribute.OwnerElement; 
                if (parent != null) {
                    source = parent;
                    namespaceParent = null;
                    return true; 
                }
            } 
            return false; 
        }
 
        public override void MoveToRoot() {
            for (;;) {
                XmlNode parent = source.ParentNode;
                if (parent == null) { 
                    XmlAttribute attribute = source as XmlAttribute;
                    if (attribute == null) { 
                        break; 
                    }
                    parent = attribute.IsNamespace ? namespaceParent : attribute.OwnerElement; 
                    if (parent == null) {
                        break;
                    }
                } 
                source = parent;
            } 
            namespaceParent = null; 
        }
 
        public override bool MoveTo(XPathNavigator other) {
            DocumentXPathNavigator that = other as DocumentXPathNavigator;
            if (that != null
                && document == that.document) { 
                source = that.source;
                attributeIndex = that.attributeIndex; 
                namespaceParent = that.namespaceParent; 
                return true;
            } 
            return false;
        }

        public override bool MoveToId(string id) { 
            XmlElement element = document.GetElementById(id);
            if (element != null) { 
                source = element; 
                namespaceParent = null;
                return true; 
            }
            return false;
        }
 
        public override bool MoveToChild(string localName, string namespaceUri) {
            if (source.NodeType == XmlNodeType.Attribute) { 
                return false; 
            }
 
            XmlNode child = FirstChild(source);
            if (child != null) {
                do {
                    if (child.NodeType == XmlNodeType.Element 
                        && child.LocalName == localName
                        && child.NamespaceURI == namespaceUri) { 
                        source = child; 
                        return true;
                    } 
                    child = NextSibling(child);
                }
                while (child != null);
            } 
            return false;
        } 
 
        public override bool MoveToChild(XPathNodeType type) {
            if (source.NodeType == XmlNodeType.Attribute) { 
                return false;
            }

            XmlNode child = FirstChild(source); 
            if (child != null) {
                int mask = GetContentKindMask(type); 
                if (mask == 0) { 
                    return false;
                } 
                do {
                    if (((1 << (int)child.XPNodeType) & mask) != 0) {
                        source = child;
                        return true; 
                    }
                    child = NextSibling(child); 
                } 
                while (child != null);
            } 
            return false;
        }

        public override bool MoveToFollowing(string localName, string namespaceUri, XPathNavigator end) { 
            XmlNode pastFollowing = null;
            DocumentXPathNavigator that = end as DocumentXPathNavigator; 
            if (that != null) { 
                if (document != that.document) {
                    return false; 
                }
                switch (that.source.NodeType) {
                    case XmlNodeType.Attribute:
                        that = (DocumentXPathNavigator)that.Clone(); 
                        if (!that.MoveToNonDescendant()) {
                            return false; 
                        } 
                        break;
                } 
                pastFollowing = that.source;
            }

            XmlNode following = source; 
            if (following.NodeType == XmlNodeType.Attribute) {
                following = ((XmlAttribute)following).OwnerElement; 
                if (following == null) { 
                    return false;
                } 
            }
            do {
                XmlNode firstChild = following.FirstChild;
                if (firstChild != null) { 
                    following = firstChild;
                } 
                else { 
                    for (;;) {
                        XmlNode nextSibling = following.NextSibling; 
                        if (nextSibling != null) {
                            following = nextSibling;
                            break;
                        } 
                        else {
                            XmlNode parent = following.ParentNode; 
                            if (parent != null) { 
                                following = parent;
                            } 
                            else {
                                return false;
                            }
                        } 
                    }
                } 
                if (following == pastFollowing) { 
                    return false;
                } 
            }
            while (following.NodeType != XmlNodeType.Element
                   || following.LocalName != localName
                   || following.NamespaceURI != namespaceUri); 

            source = following; 
            return true; 
        }
 
        public override bool MoveToFollowing(XPathNodeType type, XPathNavigator end) {
            XmlNode pastFollowing = null;
            DocumentXPathNavigator that = end as DocumentXPathNavigator;
            if (that != null) { 
                if (document != that.document) {
                    return false; 
                } 
                switch (that.source.NodeType) {
                    case XmlNodeType.Attribute: 
                        that = (DocumentXPathNavigator)that.Clone();
                        if (!that.MoveToNonDescendant()) {
                            return false;
                        } 
                        break;
                } 
                pastFollowing = that.source; 
            }
 
            int mask = GetContentKindMask(type);
            if (mask == 0) {
                return false;
            } 
            XmlNode following = source;
            switch (following.NodeType) { 
                case XmlNodeType.Attribute: 
                    following = ((XmlAttribute)following).OwnerElement;
                    if (following == null) { 
                        return false;
                    }
                    break;
                case XmlNodeType.Text: 
                case XmlNodeType.CDATA:
                case XmlNodeType.SignificantWhitespace: 
                case XmlNodeType.Whitespace: 
                    following = TextEnd(following);
                    break; 
            }
            do {
                XmlNode firstChild = following.FirstChild;
                if (firstChild != null) { 
                    following = firstChild;
                } 
                else { 
                    for (;;) {
                        XmlNode nextSibling = following.NextSibling; 
                        if (nextSibling != null) {
                            following = nextSibling;
                            break;
                        } 
                        else {
                            XmlNode parent = following.ParentNode; 
                            if (parent != null) { 
                                following = parent;
                            } 
                            else {
                                return false;
                            }
                        } 
                    }
                } 
                if (following == pastFollowing) { 
                    return false;
                } 
            }
            while (((1 << (int)following.XPNodeType) & mask) == 0);

            source = following; 
            return true;
        } 
 
        public override bool MoveToNext(string localName, string namespaceUri) {
            XmlNode sibling = NextSibling(source); 
            if (sibling == null) {
                return false;
            }
            do { 
                if (sibling.NodeType == XmlNodeType.Element
                    && sibling.LocalName == localName 
                    && sibling.NamespaceURI == namespaceUri) { 
                    source = sibling;
                    return true; 
                }
                sibling = NextSibling(sibling);
            }
            while (sibling != null); 
            return false;
        } 
 
        public override bool MoveToNext(XPathNodeType type) {
            XmlNode sibling = NextSibling(source); 
            if (sibling == null) {
                return false;
            }
            if (sibling.IsText 
                && source.IsText) {
                sibling = NextSibling(TextEnd(sibling)); 
                if (sibling == null) { 
                    return false;
                } 
            }

            int mask = GetContentKindMask(type);
            if (mask == 0) { 
                return false;
            } 
            do { 
                if (((1 << (int)sibling.XPNodeType) & mask) != 0) {
                    source = sibling; 
                    return true;
                }
                sibling = NextSibling(sibling);
            } 
            while (sibling != null);
            return false; 
        } 

        public override bool HasChildren { 
            get {
                XmlNode child;
                switch (source.NodeType) {
                    case XmlNodeType.Element: 
                        child = FirstChild(source);
                        if (child == null) { 
                            return false; 
                        }
                        return true; 
                    case XmlNodeType.DocumentFragment:
                    case XmlNodeType.Document:
                        child = FirstChild(source);
                        if (child == null) { 
                            return false;
                        } 
                        while (!IsValidChild(source, child)) { 
                            child = NextSibling(child);
                            if (child == null) { 
                                return false;
                            }
                        }
                        return true; 
                    default:
                        return false; 
                } 
            }
        } 

        public override bool IsSamePosition(XPathNavigator other) {
            DocumentXPathNavigator that = other as DocumentXPathNavigator;
            if (that != null) { 
                this.CalibrateText();
                that.CalibrateText(); 
 
                return this.source == that.source
                       && this.namespaceParent == that.namespaceParent; 
            }
            return false;
        }
 
        public override bool IsDescendant(XPathNavigator other) {
            DocumentXPathNavigator that = other as DocumentXPathNavigator; 
            if (that != null) { 
                return IsDescendant(this.source, that.source);
            } 
            return false;
        }

        public override IXmlSchemaInfo SchemaInfo { 
            get {
                return source.SchemaInfo; 
            } 
        }
 
        public override bool CheckValidity(XmlSchemaSet schemas, ValidationEventHandler validationEventHandler) {
            XmlDocument ownerDocument;

            if (source.NodeType == XmlNodeType.Document) { 
                ownerDocument = (XmlDocument)source;
            } 
            else { 
                ownerDocument = source.OwnerDocument;
 
                if (schemas != null) {
                    throw new ArgumentException(Res.GetString(Res.XPathDocument_SchemaSetNotAllowed, null));
                }
            } 
            if (schemas == null && ownerDocument != null) {
                schemas = ownerDocument.Schemas; 
            } 

            if (schemas == null || schemas.Count == 0) { 
                throw new InvalidOperationException(Res.GetString(Res.XmlDocument_NoSchemaInfo));
            }

            DocumentSchemaValidator validator = new DocumentSchemaValidator(ownerDocument, schemas, validationEventHandler); 
            validator.PsviAugmentation = false;
            return validator.Validate(source); 
        } 

        private static XmlNode OwnerNode(XmlNode node) { 
            XmlNode parent = node.ParentNode;
            if (parent != null) {
                return parent;
            } 
            XmlAttribute attribute = node as XmlAttribute;
            if (attribute != null) { 
                return attribute.OwnerElement; 
            }
            return null; 
        }

        private static int GetDepth(XmlNode node) {
            int depth = 0; 
            XmlNode owner = OwnerNode(node);
            while (owner != null) { 
                depth++; 
                owner = OwnerNode(owner);
            } 
            return depth;
        }

        //Assuming that node1 and node2 are in the same level; Except when they are namespace nodes, they should have the same parent node 
        //the returned value is node2's position corresponding to node1
        private XmlNodeOrder Compare( XmlNode node1, XmlNode node2 ) { 
            Debug.Assert( node1 != null ); 
            Debug.Assert( node2 != null );
            Debug.Assert( node1 != node2, "Should be handled by ComparePosition()" ); 
            //Attribute nodes come before other children nodes except namespace nodes
            Debug.Assert( OwnerNode(node1) == OwnerNode(node2) );
            if (node1.XPNodeType == XPathNodeType.Attribute) {
                if (node2.XPNodeType == XPathNodeType.Attribute) { 
                    XmlElement element = ((XmlAttribute)node1).OwnerElement;
                    if (element.HasAttributes) { 
                        XmlAttributeCollection attributes = element.Attributes; 
                        for (int i = 0; i < attributes.Count; i++) {
                            XmlAttribute attribute = attributes[i]; 
                            if (attribute == node1) {
                                return XmlNodeOrder.Before;
                            }
                            else if (attribute == node2) { 
                                return XmlNodeOrder.After;
                            } 
                        } 
                    }
                    return XmlNodeOrder.Unknown; 
                }
                else {
                    return XmlNodeOrder.Before;
                } 
            }
            if (node2.XPNodeType == XPathNodeType.Attribute) { 
                return XmlNodeOrder.After; 
            }
 
            //neither of the node is Namespace node or Attribute node
            XmlNode nextNode = node1.NextSibling;
            while ( nextNode != null && nextNode != node2 )
                nextNode = nextNode.NextSibling; 
            if ( nextNode == null )
                //didn't meet node2 in the path to the end, thus it has to be in the front of node1 
                return XmlNodeOrder.After; 
            else
                //met node2 in the path to the end, so node1 is at front 
                return XmlNodeOrder.Before;
        }

        public override XmlNodeOrder ComparePosition(XPathNavigator other) { 
            DocumentXPathNavigator that = other as DocumentXPathNavigator;
            if (that == null) { 
                return XmlNodeOrder.Unknown; 
            }
 
            this.CalibrateText();
            that.CalibrateText();

            if (this.source == that.source 
                && this.namespaceParent == that.namespaceParent) {
                return XmlNodeOrder.Same; 
            } 

            if (this.namespaceParent != null 
                || that.namespaceParent != null) {
                return base.ComparePosition(other);
            }
 
            XmlNode node1 = this.source;
            XmlNode node2 = that.source; 
 
            XmlNode parent1 = OwnerNode(node1);
            XmlNode parent2 = OwnerNode(node2); 
            if (parent1 == parent2) {
                if (parent1 == null) {
                    return XmlNodeOrder.Unknown;
                } 
                else {
                    Debug.Assert(node1 != node2); 
                    return Compare(node1, node2); 
                }
            } 

            int depth1 = GetDepth(node1);
            int depth2 = GetDepth(node2);
            if (depth2 > depth1) { 
                while (node2 != null
                       && depth2 > depth1) { 
                    node2 = OwnerNode(node2); 
                    depth2--;
                } 
                if (node1 == node2) {
                    return XmlNodeOrder.Before;
                }
                parent2 = OwnerNode(node2); 
            }
            else if (depth1 > depth2) { 
                while (node1 != null 
                       && depth1 > depth2) {
                    node1 = OwnerNode(node1); 
                    depth1--;
                }
                if (node1 == node2) {
                    return XmlNodeOrder.After; 
                }
                parent1 = OwnerNode(node1); 
            } 

            while (parent1 != null 
                   && parent2 != null) {
                if (parent1 == parent2) {
                    Debug.Assert(node1 != node2);
                    return Compare(node1, node2); 
                }
                node1 = parent1; 
                node2 = parent2; 
                parent1 = OwnerNode(node1);
                parent2 = OwnerNode(node2); 
            }
            return XmlNodeOrder.Unknown;
        }
 
        //the function just for XPathNodeList to enumerate current Node.
        XmlNode IHasXmlNode.GetNode() { return source; } 
 
        public override XPathNodeIterator SelectDescendants( string localName, string namespaceURI, bool matchSelf ) {
            string nsAtom = document.NameTable.Get( namespaceURI ); 
            if ( nsAtom == null || this.source.NodeType == XmlNodeType.Attribute )
                return new DocumentXPathNodeIterator_Empty( this );

            Debug.Assert( this.NodeType != XPathNodeType.Attribute && this.NodeType != XPathNodeType.Namespace && this.NodeType != XPathNodeType.All ); 

            string localNameAtom = document.NameTable.Get( localName ); 
            if ( localNameAtom == null ) 
                return new DocumentXPathNodeIterator_Empty( this );
 
            if ( localNameAtom.Length == 0 ) {
                if ( matchSelf )
                    return new DocumentXPathNodeIterator_ElemChildren_AndSelf_NoLocalName( this, nsAtom );
                return new DocumentXPathNodeIterator_ElemChildren_NoLocalName( this, nsAtom ); 
            }
 
            if ( matchSelf ) 
                return new DocumentXPathNodeIterator_ElemChildren_AndSelf( this, localNameAtom, nsAtom );
            return new DocumentXPathNodeIterator_ElemChildren( this, localNameAtom, nsAtom ); 
        }

        public override XPathNodeIterator SelectDescendants( XPathNodeType nt, bool includeSelf ) {
            if ( nt == XPathNodeType.Element ) { 
                XmlNodeType curNT = source.NodeType;
                if ( curNT != XmlNodeType.Document && curNT != XmlNodeType.Element ) { 
                    //only Document, Entity, Element node can have Element node as children ( descendant ) 
                    //entity nodes should be invisible to XPath data model
                    return new DocumentXPathNodeIterator_Empty( this ); 
                }
                if ( includeSelf )
                    return new DocumentXPathNodeIterator_AllElemChildren_AndSelf( this );
                return new DocumentXPathNodeIterator_AllElemChildren( this ); 
            }
            return base.SelectDescendants( nt, includeSelf ); 
        } 

        public override bool CanEdit { 
            get {
                return true;
            }
        } 

        public override XmlWriter PrependChild() { 
            switch (source.NodeType) { 
                case XmlNodeType.Element:
                case XmlNodeType.Document: 
                case XmlNodeType.DocumentFragment:
                    break;
                default:
                    throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition)); 
            }
 
            DocumentXmlWriter writer = new DocumentXmlWriter(DocumentXmlWriterType.PrependChild, source, document); 
            writer.NamespaceManager = GetNamespaceManager(source, document);
            return new XmlWellFormedWriter(writer, writer.Settings); 
        }

        public override XmlWriter AppendChild() {
            switch (source.NodeType) { 
                case XmlNodeType.Element:
                case XmlNodeType.Document: 
                case XmlNodeType.DocumentFragment: 
                    break;
                default: 
                    throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition));
            }

            DocumentXmlWriter writer = new DocumentXmlWriter(DocumentXmlWriterType.AppendChild, source, document); 
            writer.NamespaceManager = GetNamespaceManager(source, document);
            return new XmlWellFormedWriter(writer, writer.Settings); 
        } 

        public override XmlWriter InsertAfter() { 
            XmlNode node = source;

            switch (node.NodeType) {
                case XmlNodeType.Attribute: 
                case XmlNodeType.Document:
                case XmlNodeType.DocumentFragment: 
                    throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition)); 
                case XmlNodeType.Text:
                case XmlNodeType.CDATA: 
                case XmlNodeType.SignificantWhitespace:
                case XmlNodeType.Whitespace:
                    node = TextEnd(node);
                    break; 
                default:
                    break; 
            } 

            DocumentXmlWriter writer = new DocumentXmlWriter(DocumentXmlWriterType.InsertSiblingAfter, node, document); 
            writer.NamespaceManager = GetNamespaceManager(node.ParentNode, document);
            return new XmlWellFormedWriter(writer, writer.Settings);
        }
 
        public override XmlWriter InsertBefore() {
            switch (source.NodeType) { 
                case XmlNodeType.Attribute: 
                case XmlNodeType.Document:
                case XmlNodeType.DocumentFragment: 
                    throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition));
                case XmlNodeType.Text:
                case XmlNodeType.CDATA:
                case XmlNodeType.SignificantWhitespace: 
                case XmlNodeType.Whitespace:
                    CalibrateText(); 
 
                    break;
                default: 
                    break;
            }

            DocumentXmlWriter writer = new DocumentXmlWriter(DocumentXmlWriterType.InsertSiblingBefore, source, document); 
            writer.NamespaceManager = GetNamespaceManager(source.ParentNode, document);
            return new XmlWellFormedWriter(writer, writer.Settings); 
        } 

        public override XmlWriter CreateAttributes() { 
            if (source.NodeType != XmlNodeType.Element) {
                throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition));
            }
 
            DocumentXmlWriter writer = new DocumentXmlWriter(DocumentXmlWriterType.AppendAttribute, source, document);
            writer.NamespaceManager = GetNamespaceManager(source, document); 
            return new XmlWellFormedWriter(writer, writer.Settings); 
        }
 
        public override XmlWriter ReplaceRange(XPathNavigator lastSiblingToReplace) {
            DocumentXPathNavigator that = lastSiblingToReplace as DocumentXPathNavigator;
            if (that == null) {
                if (lastSiblingToReplace == null) { 
                    throw new ArgumentNullException("lastSiblingToReplace");
                } 
                else { 
                    throw new NotSupportedException();
                } 
            }

            this.CalibrateText();
            that.CalibrateText(); 

            XmlNode node = this.source; 
            XmlNode end = that.source; 

            if (node == end) { 
                switch (node.NodeType) {
                    case XmlNodeType.Attribute:
                    case XmlNodeType.Document:
                    case XmlNodeType.DocumentFragment: 
                        throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition));
                    case XmlNodeType.Text: 
                    case XmlNodeType.CDATA: 
                    case XmlNodeType.SignificantWhitespace:
                    case XmlNodeType.Whitespace: 
                        end = that.TextEnd(end);
                        break;
                    default:
                        break; 
                }
            } 
            else { 
                if (end.IsText) {
                    end = that.TextEnd(end); 
                }
                if (!IsFollowingSibling(node, end)) {
                    throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition));
                } 
            }
 
            DocumentXmlWriter writer = new DocumentXmlWriter(DocumentXmlWriterType.ReplaceToFollowingSibling, node, document); 
            writer.NamespaceManager = GetNamespaceManager(node.ParentNode, document);
            writer.Navigator = this; 
            writer.EndNode = end;
            return new XmlWellFormedWriter(writer, writer.Settings);
        }
 
        public override void DeleteRange(XPathNavigator lastSiblingToDelete) {
            DocumentXPathNavigator that = lastSiblingToDelete as DocumentXPathNavigator; 
            if (that == null) { 
                if (lastSiblingToDelete == null) {
                    throw new ArgumentNullException("lastSiblingToDelete"); 
                }
                else {
                    throw new NotSupportedException();
                } 
            }
 
            this.CalibrateText(); 
            that.CalibrateText();
 
            XmlNode node = this.source;
            XmlNode end = that.source;

            if (node == end) { 
                switch (node.NodeType) {
                    case XmlNodeType.Attribute: 
                        XmlAttribute attribute = (XmlAttribute)node; 
                        if (attribute.IsNamespace) {
                            goto default; 
                        }
                        XmlNode parent = OwnerNode(attribute);
                        DeleteAttribute(attribute, attributeIndex);
                        if (parent != null) { 
                            ResetPosition(parent);
                        } 
                        break; 
                    case XmlNodeType.Text:
                    case XmlNodeType.CDATA: 
                    case XmlNodeType.SignificantWhitespace:
                    case XmlNodeType.Whitespace:
                        end = that.TextEnd(end);
                        goto case XmlNodeType.Element; 
                    case XmlNodeType.Element:
                    case XmlNodeType.ProcessingInstruction: 
                    case XmlNodeType.Comment: 
                        parent = OwnerNode(node);
                        DeleteToFollowingSibling(node, end); 
                        if (parent != null) {
                            ResetPosition(parent);
                        }
                        break; 
                    default:
                        throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition)); 
                } 
            }
            else { 
                if (end.IsText) {
                    end = that.TextEnd(end);
                }
                if (!IsFollowingSibling(node, end)) { 
                    throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition));
                } 
                XmlNode parent = OwnerNode(node); 
                DeleteToFollowingSibling(node, end);
                if (parent != null) { 
                    ResetPosition(parent);
                }
            }
        } 

        public override void DeleteSelf() { 
            XmlNode node = source; 
            XmlNode end = node;
 
            switch (node.NodeType) {
                case XmlNodeType.Attribute:
                    XmlAttribute attribute = (XmlAttribute)node;
                    if (attribute.IsNamespace) { 
                        goto default;
                    } 
                    XmlNode parent = OwnerNode(attribute); 
                    DeleteAttribute(attribute, attributeIndex);
                    if (parent != null) { 
                        ResetPosition(parent);
                    }
                    break;
                case XmlNodeType.Text: 
                case XmlNodeType.CDATA:
                case XmlNodeType.SignificantWhitespace: 
                case XmlNodeType.Whitespace: 
                    CalibrateText();
 
                    node = source;
                    end = TextEnd(node);
                    goto case XmlNodeType.Element;
                case XmlNodeType.Element: 
                case XmlNodeType.ProcessingInstruction:
                case XmlNodeType.Comment: 
                    parent = OwnerNode(node); 
                    DeleteToFollowingSibling(node, end);
                    if (parent != null) { 
                        ResetPosition(parent);
                    }
                    break;
                default: 
                    throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition));
            } 
        } 

        private static void DeleteAttribute(XmlAttribute attribute, int index) { 
            XmlAttributeCollection attributes;

            if (!CheckAttributePosition(attribute, out attributes, index)
                && !ResetAttributePosition(attribute, attributes, out index)) { 
                throw new InvalidOperationException(Res.GetString(Res.Xpn_MissingParent));
            } 
            if (attribute.IsReadOnly) { 
                throw new InvalidOperationException(Res.GetString(Res.Xdom_Node_Modify_ReadOnly));
            } 
            attributes.RemoveAt(index);
        }

        internal static void DeleteToFollowingSibling(XmlNode node, XmlNode end) { 
            XmlNode parent = node.ParentNode;
 
            if (parent == null) { 
                throw new InvalidOperationException(Res.GetString(Res.Xpn_MissingParent));
            } 
            if (node.IsReadOnly
                || end.IsReadOnly) {
                throw new InvalidOperationException(Res.GetString(Res.Xdom_Node_Modify_ReadOnly));
            } 
            while (node != end) {
                XmlNode temp = node; 
                node = node.NextSibling; 
                parent.RemoveChild(temp);
            } 
            parent.RemoveChild(node);
        }

        private static XmlNamespaceManager GetNamespaceManager(XmlNode node, XmlDocument document) { 
            XmlNamespaceManager namespaceManager = new XmlNamespaceManager(document.NameTable);
            List elements = new List(); 
 
            while (node != null) {
                XmlElement element = node as XmlElement; 
                if (element != null
                    && element.HasAttributes) {
                    elements.Add(element);
                } 
                node = node.ParentNode;
            } 
            for (int i = elements.Count - 1; i >= 0; i--) { 
                namespaceManager.PushScope();
                XmlAttributeCollection attributes = elements[i].Attributes; 
                for (int j = 0; j < attributes.Count; j++) {
                    XmlAttribute attribute = attributes[j];
                    if (attribute.IsNamespace) {
                        string prefix = attribute.Prefix.Length == 0 ? string.Empty : attribute.LocalName; 
                        namespaceManager.AddNamespace(prefix, attribute.Value);
                    } 
                } 
            }
            return namespaceManager; 
        }

        internal void ResetPosition(XmlNode node) {
            Debug.Assert(node != null, "Undefined navigator position"); 
            Debug.Assert(node == document || node.OwnerDocument == document, "Navigator switched documents");
            source = node; 
            XmlAttribute attribute = node as XmlAttribute; 
            if (attribute != null) {
                XmlElement element = attribute.OwnerElement; 
                if (element != null) {
                    ResetAttributePosition(attribute, element.Attributes, out attributeIndex);
                    if (attribute.IsNamespace) {
                        namespaceParent = element; 
                    }
                } 
            } 
        }
 
        private static bool ResetAttributePosition(XmlAttribute attribute, XmlAttributeCollection attributes, out int index) {
            if (attributes != null) {
                for (int i = 0; i < attributes.Count; i++) {
                    if (attribute == attributes[i]) { 
                        index = i;
                        return true; 
                    } 
                }
            } 
            index = 0;
            return false;
        }
 
        private static bool CheckAttributePosition(XmlAttribute attribute, out XmlAttributeCollection attributes, int index) {
            XmlElement element = attribute.OwnerElement; 
            if (element != null) { 
                attributes = element.Attributes;
                if (index >= 0 
                    && index < attributes.Count
                    && attribute == attributes[index]) {
                    return true;
                } 
            }
            else { 
                attributes = null; 
            }
            return false; 
        }

        private void CalibrateText() {
            XmlNode text = PreviousText(source); 
            while (text != null) {
                ResetPosition(text); 
                text = PreviousText(text); 
            }
        } 

        private XmlNode ParentNode(XmlNode node) {
            XmlNode parent = node.ParentNode;
 
            if (!document.HasEntityReferences) {
                return parent; 
            } 
            return ParentNodeTail(parent);
        } 

        private XmlNode ParentNodeTail(XmlNode parent) {
            while (parent != null
                   && parent.NodeType == XmlNodeType.EntityReference) { 
                parent = parent.ParentNode;
            } 
            return parent; 
        }
 
        private XmlNode FirstChild(XmlNode node) {
            XmlNode child = node.FirstChild;

            if (!document.HasEntityReferences) { 
                return child;
            } 
            return FirstChildTail(child); 
        }
 
        private XmlNode FirstChildTail(XmlNode child) {
            while (child != null
                   && child.NodeType == XmlNodeType.EntityReference) {
                child = child.FirstChild; 
            }
            return child; 
        } 

        private XmlNode NextSibling(XmlNode node) { 
            XmlNode sibling = node.NextSibling;

            if (!document.HasEntityReferences) {
                return sibling; 
            }
            return NextSiblingTail(node, sibling); 
        } 

        private XmlNode NextSiblingTail(XmlNode node, XmlNode sibling) { 
            while (sibling == null) {
                node = node.ParentNode;
                if (node == null
                    || node.NodeType != XmlNodeType.EntityReference) { 
                    return null;
                } 
                sibling = node.NextSibling; 
            }
            while (sibling != null 
                   && sibling.NodeType == XmlNodeType.EntityReference) {
                sibling = sibling.FirstChild;
            }
            return sibling; 
        }
 
        private XmlNode PreviousSibling(XmlNode node) { 
            XmlNode sibling = node.PreviousSibling;
 
            if (!document.HasEntityReferences) {
                return sibling;
            }
            return PreviousSiblingTail(node, sibling); 
        }
 
        private XmlNode PreviousSiblingTail(XmlNode node, XmlNode sibling) { 
            while (sibling == null) {
                node = node.ParentNode; 
                if (node == null
                    || node.NodeType != XmlNodeType.EntityReference) {
                    return null;
                } 
                sibling = node.PreviousSibling;
            } 
            while (sibling != null 
                   && sibling.NodeType == XmlNodeType.EntityReference) {
                sibling = sibling.LastChild; 
            }
            return sibling;
        }
 
        private XmlNode PreviousText(XmlNode node) {
            XmlNode text = node.PreviousText; 
 
            if (!document.HasEntityReferences) {
                return text; 
            }
            return PreviousTextTail(node, text);
        }
 
        private XmlNode PreviousTextTail(XmlNode node, XmlNode text) {
            if (text != null) { 
                return text; 
            }
            if (!node.IsText) { 
                return null;
            }
            XmlNode sibling = node.PreviousSibling;
            while (sibling == null) { 
                node = node.ParentNode;
                if (node == null 
                    || node.NodeType != XmlNodeType.EntityReference) { 
                    return null;
                } 
                sibling = node.PreviousSibling;
            }
            while (sibling != null) {
                switch (sibling.NodeType) { 
                    case XmlNodeType.EntityReference:
                        sibling = sibling.LastChild; 
                        break; 
                    case XmlNodeType.Text:
                    case XmlNodeType.CDATA: 
                    case XmlNodeType.Whitespace:
                    case XmlNodeType.SignificantWhitespace:
                        return sibling;
                    default: 
                        return null;
                } 
            } 
            return null;
        } 

        internal static bool IsFollowingSibling(XmlNode left, XmlNode right) {
            for (;;) {
                left = left.NextSibling; 
                if (left == null) {
                    break; 
                } 
                if (left == right) {
                    return true; 
                }
            }
            return false;
        } 

        private static bool IsDescendant(XmlNode top, XmlNode bottom) { 
            for (;;) { 
                XmlNode parent = bottom.ParentNode;
                if (parent == null) { 
                    XmlAttribute attribute = bottom as XmlAttribute;
                    if (attribute == null) {
                        break;
                    } 
                    parent = attribute.OwnerElement;
                    if (parent == null) { 
                        break; 
                    }
                } 
                bottom = parent;
                if (top == bottom) {
                    return true;
                } 
            }
            return false; 
        } 

        private static bool IsValidChild(XmlNode parent, XmlNode child) { 
            switch (parent.NodeType) {
                case XmlNodeType.Element:
                    return true;
                case XmlNodeType.DocumentFragment: 
                    switch (child.NodeType) {
                        case XmlNodeType.Element: 
                        case XmlNodeType.Text: 
                        case XmlNodeType.CDATA:
                        case XmlNodeType.ProcessingInstruction: 
                        case XmlNodeType.Comment:
                        case XmlNodeType.Whitespace:
                        case XmlNodeType.SignificantWhitespace:
                            return true; 
                    }
                    break; 
                case XmlNodeType.Document: 
                    switch (child.NodeType) {
                        case XmlNodeType.Element: 
                        case XmlNodeType.ProcessingInstruction:
                        case XmlNodeType.Comment:
                            return true;
                    } 
                    break;
                default: 
                    break; 
            }
            return false; 
        }

        private XmlNode TextStart(XmlNode node) {
            XmlNode start; 

            do { 
                start = node; 
                node = PreviousSibling(node);
            } 
            while (node != null
                   && node.IsText);
            return start;
        } 

        private XmlNode TextEnd(XmlNode node) { 
            XmlNode end; 

            do { 
                end = node;
                node = NextSibling(node);
            }
            while (node != null 
                   && node.IsText);
            return end; 
        } 
    }
 
    // An iterator that matches no nodes
    internal sealed class DocumentXPathNodeIterator_Empty : XPathNodeIterator {
        private XPathNavigator nav;
 
        internal DocumentXPathNodeIterator_Empty( DocumentXPathNavigator nav )               { this.nav = nav.Clone(); }
        internal DocumentXPathNodeIterator_Empty( DocumentXPathNodeIterator_Empty other )    { this.nav = other.nav.Clone(); } 
        public override XPathNodeIterator Clone()   { return new DocumentXPathNodeIterator_Empty( this ); } 
        public override bool MoveNext()         { return false; }
        public override XPathNavigator Current  { get { return nav; } } 
        public override int CurrentPosition     { get { return 0; } }
        public override int Count                { get { return 0; } }
    }
 
    // An iterator that can match any child elements that match the Match condition (overrided in the derived class)
    internal abstract class DocumentXPathNodeIterator_ElemDescendants : XPathNodeIterator { 
        private DocumentXPathNavigator nav; 
        private int level;
        private int position; 

        internal DocumentXPathNodeIterator_ElemDescendants( DocumentXPathNavigator nav ) {
            this.nav      = (DocumentXPathNavigator)(nav.Clone());
            this.level    = 0; 
            this.position = 0;
        } 
        internal DocumentXPathNodeIterator_ElemDescendants( DocumentXPathNodeIterator_ElemDescendants other ) { 
            this.nav      = (DocumentXPathNavigator)(other.nav.Clone());
            this.level    = other.level; 
            this.position = other.position;
        }

        protected abstract bool Match( XmlNode node ); 

        public override XPathNavigator Current { 
            get { return nav; } 
        }
 
        public override int CurrentPosition {
            get { return position; }
        }
 
        protected void SetPosition( int pos ) {
            position = pos; 
        } 

        public override bool MoveNext() { 
            for (;;) {
                if (nav.MoveToFirstChild()) {
                    level++;
                } 
                else {
                    if (level == 0) { 
                        return false; 
                    }
                    while (!nav.MoveToNext()) { 
                        level--;
                        if (level == 0) {
                            return false;
                        } 
                        if (!nav.MoveToParent()) {
                            return false; 
                        } 
                    }
                } 
                XmlNode node = (XmlNode)nav.UnderlyingObject;
                if (node.NodeType == XmlNodeType.Element && Match(node)) {
                    position++;
                    return true; 
                }
            } 
        } 
    }
 
    // Iterate over all element children irrespective of the localName and namespace
    internal class DocumentXPathNodeIterator_AllElemChildren : DocumentXPathNodeIterator_ElemDescendants {
        internal DocumentXPathNodeIterator_AllElemChildren( DocumentXPathNavigator nav ) : base( nav ) {
            Debug.Assert( ((XmlNode)nav.UnderlyingObject).NodeType != XmlNodeType.Attribute ); 
        }
        internal DocumentXPathNodeIterator_AllElemChildren( DocumentXPathNodeIterator_AllElemChildren other ) : base( other ) { 
        } 

        public override XPathNodeIterator Clone() { 
            return new DocumentXPathNodeIterator_AllElemChildren( this );
        }

        protected override bool Match( XmlNode node ) { 
            Debug.Assert( node != null );
            return ( node.NodeType == XmlNodeType.Element ); 
        } 
    }
    // Iterate over all element children irrespective of the localName and namespace, include the self node when testing for localName/ns 
    internal sealed class DocumentXPathNodeIterator_AllElemChildren_AndSelf :  DocumentXPathNodeIterator_AllElemChildren {
        internal DocumentXPathNodeIterator_AllElemChildren_AndSelf( DocumentXPathNavigator nav ) : base( nav ) {
        }
        internal DocumentXPathNodeIterator_AllElemChildren_AndSelf( DocumentXPathNodeIterator_AllElemChildren_AndSelf other ) : base( other ) { 
        }
 
        public override XPathNodeIterator Clone() { 
            return new DocumentXPathNodeIterator_AllElemChildren_AndSelf( this );
        } 

        public override bool MoveNext() {
            if( CurrentPosition == 0 ) {
                DocumentXPathNavigator nav = (DocumentXPathNavigator)this.Current; 
                XmlNode node = (XmlNode)nav.UnderlyingObject;
                if ( node.NodeType == XmlNodeType.Element && Match( node ) ) { 
                    SetPosition( 1 ); 
                    return true;
                } 
            }
            return base.MoveNext();
        }
    } 
    // Iterate over all element children that have a given namespace but irrespective of the localName
    internal class DocumentXPathNodeIterator_ElemChildren_NoLocalName : DocumentXPathNodeIterator_ElemDescendants { 
        private string nsAtom; 

        internal DocumentXPathNodeIterator_ElemChildren_NoLocalName( DocumentXPathNavigator nav, string nsAtom ) : base( nav ) { 
            Debug.Assert( ((XmlNode)nav.UnderlyingObject).NodeType != XmlNodeType.Attribute );
            Debug.Assert( Ref.Equal(nav.NameTable.Get( nsAtom ), nsAtom) );
            this.nsAtom = nsAtom;
        } 
        internal DocumentXPathNodeIterator_ElemChildren_NoLocalName( DocumentXPathNodeIterator_ElemChildren_NoLocalName other ) : base( other ) {
            this.nsAtom = other.nsAtom; 
        } 
        public override XPathNodeIterator Clone() {
            return new DocumentXPathNodeIterator_ElemChildren_NoLocalName( this ); 
        }

        protected override bool Match( XmlNode node ) {
            Debug.Assert( node != null ); 
            Debug.Assert( node.NodeType == XmlNodeType.Element );
            return Ref.Equal(node.NamespaceURI, nsAtom); 
        } 
    }
    // Iterate over all element children that have a given namespace but irrespective of the localName, include self node when checking for ns 
    internal sealed class DocumentXPathNodeIterator_ElemChildren_AndSelf_NoLocalName :  DocumentXPathNodeIterator_ElemChildren_NoLocalName {

        internal DocumentXPathNodeIterator_ElemChildren_AndSelf_NoLocalName( DocumentXPathNavigator nav, string nsAtom ) : base( nav, nsAtom ) {
        } 
        internal DocumentXPathNodeIterator_ElemChildren_AndSelf_NoLocalName( DocumentXPathNodeIterator_ElemChildren_AndSelf_NoLocalName other ) : base( other ) {
        } 
 
        public override XPathNodeIterator Clone() {
            return new DocumentXPathNodeIterator_ElemChildren_AndSelf_NoLocalName( this ); 
        }

        public override bool MoveNext() {
            if( CurrentPosition == 0 ) { 
                DocumentXPathNavigator nav = (DocumentXPathNavigator)this.Current;
                XmlNode node = (XmlNode)nav.UnderlyingObject; 
                if ( node.NodeType == XmlNodeType.Element && Match( node ) ) { 
                    SetPosition( 1 );
                    return true; 
                }
            }
            return base.MoveNext();
        } 
    }
    // Iterate over all element children that have a given name and namespace 
    internal class DocumentXPathNodeIterator_ElemChildren : DocumentXPathNodeIterator_ElemDescendants { 
        protected string localNameAtom;
        protected string nsAtom; 

        internal DocumentXPathNodeIterator_ElemChildren( DocumentXPathNavigator nav, string localNameAtom, string nsAtom ) : base( nav ) {
            Debug.Assert( ((XmlNode)nav.UnderlyingObject).NodeType != XmlNodeType.Attribute );
            Debug.Assert( Ref.Equal(nav.NameTable.Get( localNameAtom ), localNameAtom) ); 
            Debug.Assert( Ref.Equal(nav.NameTable.Get( nsAtom ), nsAtom) );
            Debug.Assert( localNameAtom.Length > 0 );   // Use DocumentXPathNodeIterator_ElemChildren_NoLocalName class for special magic value of localNameAtom 
 
            this.localNameAtom = localNameAtom;
            this.nsAtom        = nsAtom; 
        }

        internal DocumentXPathNodeIterator_ElemChildren( DocumentXPathNodeIterator_ElemChildren other ) : base( other ) {
            this.localNameAtom = other.localNameAtom; 
            this.nsAtom        = other.nsAtom;
        } 
 
        public override XPathNodeIterator Clone() {
            return new DocumentXPathNodeIterator_ElemChildren( this ); 
        }

        protected override bool Match( XmlNode node ) {
            Debug.Assert( node != null ); 
            Debug.Assert( node.NodeType == XmlNodeType.Element );
            return Ref.Equal(node.LocalName, localNameAtom) && Ref.Equal(node.NamespaceURI, nsAtom); 
        } 
    }
    // Iterate over all elem children and itself and check for the given localName (including the magic value "") and namespace 
    internal sealed class DocumentXPathNodeIterator_ElemChildren_AndSelf : DocumentXPathNodeIterator_ElemChildren {

        internal DocumentXPathNodeIterator_ElemChildren_AndSelf( DocumentXPathNavigator nav, string localNameAtom, string nsAtom )
            : base( nav, localNameAtom, nsAtom ) { 
            Debug.Assert( localNameAtom.Length > 0 );   // Use DocumentXPathNodeIterator_ElemChildren_AndSelf_NoLocalName if localName == String.Empty
        } 
        internal DocumentXPathNodeIterator_ElemChildren_AndSelf( DocumentXPathNodeIterator_ElemChildren_AndSelf other ) : base( other ) { 
        }
 
        public override XPathNodeIterator Clone() {
            return new DocumentXPathNodeIterator_ElemChildren_AndSelf( this );
        }
 
        public override bool MoveNext() {
            if( CurrentPosition == 0 ) { 
                DocumentXPathNavigator nav = (DocumentXPathNavigator)this.Current; 
                XmlNode node = (XmlNode)nav.UnderlyingObject;
                if ( node.NodeType == XmlNodeType.Element && Match( node ) ) { 
                    SetPosition( 1 );
                    return true;
                }
            } 
            return base.MoveNext();
        } 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
//-----------------------------------------------------------------------------
 
using System; 
using System.Collections;
using System.Collections.Generic; 
using System.Text;
using System.Xml.Schema;
using System.Xml.XPath;
using System.Diagnostics; 

namespace System.Xml { 
    internal sealed class DocumentXPathNavigator : XPathNavigator, IHasXmlNode { 
        private XmlDocument document; // owner document
        private XmlNode source; // navigator position 
        private int attributeIndex; // index in attribute collection for attribute
        private XmlElement namespaceParent; // parent for namespace

        public DocumentXPathNavigator(XmlDocument document, XmlNode node) { 
            this.document = document;
            ResetPosition(node); 
        } 

        public DocumentXPathNavigator(DocumentXPathNavigator other) { 
            document = other.document;
            source = other.source;
            attributeIndex = other.attributeIndex;
            namespaceParent = other.namespaceParent; 
        }
 
        public override XPathNavigator Clone() { 
            return new DocumentXPathNavigator(this);
        } 

        public override void SetValue(string value) {
            if (value == null) {
                throw new ArgumentNullException("value"); 
            }
 
            XmlNode node = source; 
            XmlNode end;
 
            switch (node.NodeType) {
                case XmlNodeType.Attribute:
                    if (((XmlAttribute)node).IsNamespace) {
                        goto default; 
                    }
                    node.InnerText = value; 
                    break; 
                case XmlNodeType.Text:
                case XmlNodeType.CDATA: 
                case XmlNodeType.Whitespace:
                case XmlNodeType.SignificantWhitespace:
                    CalibrateText();
 
                    node = source;
                    end = TextEnd(node); 
                    if (node != end) { 
                        if (node.IsReadOnly) {
                            throw new InvalidOperationException(Res.GetString(Res.Xdom_Node_Modify_ReadOnly)); 
                        }
                        DeleteToFollowingSibling(node.NextSibling, end);
                    }
                    goto case XmlNodeType.Element; 
                case XmlNodeType.Element:
                case XmlNodeType.ProcessingInstruction: 
                case XmlNodeType.Comment: 
                    node.InnerText = value;
                    break; 
                default:
                    throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition));
            }
        } 

        public override XmlNameTable NameTable { 
            get { 
                return document.NameTable;
            } 
        }

        public override XPathNodeType NodeType {
            get { 
                CalibrateText();
 
                return (XPathNodeType)source.XPNodeType; 
            }
        } 

        public override string LocalName {
            get {
                return source.XPLocalName; 
            }
        } 
 
        public override string NamespaceURI {
            get { 
                XmlAttribute attribute = source as XmlAttribute;
                if (attribute != null
                    && attribute.IsNamespace) {
                    return string.Empty; 
                }
                return source.NamespaceURI; 
            } 
        }
 
        public override string Name {
            get {
                switch (source.NodeType) {
                    case XmlNodeType.Element: 
                    case XmlNodeType.ProcessingInstruction:
                        return source.Name; 
                    case XmlNodeType.Attribute: 
                        if (((XmlAttribute)source).IsNamespace) {
                            string localName = source.LocalName; 
                            if (Ref.Equals(localName, document.strXmlns)) {
                                return string.Empty; // xmlns declaration
                            }
                            return localName; // xmlns:name declaration 
                        }
                        return source.Name; // attribute 
                    default: 
                        return string.Empty;
                } 
            }
        }

        public override string Prefix { 
            get {
                XmlAttribute attribute = source as XmlAttribute; 
                if (attribute != null 
                    && attribute.IsNamespace) {
                    return string.Empty; 
                }
                return source.Prefix;
            }
        } 

        public override string Value { 
            get { 
                switch (source.NodeType) {
                    case XmlNodeType.Element: 
                    case XmlNodeType.DocumentFragment:
                        return source.InnerText;
                    case XmlNodeType.Document:
                        return ValueDocument; 
                    case XmlNodeType.Text:
                    case XmlNodeType.CDATA: 
                    case XmlNodeType.Whitespace: 
                    case XmlNodeType.SignificantWhitespace:
                        return ValueText; 
                    default:
                        return source.Value;
                }
            } 
        }
 
        private string ValueDocument { 
            get {
                XmlElement element = document.DocumentElement; 
                if (element != null) {
                    return element.InnerText;
                }
                return string.Empty; 
            }
        } 
 
        private string ValueText {
            get { 
                CalibrateText();

                string value = source.Value;
                XmlNode nextSibling = NextSibling(source); 
                if (nextSibling != null
                    && nextSibling.IsText) { 
                    StringBuilder builder = new StringBuilder(value); 
                    do {
                        builder.Append(nextSibling.Value); 
                        nextSibling = NextSibling(nextSibling);
                    }
                    while (nextSibling != null
                           && nextSibling.IsText); 
                    value = builder.ToString();
                } 
                return value; 
            }
        } 

        public override string BaseURI {
            get {
                return source.BaseURI; 
            }
        } 
 
        public override bool IsEmptyElement {
            get { 
                XmlElement element = source as XmlElement;
                if (element != null) {
                    return element.IsEmpty;
                } 
                return false;
            } 
        } 

        public override string XmlLang { 
            get {
                return source.XmlLang;
            }
        } 

        public override object UnderlyingObject { 
            get { 
                CalibrateText();
 
                return source;
            }
        }
 
        public override bool HasAttributes {
            get { 
                XmlElement element = source as XmlElement; 
                if (element != null
                    && element.HasAttributes) { 
                    XmlAttributeCollection attributes = element.Attributes;
                    for (int i = 0; i < attributes.Count; i++) {
                        XmlAttribute attribute = attributes[i];
                        if (!attribute.IsNamespace) { 
                            return true;
                        } 
                    } 
                }
                return false; 
            }
        }

        public override string GetAttribute(string localName, string namespaceURI) { 
            return source.GetXPAttribute(localName, namespaceURI);
        } 
 
        public override bool MoveToAttribute(string localName, string namespaceURI) {
            XmlElement element = source as XmlElement; 
            if (element != null
                && element.HasAttributes) {
                XmlAttributeCollection attributes = element.Attributes;
                for (int i = 0; i < attributes.Count; i++) { 
                    XmlAttribute attribute = attributes[i];
                    if (attribute.LocalName == localName 
                        && attribute.NamespaceURI == namespaceURI) { 
                        if (!attribute.IsNamespace) {
                            source = attribute; 
                            attributeIndex = i;
                            return true;
                        }
                        else { 
                            return false;
                        } 
                    } 
                }
            } 
            return false;
        }

        public override bool MoveToFirstAttribute() { 
            XmlElement element = source as XmlElement;
            if (element != null 
                && element.HasAttributes) { 
                XmlAttributeCollection attributes = element.Attributes;
                for (int i = 0; i < attributes.Count; i++) { 
                    XmlAttribute attribute = attributes[i];
                    if (!attribute.IsNamespace) {
                        source = attribute;
                        attributeIndex = i; 
                        return true;
                    } 
                } 
            }
            return false; 
        }

        public override bool MoveToNextAttribute() {
            XmlAttribute attribute = source as XmlAttribute; 
            if (attribute == null
                || attribute.IsNamespace) { 
                return false; 
            }
            XmlAttributeCollection attributes; 
            if (!CheckAttributePosition(attribute, out attributes, attributeIndex)
                && !ResetAttributePosition(attribute, attributes, out attributeIndex)) {
                return false;
            } 
            for (int i = attributeIndex + 1; i < attributes.Count; i++) {
                attribute = attributes[i]; 
                if (!attribute.IsNamespace) { 
                    source = attribute;
                    attributeIndex = i; 
                    return true;
                }
            }
            return false; 
        }
 
        public override string GetNamespace(string name) { 
            XmlNode node = source;
            while (node != null 
                   && node.NodeType != XmlNodeType.Element) {
                XmlAttribute attribute = node as XmlAttribute;
                if (attribute != null) {
                    node = attribute.OwnerElement; 
                }
                else { 
                    node = node.ParentNode; 
                }
            } 

            XmlElement element = node as XmlElement;
            if (element != null) {
                string localName; 
                if (name != null
                    && name.Length != 0) { 
                    localName = name; 
                }
                else { 
                    localName = document.strXmlns;
                }
                string namespaceUri = document.strReservedXmlns;
 
                do
                { 
                    XmlAttribute attribute = element.GetAttributeNode(localName, namespaceUri); 
                    if (attribute != null) {
                        return attribute.Value; 
                    }
                    element = element.ParentNode as XmlElement;
                }
                while (element != null); 
            }
 
            if (name == document.strXml) { 
                return document.strReservedXml;
            } 
            else if (name == document.strXmlns) {
                return document.strReservedXmlns;
            }
            return string.Empty; 
        }
 
        public override bool MoveToNamespace(string name) { 
            if (name == document.strXmlns) {
                return false; 
            }
            XmlElement element = source as XmlElement;
            if (element != null) {
                string localName; 
                if (name != null
                    && name.Length != 0) { 
                    localName = name; 
                }
                else { 
                    localName = document.strXmlns;
                }
                string namespaceUri = document.strReservedXmlns;
 
                do {
                    XmlAttribute attribute = element.GetAttributeNode(localName, namespaceUri); 
                    if (attribute != null) { 
                        namespaceParent = (XmlElement)source;
                        source = attribute; 
                        return true;
                    }
                    element = element.ParentNode as XmlElement;
                } 
                while (element != null);
 
                if (name == document.strXml) { 
                    namespaceParent = (XmlElement)source;
                    source = document.NamespaceXml; 
                    return true;
                }
            }
            return false; 
        }
 
        public override bool MoveToFirstNamespace(XPathNamespaceScope scope) { 
            XmlElement element = source as XmlElement;
            if (element == null) { 
                return false;
            }
            XmlAttributeCollection attributes;
            int index = Int32.MaxValue; 
            switch (scope) {
                case XPathNamespaceScope.Local: 
                    if (!element.HasAttributes) { 
                        return false;
                    } 
                    attributes = element.Attributes;
                    if (!MoveToFirstNamespaceLocal(attributes, ref index)) {
                        return false;
                    } 
                    source = attributes[index];
                    attributeIndex = index; 
                    namespaceParent = element; 
                    break;
                case XPathNamespaceScope.ExcludeXml: 
                    attributes = element.Attributes;
                    if (!MoveToFirstNamespaceGlobal(ref attributes, ref index)) {
                        return false;
                    } 
                    XmlAttribute attribute = attributes[index];
                    while (Ref.Equals(attribute.LocalName, document.strXml)) { 
                        if (!MoveToNextNamespaceGlobal(ref attributes, ref index)) { 
                            return false;
                        } 
                        attribute = attributes[index];
                    }
                    source = attribute;
                    attributeIndex = index; 
                    namespaceParent = element;
                    break; 
                case XPathNamespaceScope.All: 
                    attributes = element.Attributes;
                    if (!MoveToFirstNamespaceGlobal(ref attributes, ref index)) { 
                        source = document.NamespaceXml;
                        // attributeIndex = 0;
                    }
                    else { 
                        source = attributes[index];
                        attributeIndex = index; 
                    } 
                    namespaceParent = element;
                    break; 
                default:
                    Debug.Assert(false);
                    return false;
            } 
            return true;
        } 
 
        private static bool MoveToFirstNamespaceLocal(XmlAttributeCollection attributes, ref int index) {
            Debug.Assert(attributes != null); 
            for (int i = attributes.Count - 1; i >= 0; i--) {
                XmlAttribute attribute = attributes[i];
                if (attribute.IsNamespace) {
                    index = i; 
                    return true;
                } 
            } 
            return false;
        } 

        private static bool MoveToFirstNamespaceGlobal(ref XmlAttributeCollection attributes, ref int index) {
            if (MoveToFirstNamespaceLocal(attributes, ref index)) {
                return true; 
            }
 
            Debug.Assert(attributes != null && attributes.parent != null); 
            XmlElement element = attributes.parent.ParentNode as XmlElement;
            while (element != null) { 
                if (element.HasAttributes) {
                    attributes = element.Attributes;
                    if (MoveToFirstNamespaceLocal(attributes, ref index)) {
                        return true; 
                    }
                } 
                element = element.ParentNode as XmlElement; 
            }
            return false; 
        }

        public override bool MoveToNextNamespace(XPathNamespaceScope scope) {
            XmlAttribute attribute = source as XmlAttribute; 
            if (attribute == null
                || !attribute.IsNamespace) { 
                return false; 
            }
            XmlAttributeCollection attributes; 
            int index = attributeIndex;
            if (!CheckAttributePosition(attribute, out attributes, index)
                && !ResetAttributePosition(attribute, attributes, out index)) {
                return false; 
            }
            Debug.Assert(namespaceParent != null); 
            switch (scope) { 
                case XPathNamespaceScope.Local:
                    if (attribute.OwnerElement != namespaceParent) { 
                        return false;
                    }
                    if (!MoveToNextNamespaceLocal(attributes, ref index)) {
                        return false; 
                    }
                    source = attributes[index]; 
                    attributeIndex = index; 
                    break;
                case XPathNamespaceScope.ExcludeXml: 
                    string localName;
                    do {
                        if (!MoveToNextNamespaceGlobal(ref attributes, ref index)) {
                            return false; 
                        }
                        attribute = attributes[index]; 
                        localName = attribute.LocalName; 
                    }
                    while (PathHasDuplicateNamespace(attribute.OwnerElement, namespaceParent, localName) 
                           || Ref.Equals(localName, document.strXml));
                    source = attribute;
                    attributeIndex = index;
                    break; 
                case XPathNamespaceScope.All:
                    do { 
                        if (!MoveToNextNamespaceGlobal(ref attributes, ref index)) { 
                            if (PathHasDuplicateNamespace(null, namespaceParent, document.strXml)) {
                                return false; 
                            }
                            else {
                                source = document.NamespaceXml;
                                // attributeIndex = 0; 
                                return true;
                            } 
                        } 
                        attribute = attributes[index];
                    } 
                    while (PathHasDuplicateNamespace(attribute.OwnerElement, namespaceParent, attribute.LocalName));
                    source = attribute;
                    attributeIndex = index;
                    break; 
                default:
                    Debug.Assert(false); 
                    return false; 
            }
            return true; 
        }

        private static bool MoveToNextNamespaceLocal(XmlAttributeCollection attributes, ref int index) {
            Debug.Assert(attributes != null); 
            Debug.Assert(0 <= index && index < attributes.Count);
            for (int i = index - 1; i >= 0; i--) { 
                XmlAttribute attribute = attributes[i]; 
                if (attribute.IsNamespace) {
                    index = i; 
                    return true;
                }
            }
            return false; 
        }
 
        private static bool MoveToNextNamespaceGlobal(ref XmlAttributeCollection attributes, ref int index) { 
            if (MoveToNextNamespaceLocal(attributes, ref index)) {
                return true; 
            }

            Debug.Assert(attributes != null && attributes.parent != null);
            XmlElement element = attributes.parent.ParentNode as XmlElement; 
            while (element != null) {
                if (element.HasAttributes) { 
                    attributes = element.Attributes; 
                    if (MoveToFirstNamespaceLocal(attributes, ref index)) {
                        return true; 
                    }
                }
                element = element.ParentNode as XmlElement;
            } 
            return false;
        } 
 
        private bool PathHasDuplicateNamespace(XmlElement top, XmlElement bottom, string localName) {
            string namespaceUri = document.strReservedXmlns; 
            while (bottom != null
                   && bottom != top) {
                XmlAttribute attribute = bottom.GetAttributeNode(localName, namespaceUri);
                if (attribute != null) { 
                    return true;
                } 
                bottom = bottom.ParentNode as XmlElement; 
            }
            return false; 
        }

        public override bool MoveToNext() {
            XmlNode sibling = NextSibling(source); 
            if (sibling == null) {
                return false; 
            } 
            if (sibling.IsText) {
                if (source.IsText) { 
                    sibling = NextSibling(TextEnd(sibling));
                    if (sibling == null) {
                        return false;
                    } 
                }
            } 
            XmlNode parent = ParentNode(sibling); 
            Debug.Assert(parent != null);
            while (!IsValidChild(parent, sibling)) { 
                sibling = NextSibling(sibling);
                if (sibling == null) {
                    return false;
                } 
            }
            source = sibling; 
            return true; 
        }
 
        public override bool MoveToPrevious() {
            XmlNode sibling = PreviousSibling(source);
            if (sibling == null) {
                return false; 
            }
            if (sibling.IsText) { 
                if (source.IsText) { 
                    sibling = PreviousSibling(TextStart(sibling));
                    if (sibling == null) { 
                        return false;
                    }
                }
                else { 
                    sibling = TextStart(sibling);
                } 
            } 
            XmlNode parent = ParentNode(sibling);
            Debug.Assert(parent != null); 
            while (!IsValidChild(parent, sibling)) {
                sibling = PreviousSibling(sibling);
                if (sibling == null) {
                    return false; 
                }
                // if (sibling.IsText) { 
                //     sibling = TextStart(sibling); 
                // }
            } 
            source = sibling;
            return true;
        }
 
        public override bool MoveToFirst() {
            if (source.NodeType == XmlNodeType.Attribute) { 
                return false; 
            }
            XmlNode parent = ParentNode(source); 
            if (parent == null) {
                return false;
            }
            XmlNode sibling = FirstChild(parent); 
            Debug.Assert(sibling != null);
            while (!IsValidChild(parent, sibling)) { 
                sibling = NextSibling(sibling); 
                if (sibling == null) {
                    return false; 
                }
            }
            source = sibling;
            return true; 
        }
 
        public override bool MoveToFirstChild() { 
            XmlNode child;
            switch (source.NodeType) { 
                case XmlNodeType.Element:
                    child = FirstChild(source);
                    if (child == null) {
                        return false; 
                    }
                    break; 
                case XmlNodeType.DocumentFragment: 
                case XmlNodeType.Document:
                    child = FirstChild(source); 
                    if (child == null) {
                        return false;
                    }
                    while (!IsValidChild(source, child)) { 
                        child = NextSibling(child);
                        if (child == null) { 
                            return false; 
                        }
                    } 
                    break;
                default:
                    return false;
 
            }
            source = child; 
            return true; 
        }
 
        public override bool MoveToParent() {
            XmlNode parent = ParentNode(source);
            if (parent != null) {
                source = parent; 
                return true;
            } 
            XmlAttribute attribute = source as XmlAttribute; 
            if (attribute != null) {
                parent = attribute.IsNamespace ? namespaceParent : attribute.OwnerElement; 
                if (parent != null) {
                    source = parent;
                    namespaceParent = null;
                    return true; 
                }
            } 
            return false; 
        }
 
        public override void MoveToRoot() {
            for (;;) {
                XmlNode parent = source.ParentNode;
                if (parent == null) { 
                    XmlAttribute attribute = source as XmlAttribute;
                    if (attribute == null) { 
                        break; 
                    }
                    parent = attribute.IsNamespace ? namespaceParent : attribute.OwnerElement; 
                    if (parent == null) {
                        break;
                    }
                } 
                source = parent;
            } 
            namespaceParent = null; 
        }
 
        public override bool MoveTo(XPathNavigator other) {
            DocumentXPathNavigator that = other as DocumentXPathNavigator;
            if (that != null
                && document == that.document) { 
                source = that.source;
                attributeIndex = that.attributeIndex; 
                namespaceParent = that.namespaceParent; 
                return true;
            } 
            return false;
        }

        public override bool MoveToId(string id) { 
            XmlElement element = document.GetElementById(id);
            if (element != null) { 
                source = element; 
                namespaceParent = null;
                return true; 
            }
            return false;
        }
 
        public override bool MoveToChild(string localName, string namespaceUri) {
            if (source.NodeType == XmlNodeType.Attribute) { 
                return false; 
            }
 
            XmlNode child = FirstChild(source);
            if (child != null) {
                do {
                    if (child.NodeType == XmlNodeType.Element 
                        && child.LocalName == localName
                        && child.NamespaceURI == namespaceUri) { 
                        source = child; 
                        return true;
                    } 
                    child = NextSibling(child);
                }
                while (child != null);
            } 
            return false;
        } 
 
        public override bool MoveToChild(XPathNodeType type) {
            if (source.NodeType == XmlNodeType.Attribute) { 
                return false;
            }

            XmlNode child = FirstChild(source); 
            if (child != null) {
                int mask = GetContentKindMask(type); 
                if (mask == 0) { 
                    return false;
                } 
                do {
                    if (((1 << (int)child.XPNodeType) & mask) != 0) {
                        source = child;
                        return true; 
                    }
                    child = NextSibling(child); 
                } 
                while (child != null);
            } 
            return false;
        }

        public override bool MoveToFollowing(string localName, string namespaceUri, XPathNavigator end) { 
            XmlNode pastFollowing = null;
            DocumentXPathNavigator that = end as DocumentXPathNavigator; 
            if (that != null) { 
                if (document != that.document) {
                    return false; 
                }
                switch (that.source.NodeType) {
                    case XmlNodeType.Attribute:
                        that = (DocumentXPathNavigator)that.Clone(); 
                        if (!that.MoveToNonDescendant()) {
                            return false; 
                        } 
                        break;
                } 
                pastFollowing = that.source;
            }

            XmlNode following = source; 
            if (following.NodeType == XmlNodeType.Attribute) {
                following = ((XmlAttribute)following).OwnerElement; 
                if (following == null) { 
                    return false;
                } 
            }
            do {
                XmlNode firstChild = following.FirstChild;
                if (firstChild != null) { 
                    following = firstChild;
                } 
                else { 
                    for (;;) {
                        XmlNode nextSibling = following.NextSibling; 
                        if (nextSibling != null) {
                            following = nextSibling;
                            break;
                        } 
                        else {
                            XmlNode parent = following.ParentNode; 
                            if (parent != null) { 
                                following = parent;
                            } 
                            else {
                                return false;
                            }
                        } 
                    }
                } 
                if (following == pastFollowing) { 
                    return false;
                } 
            }
            while (following.NodeType != XmlNodeType.Element
                   || following.LocalName != localName
                   || following.NamespaceURI != namespaceUri); 

            source = following; 
            return true; 
        }
 
        public override bool MoveToFollowing(XPathNodeType type, XPathNavigator end) {
            XmlNode pastFollowing = null;
            DocumentXPathNavigator that = end as DocumentXPathNavigator;
            if (that != null) { 
                if (document != that.document) {
                    return false; 
                } 
                switch (that.source.NodeType) {
                    case XmlNodeType.Attribute: 
                        that = (DocumentXPathNavigator)that.Clone();
                        if (!that.MoveToNonDescendant()) {
                            return false;
                        } 
                        break;
                } 
                pastFollowing = that.source; 
            }
 
            int mask = GetContentKindMask(type);
            if (mask == 0) {
                return false;
            } 
            XmlNode following = source;
            switch (following.NodeType) { 
                case XmlNodeType.Attribute: 
                    following = ((XmlAttribute)following).OwnerElement;
                    if (following == null) { 
                        return false;
                    }
                    break;
                case XmlNodeType.Text: 
                case XmlNodeType.CDATA:
                case XmlNodeType.SignificantWhitespace: 
                case XmlNodeType.Whitespace: 
                    following = TextEnd(following);
                    break; 
            }
            do {
                XmlNode firstChild = following.FirstChild;
                if (firstChild != null) { 
                    following = firstChild;
                } 
                else { 
                    for (;;) {
                        XmlNode nextSibling = following.NextSibling; 
                        if (nextSibling != null) {
                            following = nextSibling;
                            break;
                        } 
                        else {
                            XmlNode parent = following.ParentNode; 
                            if (parent != null) { 
                                following = parent;
                            } 
                            else {
                                return false;
                            }
                        } 
                    }
                } 
                if (following == pastFollowing) { 
                    return false;
                } 
            }
            while (((1 << (int)following.XPNodeType) & mask) == 0);

            source = following; 
            return true;
        } 
 
        public override bool MoveToNext(string localName, string namespaceUri) {
            XmlNode sibling = NextSibling(source); 
            if (sibling == null) {
                return false;
            }
            do { 
                if (sibling.NodeType == XmlNodeType.Element
                    && sibling.LocalName == localName 
                    && sibling.NamespaceURI == namespaceUri) { 
                    source = sibling;
                    return true; 
                }
                sibling = NextSibling(sibling);
            }
            while (sibling != null); 
            return false;
        } 
 
        public override bool MoveToNext(XPathNodeType type) {
            XmlNode sibling = NextSibling(source); 
            if (sibling == null) {
                return false;
            }
            if (sibling.IsText 
                && source.IsText) {
                sibling = NextSibling(TextEnd(sibling)); 
                if (sibling == null) { 
                    return false;
                } 
            }

            int mask = GetContentKindMask(type);
            if (mask == 0) { 
                return false;
            } 
            do { 
                if (((1 << (int)sibling.XPNodeType) & mask) != 0) {
                    source = sibling; 
                    return true;
                }
                sibling = NextSibling(sibling);
            } 
            while (sibling != null);
            return false; 
        } 

        public override bool HasChildren { 
            get {
                XmlNode child;
                switch (source.NodeType) {
                    case XmlNodeType.Element: 
                        child = FirstChild(source);
                        if (child == null) { 
                            return false; 
                        }
                        return true; 
                    case XmlNodeType.DocumentFragment:
                    case XmlNodeType.Document:
                        child = FirstChild(source);
                        if (child == null) { 
                            return false;
                        } 
                        while (!IsValidChild(source, child)) { 
                            child = NextSibling(child);
                            if (child == null) { 
                                return false;
                            }
                        }
                        return true; 
                    default:
                        return false; 
                } 
            }
        } 

        public override bool IsSamePosition(XPathNavigator other) {
            DocumentXPathNavigator that = other as DocumentXPathNavigator;
            if (that != null) { 
                this.CalibrateText();
                that.CalibrateText(); 
 
                return this.source == that.source
                       && this.namespaceParent == that.namespaceParent; 
            }
            return false;
        }
 
        public override bool IsDescendant(XPathNavigator other) {
            DocumentXPathNavigator that = other as DocumentXPathNavigator; 
            if (that != null) { 
                return IsDescendant(this.source, that.source);
            } 
            return false;
        }

        public override IXmlSchemaInfo SchemaInfo { 
            get {
                return source.SchemaInfo; 
            } 
        }
 
        public override bool CheckValidity(XmlSchemaSet schemas, ValidationEventHandler validationEventHandler) {
            XmlDocument ownerDocument;

            if (source.NodeType == XmlNodeType.Document) { 
                ownerDocument = (XmlDocument)source;
            } 
            else { 
                ownerDocument = source.OwnerDocument;
 
                if (schemas != null) {
                    throw new ArgumentException(Res.GetString(Res.XPathDocument_SchemaSetNotAllowed, null));
                }
            } 
            if (schemas == null && ownerDocument != null) {
                schemas = ownerDocument.Schemas; 
            } 

            if (schemas == null || schemas.Count == 0) { 
                throw new InvalidOperationException(Res.GetString(Res.XmlDocument_NoSchemaInfo));
            }

            DocumentSchemaValidator validator = new DocumentSchemaValidator(ownerDocument, schemas, validationEventHandler); 
            validator.PsviAugmentation = false;
            return validator.Validate(source); 
        } 

        private static XmlNode OwnerNode(XmlNode node) { 
            XmlNode parent = node.ParentNode;
            if (parent != null) {
                return parent;
            } 
            XmlAttribute attribute = node as XmlAttribute;
            if (attribute != null) { 
                return attribute.OwnerElement; 
            }
            return null; 
        }

        private static int GetDepth(XmlNode node) {
            int depth = 0; 
            XmlNode owner = OwnerNode(node);
            while (owner != null) { 
                depth++; 
                owner = OwnerNode(owner);
            } 
            return depth;
        }

        //Assuming that node1 and node2 are in the same level; Except when they are namespace nodes, they should have the same parent node 
        //the returned value is node2's position corresponding to node1
        private XmlNodeOrder Compare( XmlNode node1, XmlNode node2 ) { 
            Debug.Assert( node1 != null ); 
            Debug.Assert( node2 != null );
            Debug.Assert( node1 != node2, "Should be handled by ComparePosition()" ); 
            //Attribute nodes come before other children nodes except namespace nodes
            Debug.Assert( OwnerNode(node1) == OwnerNode(node2) );
            if (node1.XPNodeType == XPathNodeType.Attribute) {
                if (node2.XPNodeType == XPathNodeType.Attribute) { 
                    XmlElement element = ((XmlAttribute)node1).OwnerElement;
                    if (element.HasAttributes) { 
                        XmlAttributeCollection attributes = element.Attributes; 
                        for (int i = 0; i < attributes.Count; i++) {
                            XmlAttribute attribute = attributes[i]; 
                            if (attribute == node1) {
                                return XmlNodeOrder.Before;
                            }
                            else if (attribute == node2) { 
                                return XmlNodeOrder.After;
                            } 
                        } 
                    }
                    return XmlNodeOrder.Unknown; 
                }
                else {
                    return XmlNodeOrder.Before;
                } 
            }
            if (node2.XPNodeType == XPathNodeType.Attribute) { 
                return XmlNodeOrder.After; 
            }
 
            //neither of the node is Namespace node or Attribute node
            XmlNode nextNode = node1.NextSibling;
            while ( nextNode != null && nextNode != node2 )
                nextNode = nextNode.NextSibling; 
            if ( nextNode == null )
                //didn't meet node2 in the path to the end, thus it has to be in the front of node1 
                return XmlNodeOrder.After; 
            else
                //met node2 in the path to the end, so node1 is at front 
                return XmlNodeOrder.Before;
        }

        public override XmlNodeOrder ComparePosition(XPathNavigator other) { 
            DocumentXPathNavigator that = other as DocumentXPathNavigator;
            if (that == null) { 
                return XmlNodeOrder.Unknown; 
            }
 
            this.CalibrateText();
            that.CalibrateText();

            if (this.source == that.source 
                && this.namespaceParent == that.namespaceParent) {
                return XmlNodeOrder.Same; 
            } 

            if (this.namespaceParent != null 
                || that.namespaceParent != null) {
                return base.ComparePosition(other);
            }
 
            XmlNode node1 = this.source;
            XmlNode node2 = that.source; 
 
            XmlNode parent1 = OwnerNode(node1);
            XmlNode parent2 = OwnerNode(node2); 
            if (parent1 == parent2) {
                if (parent1 == null) {
                    return XmlNodeOrder.Unknown;
                } 
                else {
                    Debug.Assert(node1 != node2); 
                    return Compare(node1, node2); 
                }
            } 

            int depth1 = GetDepth(node1);
            int depth2 = GetDepth(node2);
            if (depth2 > depth1) { 
                while (node2 != null
                       && depth2 > depth1) { 
                    node2 = OwnerNode(node2); 
                    depth2--;
                } 
                if (node1 == node2) {
                    return XmlNodeOrder.Before;
                }
                parent2 = OwnerNode(node2); 
            }
            else if (depth1 > depth2) { 
                while (node1 != null 
                       && depth1 > depth2) {
                    node1 = OwnerNode(node1); 
                    depth1--;
                }
                if (node1 == node2) {
                    return XmlNodeOrder.After; 
                }
                parent1 = OwnerNode(node1); 
            } 

            while (parent1 != null 
                   && parent2 != null) {
                if (parent1 == parent2) {
                    Debug.Assert(node1 != node2);
                    return Compare(node1, node2); 
                }
                node1 = parent1; 
                node2 = parent2; 
                parent1 = OwnerNode(node1);
                parent2 = OwnerNode(node2); 
            }
            return XmlNodeOrder.Unknown;
        }
 
        //the function just for XPathNodeList to enumerate current Node.
        XmlNode IHasXmlNode.GetNode() { return source; } 
 
        public override XPathNodeIterator SelectDescendants( string localName, string namespaceURI, bool matchSelf ) {
            string nsAtom = document.NameTable.Get( namespaceURI ); 
            if ( nsAtom == null || this.source.NodeType == XmlNodeType.Attribute )
                return new DocumentXPathNodeIterator_Empty( this );

            Debug.Assert( this.NodeType != XPathNodeType.Attribute && this.NodeType != XPathNodeType.Namespace && this.NodeType != XPathNodeType.All ); 

            string localNameAtom = document.NameTable.Get( localName ); 
            if ( localNameAtom == null ) 
                return new DocumentXPathNodeIterator_Empty( this );
 
            if ( localNameAtom.Length == 0 ) {
                if ( matchSelf )
                    return new DocumentXPathNodeIterator_ElemChildren_AndSelf_NoLocalName( this, nsAtom );
                return new DocumentXPathNodeIterator_ElemChildren_NoLocalName( this, nsAtom ); 
            }
 
            if ( matchSelf ) 
                return new DocumentXPathNodeIterator_ElemChildren_AndSelf( this, localNameAtom, nsAtom );
            return new DocumentXPathNodeIterator_ElemChildren( this, localNameAtom, nsAtom ); 
        }

        public override XPathNodeIterator SelectDescendants( XPathNodeType nt, bool includeSelf ) {
            if ( nt == XPathNodeType.Element ) { 
                XmlNodeType curNT = source.NodeType;
                if ( curNT != XmlNodeType.Document && curNT != XmlNodeType.Element ) { 
                    //only Document, Entity, Element node can have Element node as children ( descendant ) 
                    //entity nodes should be invisible to XPath data model
                    return new DocumentXPathNodeIterator_Empty( this ); 
                }
                if ( includeSelf )
                    return new DocumentXPathNodeIterator_AllElemChildren_AndSelf( this );
                return new DocumentXPathNodeIterator_AllElemChildren( this ); 
            }
            return base.SelectDescendants( nt, includeSelf ); 
        } 

        public override bool CanEdit { 
            get {
                return true;
            }
        } 

        public override XmlWriter PrependChild() { 
            switch (source.NodeType) { 
                case XmlNodeType.Element:
                case XmlNodeType.Document: 
                case XmlNodeType.DocumentFragment:
                    break;
                default:
                    throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition)); 
            }
 
            DocumentXmlWriter writer = new DocumentXmlWriter(DocumentXmlWriterType.PrependChild, source, document); 
            writer.NamespaceManager = GetNamespaceManager(source, document);
            return new XmlWellFormedWriter(writer, writer.Settings); 
        }

        public override XmlWriter AppendChild() {
            switch (source.NodeType) { 
                case XmlNodeType.Element:
                case XmlNodeType.Document: 
                case XmlNodeType.DocumentFragment: 
                    break;
                default: 
                    throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition));
            }

            DocumentXmlWriter writer = new DocumentXmlWriter(DocumentXmlWriterType.AppendChild, source, document); 
            writer.NamespaceManager = GetNamespaceManager(source, document);
            return new XmlWellFormedWriter(writer, writer.Settings); 
        } 

        public override XmlWriter InsertAfter() { 
            XmlNode node = source;

            switch (node.NodeType) {
                case XmlNodeType.Attribute: 
                case XmlNodeType.Document:
                case XmlNodeType.DocumentFragment: 
                    throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition)); 
                case XmlNodeType.Text:
                case XmlNodeType.CDATA: 
                case XmlNodeType.SignificantWhitespace:
                case XmlNodeType.Whitespace:
                    node = TextEnd(node);
                    break; 
                default:
                    break; 
            } 

            DocumentXmlWriter writer = new DocumentXmlWriter(DocumentXmlWriterType.InsertSiblingAfter, node, document); 
            writer.NamespaceManager = GetNamespaceManager(node.ParentNode, document);
            return new XmlWellFormedWriter(writer, writer.Settings);
        }
 
        public override XmlWriter InsertBefore() {
            switch (source.NodeType) { 
                case XmlNodeType.Attribute: 
                case XmlNodeType.Document:
                case XmlNodeType.DocumentFragment: 
                    throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition));
                case XmlNodeType.Text:
                case XmlNodeType.CDATA:
                case XmlNodeType.SignificantWhitespace: 
                case XmlNodeType.Whitespace:
                    CalibrateText(); 
 
                    break;
                default: 
                    break;
            }

            DocumentXmlWriter writer = new DocumentXmlWriter(DocumentXmlWriterType.InsertSiblingBefore, source, document); 
            writer.NamespaceManager = GetNamespaceManager(source.ParentNode, document);
            return new XmlWellFormedWriter(writer, writer.Settings); 
        } 

        public override XmlWriter CreateAttributes() { 
            if (source.NodeType != XmlNodeType.Element) {
                throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition));
            }
 
            DocumentXmlWriter writer = new DocumentXmlWriter(DocumentXmlWriterType.AppendAttribute, source, document);
            writer.NamespaceManager = GetNamespaceManager(source, document); 
            return new XmlWellFormedWriter(writer, writer.Settings); 
        }
 
        public override XmlWriter ReplaceRange(XPathNavigator lastSiblingToReplace) {
            DocumentXPathNavigator that = lastSiblingToReplace as DocumentXPathNavigator;
            if (that == null) {
                if (lastSiblingToReplace == null) { 
                    throw new ArgumentNullException("lastSiblingToReplace");
                } 
                else { 
                    throw new NotSupportedException();
                } 
            }

            this.CalibrateText();
            that.CalibrateText(); 

            XmlNode node = this.source; 
            XmlNode end = that.source; 

            if (node == end) { 
                switch (node.NodeType) {
                    case XmlNodeType.Attribute:
                    case XmlNodeType.Document:
                    case XmlNodeType.DocumentFragment: 
                        throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition));
                    case XmlNodeType.Text: 
                    case XmlNodeType.CDATA: 
                    case XmlNodeType.SignificantWhitespace:
                    case XmlNodeType.Whitespace: 
                        end = that.TextEnd(end);
                        break;
                    default:
                        break; 
                }
            } 
            else { 
                if (end.IsText) {
                    end = that.TextEnd(end); 
                }
                if (!IsFollowingSibling(node, end)) {
                    throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition));
                } 
            }
 
            DocumentXmlWriter writer = new DocumentXmlWriter(DocumentXmlWriterType.ReplaceToFollowingSibling, node, document); 
            writer.NamespaceManager = GetNamespaceManager(node.ParentNode, document);
            writer.Navigator = this; 
            writer.EndNode = end;
            return new XmlWellFormedWriter(writer, writer.Settings);
        }
 
        public override void DeleteRange(XPathNavigator lastSiblingToDelete) {
            DocumentXPathNavigator that = lastSiblingToDelete as DocumentXPathNavigator; 
            if (that == null) { 
                if (lastSiblingToDelete == null) {
                    throw new ArgumentNullException("lastSiblingToDelete"); 
                }
                else {
                    throw new NotSupportedException();
                } 
            }
 
            this.CalibrateText(); 
            that.CalibrateText();
 
            XmlNode node = this.source;
            XmlNode end = that.source;

            if (node == end) { 
                switch (node.NodeType) {
                    case XmlNodeType.Attribute: 
                        XmlAttribute attribute = (XmlAttribute)node; 
                        if (attribute.IsNamespace) {
                            goto default; 
                        }
                        XmlNode parent = OwnerNode(attribute);
                        DeleteAttribute(attribute, attributeIndex);
                        if (parent != null) { 
                            ResetPosition(parent);
                        } 
                        break; 
                    case XmlNodeType.Text:
                    case XmlNodeType.CDATA: 
                    case XmlNodeType.SignificantWhitespace:
                    case XmlNodeType.Whitespace:
                        end = that.TextEnd(end);
                        goto case XmlNodeType.Element; 
                    case XmlNodeType.Element:
                    case XmlNodeType.ProcessingInstruction: 
                    case XmlNodeType.Comment: 
                        parent = OwnerNode(node);
                        DeleteToFollowingSibling(node, end); 
                        if (parent != null) {
                            ResetPosition(parent);
                        }
                        break; 
                    default:
                        throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition)); 
                } 
            }
            else { 
                if (end.IsText) {
                    end = that.TextEnd(end);
                }
                if (!IsFollowingSibling(node, end)) { 
                    throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition));
                } 
                XmlNode parent = OwnerNode(node); 
                DeleteToFollowingSibling(node, end);
                if (parent != null) { 
                    ResetPosition(parent);
                }
            }
        } 

        public override void DeleteSelf() { 
            XmlNode node = source; 
            XmlNode end = node;
 
            switch (node.NodeType) {
                case XmlNodeType.Attribute:
                    XmlAttribute attribute = (XmlAttribute)node;
                    if (attribute.IsNamespace) { 
                        goto default;
                    } 
                    XmlNode parent = OwnerNode(attribute); 
                    DeleteAttribute(attribute, attributeIndex);
                    if (parent != null) { 
                        ResetPosition(parent);
                    }
                    break;
                case XmlNodeType.Text: 
                case XmlNodeType.CDATA:
                case XmlNodeType.SignificantWhitespace: 
                case XmlNodeType.Whitespace: 
                    CalibrateText();
 
                    node = source;
                    end = TextEnd(node);
                    goto case XmlNodeType.Element;
                case XmlNodeType.Element: 
                case XmlNodeType.ProcessingInstruction:
                case XmlNodeType.Comment: 
                    parent = OwnerNode(node); 
                    DeleteToFollowingSibling(node, end);
                    if (parent != null) { 
                        ResetPosition(parent);
                    }
                    break;
                default: 
                    throw new InvalidOperationException(Res.GetString(Res.Xpn_BadPosition));
            } 
        } 

        private static void DeleteAttribute(XmlAttribute attribute, int index) { 
            XmlAttributeCollection attributes;

            if (!CheckAttributePosition(attribute, out attributes, index)
                && !ResetAttributePosition(attribute, attributes, out index)) { 
                throw new InvalidOperationException(Res.GetString(Res.Xpn_MissingParent));
            } 
            if (attribute.IsReadOnly) { 
                throw new InvalidOperationException(Res.GetString(Res.Xdom_Node_Modify_ReadOnly));
            } 
            attributes.RemoveAt(index);
        }

        internal static void DeleteToFollowingSibling(XmlNode node, XmlNode end) { 
            XmlNode parent = node.ParentNode;
 
            if (parent == null) { 
                throw new InvalidOperationException(Res.GetString(Res.Xpn_MissingParent));
            } 
            if (node.IsReadOnly
                || end.IsReadOnly) {
                throw new InvalidOperationException(Res.GetString(Res.Xdom_Node_Modify_ReadOnly));
            } 
            while (node != end) {
                XmlNode temp = node; 
                node = node.NextSibling; 
                parent.RemoveChild(temp);
            } 
            parent.RemoveChild(node);
        }

        private static XmlNamespaceManager GetNamespaceManager(XmlNode node, XmlDocument document) { 
            XmlNamespaceManager namespaceManager = new XmlNamespaceManager(document.NameTable);
            List elements = new List(); 
 
            while (node != null) {
                XmlElement element = node as XmlElement; 
                if (element != null
                    && element.HasAttributes) {
                    elements.Add(element);
                } 
                node = node.ParentNode;
            } 
            for (int i = elements.Count - 1; i >= 0; i--) { 
                namespaceManager.PushScope();
                XmlAttributeCollection attributes = elements[i].Attributes; 
                for (int j = 0; j < attributes.Count; j++) {
                    XmlAttribute attribute = attributes[j];
                    if (attribute.IsNamespace) {
                        string prefix = attribute.Prefix.Length == 0 ? string.Empty : attribute.LocalName; 
                        namespaceManager.AddNamespace(prefix, attribute.Value);
                    } 
                } 
            }
            return namespaceManager; 
        }

        internal void ResetPosition(XmlNode node) {
            Debug.Assert(node != null, "Undefined navigator position"); 
            Debug.Assert(node == document || node.OwnerDocument == document, "Navigator switched documents");
            source = node; 
            XmlAttribute attribute = node as XmlAttribute; 
            if (attribute != null) {
                XmlElement element = attribute.OwnerElement; 
                if (element != null) {
                    ResetAttributePosition(attribute, element.Attributes, out attributeIndex);
                    if (attribute.IsNamespace) {
                        namespaceParent = element; 
                    }
                } 
            } 
        }
 
        private static bool ResetAttributePosition(XmlAttribute attribute, XmlAttributeCollection attributes, out int index) {
            if (attributes != null) {
                for (int i = 0; i < attributes.Count; i++) {
                    if (attribute == attributes[i]) { 
                        index = i;
                        return true; 
                    } 
                }
            } 
            index = 0;
            return false;
        }
 
        private static bool CheckAttributePosition(XmlAttribute attribute, out XmlAttributeCollection attributes, int index) {
            XmlElement element = attribute.OwnerElement; 
            if (element != null) { 
                attributes = element.Attributes;
                if (index >= 0 
                    && index < attributes.Count
                    && attribute == attributes[index]) {
                    return true;
                } 
            }
            else { 
                attributes = null; 
            }
            return false; 
        }

        private void CalibrateText() {
            XmlNode text = PreviousText(source); 
            while (text != null) {
                ResetPosition(text); 
                text = PreviousText(text); 
            }
        } 

        private XmlNode ParentNode(XmlNode node) {
            XmlNode parent = node.ParentNode;
 
            if (!document.HasEntityReferences) {
                return parent; 
            } 
            return ParentNodeTail(parent);
        } 

        private XmlNode ParentNodeTail(XmlNode parent) {
            while (parent != null
                   && parent.NodeType == XmlNodeType.EntityReference) { 
                parent = parent.ParentNode;
            } 
            return parent; 
        }
 
        private XmlNode FirstChild(XmlNode node) {
            XmlNode child = node.FirstChild;

            if (!document.HasEntityReferences) { 
                return child;
            } 
            return FirstChildTail(child); 
        }
 
        private XmlNode FirstChildTail(XmlNode child) {
            while (child != null
                   && child.NodeType == XmlNodeType.EntityReference) {
                child = child.FirstChild; 
            }
            return child; 
        } 

        private XmlNode NextSibling(XmlNode node) { 
            XmlNode sibling = node.NextSibling;

            if (!document.HasEntityReferences) {
                return sibling; 
            }
            return NextSiblingTail(node, sibling); 
        } 

        private XmlNode NextSiblingTail(XmlNode node, XmlNode sibling) { 
            while (sibling == null) {
                node = node.ParentNode;
                if (node == null
                    || node.NodeType != XmlNodeType.EntityReference) { 
                    return null;
                } 
                sibling = node.NextSibling; 
            }
            while (sibling != null 
                   && sibling.NodeType == XmlNodeType.EntityReference) {
                sibling = sibling.FirstChild;
            }
            return sibling; 
        }
 
        private XmlNode PreviousSibling(XmlNode node) { 
            XmlNode sibling = node.PreviousSibling;
 
            if (!document.HasEntityReferences) {
                return sibling;
            }
            return PreviousSiblingTail(node, sibling); 
        }
 
        private XmlNode PreviousSiblingTail(XmlNode node, XmlNode sibling) { 
            while (sibling == null) {
                node = node.ParentNode; 
                if (node == null
                    || node.NodeType != XmlNodeType.EntityReference) {
                    return null;
                } 
                sibling = node.PreviousSibling;
            } 
            while (sibling != null 
                   && sibling.NodeType == XmlNodeType.EntityReference) {
                sibling = sibling.LastChild; 
            }
            return sibling;
        }
 
        private XmlNode PreviousText(XmlNode node) {
            XmlNode text = node.PreviousText; 
 
            if (!document.HasEntityReferences) {
                return text; 
            }
            return PreviousTextTail(node, text);
        }
 
        private XmlNode PreviousTextTail(XmlNode node, XmlNode text) {
            if (text != null) { 
                return text; 
            }
            if (!node.IsText) { 
                return null;
            }
            XmlNode sibling = node.PreviousSibling;
            while (sibling == null) { 
                node = node.ParentNode;
                if (node == null 
                    || node.NodeType != XmlNodeType.EntityReference) { 
                    return null;
                } 
                sibling = node.PreviousSibling;
            }
            while (sibling != null) {
                switch (sibling.NodeType) { 
                    case XmlNodeType.EntityReference:
                        sibling = sibling.LastChild; 
                        break; 
                    case XmlNodeType.Text:
                    case XmlNodeType.CDATA: 
                    case XmlNodeType.Whitespace:
                    case XmlNodeType.SignificantWhitespace:
                        return sibling;
                    default: 
                        return null;
                } 
            } 
            return null;
        } 

        internal static bool IsFollowingSibling(XmlNode left, XmlNode right) {
            for (;;) {
                left = left.NextSibling; 
                if (left == null) {
                    break; 
                } 
                if (left == right) {
                    return true; 
                }
            }
            return false;
        } 

        private static bool IsDescendant(XmlNode top, XmlNode bottom) { 
            for (;;) { 
                XmlNode parent = bottom.ParentNode;
                if (parent == null) { 
                    XmlAttribute attribute = bottom as XmlAttribute;
                    if (attribute == null) {
                        break;
                    } 
                    parent = attribute.OwnerElement;
                    if (parent == null) { 
                        break; 
                    }
                } 
                bottom = parent;
                if (top == bottom) {
                    return true;
                } 
            }
            return false; 
        } 

        private static bool IsValidChild(XmlNode parent, XmlNode child) { 
            switch (parent.NodeType) {
                case XmlNodeType.Element:
                    return true;
                case XmlNodeType.DocumentFragment: 
                    switch (child.NodeType) {
                        case XmlNodeType.Element: 
                        case XmlNodeType.Text: 
                        case XmlNodeType.CDATA:
                        case XmlNodeType.ProcessingInstruction: 
                        case XmlNodeType.Comment:
                        case XmlNodeType.Whitespace:
                        case XmlNodeType.SignificantWhitespace:
                            return true; 
                    }
                    break; 
                case XmlNodeType.Document: 
                    switch (child.NodeType) {
                        case XmlNodeType.Element: 
                        case XmlNodeType.ProcessingInstruction:
                        case XmlNodeType.Comment:
                            return true;
                    } 
                    break;
                default: 
                    break; 
            }
            return false; 
        }

        private XmlNode TextStart(XmlNode node) {
            XmlNode start; 

            do { 
                start = node; 
                node = PreviousSibling(node);
            } 
            while (node != null
                   && node.IsText);
            return start;
        } 

        private XmlNode TextEnd(XmlNode node) { 
            XmlNode end; 

            do { 
                end = node;
                node = NextSibling(node);
            }
            while (node != null 
                   && node.IsText);
            return end; 
        } 
    }
 
    // An iterator that matches no nodes
    internal sealed class DocumentXPathNodeIterator_Empty : XPathNodeIterator {
        private XPathNavigator nav;
 
        internal DocumentXPathNodeIterator_Empty( DocumentXPathNavigator nav )               { this.nav = nav.Clone(); }
        internal DocumentXPathNodeIterator_Empty( DocumentXPathNodeIterator_Empty other )    { this.nav = other.nav.Clone(); } 
        public override XPathNodeIterator Clone()   { return new DocumentXPathNodeIterator_Empty( this ); } 
        public override bool MoveNext()         { return false; }
        public override XPathNavigator Current  { get { return nav; } } 
        public override int CurrentPosition     { get { return 0; } }
        public override int Count                { get { return 0; } }
    }
 
    // An iterator that can match any child elements that match the Match condition (overrided in the derived class)
    internal abstract class DocumentXPathNodeIterator_ElemDescendants : XPathNodeIterator { 
        private DocumentXPathNavigator nav; 
        private int level;
        private int position; 

        internal DocumentXPathNodeIterator_ElemDescendants( DocumentXPathNavigator nav ) {
            this.nav      = (DocumentXPathNavigator)(nav.Clone());
            this.level    = 0; 
            this.position = 0;
        } 
        internal DocumentXPathNodeIterator_ElemDescendants( DocumentXPathNodeIterator_ElemDescendants other ) { 
            this.nav      = (DocumentXPathNavigator)(other.nav.Clone());
            this.level    = other.level; 
            this.position = other.position;
        }

        protected abstract bool Match( XmlNode node ); 

        public override XPathNavigator Current { 
            get { return nav; } 
        }
 
        public override int CurrentPosition {
            get { return position; }
        }
 
        protected void SetPosition( int pos ) {
            position = pos; 
        } 

        public override bool MoveNext() { 
            for (;;) {
                if (nav.MoveToFirstChild()) {
                    level++;
                } 
                else {
                    if (level == 0) { 
                        return false; 
                    }
                    while (!nav.MoveToNext()) { 
                        level--;
                        if (level == 0) {
                            return false;
                        } 
                        if (!nav.MoveToParent()) {
                            return false; 
                        } 
                    }
                } 
                XmlNode node = (XmlNode)nav.UnderlyingObject;
                if (node.NodeType == XmlNodeType.Element && Match(node)) {
                    position++;
                    return true; 
                }
            } 
        } 
    }
 
    // Iterate over all element children irrespective of the localName and namespace
    internal class DocumentXPathNodeIterator_AllElemChildren : DocumentXPathNodeIterator_ElemDescendants {
        internal DocumentXPathNodeIterator_AllElemChildren( DocumentXPathNavigator nav ) : base( nav ) {
            Debug.Assert( ((XmlNode)nav.UnderlyingObject).NodeType != XmlNodeType.Attribute ); 
        }
        internal DocumentXPathNodeIterator_AllElemChildren( DocumentXPathNodeIterator_AllElemChildren other ) : base( other ) { 
        } 

        public override XPathNodeIterator Clone() { 
            return new DocumentXPathNodeIterator_AllElemChildren( this );
        }

        protected override bool Match( XmlNode node ) { 
            Debug.Assert( node != null );
            return ( node.NodeType == XmlNodeType.Element ); 
        } 
    }
    // Iterate over all element children irrespective of the localName and namespace, include the self node when testing for localName/ns 
    internal sealed class DocumentXPathNodeIterator_AllElemChildren_AndSelf :  DocumentXPathNodeIterator_AllElemChildren {
        internal DocumentXPathNodeIterator_AllElemChildren_AndSelf( DocumentXPathNavigator nav ) : base( nav ) {
        }
        internal DocumentXPathNodeIterator_AllElemChildren_AndSelf( DocumentXPathNodeIterator_AllElemChildren_AndSelf other ) : base( other ) { 
        }
 
        public override XPathNodeIterator Clone() { 
            return new DocumentXPathNodeIterator_AllElemChildren_AndSelf( this );
        } 

        public override bool MoveNext() {
            if( CurrentPosition == 0 ) {
                DocumentXPathNavigator nav = (DocumentXPathNavigator)this.Current; 
                XmlNode node = (XmlNode)nav.UnderlyingObject;
                if ( node.NodeType == XmlNodeType.Element && Match( node ) ) { 
                    SetPosition( 1 ); 
                    return true;
                } 
            }
            return base.MoveNext();
        }
    } 
    // Iterate over all element children that have a given namespace but irrespective of the localName
    internal class DocumentXPathNodeIterator_ElemChildren_NoLocalName : DocumentXPathNodeIterator_ElemDescendants { 
        private string nsAtom; 

        internal DocumentXPathNodeIterator_ElemChildren_NoLocalName( DocumentXPathNavigator nav, string nsAtom ) : base( nav ) { 
            Debug.Assert( ((XmlNode)nav.UnderlyingObject).NodeType != XmlNodeType.Attribute );
            Debug.Assert( Ref.Equal(nav.NameTable.Get( nsAtom ), nsAtom) );
            this.nsAtom = nsAtom;
        } 
        internal DocumentXPathNodeIterator_ElemChildren_NoLocalName( DocumentXPathNodeIterator_ElemChildren_NoLocalName other ) : base( other ) {
            this.nsAtom = other.nsAtom; 
        } 
        public override XPathNodeIterator Clone() {
            return new DocumentXPathNodeIterator_ElemChildren_NoLocalName( this ); 
        }

        protected override bool Match( XmlNode node ) {
            Debug.Assert( node != null ); 
            Debug.Assert( node.NodeType == XmlNodeType.Element );
            return Ref.Equal(node.NamespaceURI, nsAtom); 
        } 
    }
    // Iterate over all element children that have a given namespace but irrespective of the localName, include self node when checking for ns 
    internal sealed class DocumentXPathNodeIterator_ElemChildren_AndSelf_NoLocalName :  DocumentXPathNodeIterator_ElemChildren_NoLocalName {

        internal DocumentXPathNodeIterator_ElemChildren_AndSelf_NoLocalName( DocumentXPathNavigator nav, string nsAtom ) : base( nav, nsAtom ) {
        } 
        internal DocumentXPathNodeIterator_ElemChildren_AndSelf_NoLocalName( DocumentXPathNodeIterator_ElemChildren_AndSelf_NoLocalName other ) : base( other ) {
        } 
 
        public override XPathNodeIterator Clone() {
            return new DocumentXPathNodeIterator_ElemChildren_AndSelf_NoLocalName( this ); 
        }

        public override bool MoveNext() {
            if( CurrentPosition == 0 ) { 
                DocumentXPathNavigator nav = (DocumentXPathNavigator)this.Current;
                XmlNode node = (XmlNode)nav.UnderlyingObject; 
                if ( node.NodeType == XmlNodeType.Element && Match( node ) ) { 
                    SetPosition( 1 );
                    return true; 
                }
            }
            return base.MoveNext();
        } 
    }
    // Iterate over all element children that have a given name and namespace 
    internal class DocumentXPathNodeIterator_ElemChildren : DocumentXPathNodeIterator_ElemDescendants { 
        protected string localNameAtom;
        protected string nsAtom; 

        internal DocumentXPathNodeIterator_ElemChildren( DocumentXPathNavigator nav, string localNameAtom, string nsAtom ) : base( nav ) {
            Debug.Assert( ((XmlNode)nav.UnderlyingObject).NodeType != XmlNodeType.Attribute );
            Debug.Assert( Ref.Equal(nav.NameTable.Get( localNameAtom ), localNameAtom) ); 
            Debug.Assert( Ref.Equal(nav.NameTable.Get( nsAtom ), nsAtom) );
            Debug.Assert( localNameAtom.Length > 0 );   // Use DocumentXPathNodeIterator_ElemChildren_NoLocalName class for special magic value of localNameAtom 
 
            this.localNameAtom = localNameAtom;
            this.nsAtom        = nsAtom; 
        }

        internal DocumentXPathNodeIterator_ElemChildren( DocumentXPathNodeIterator_ElemChildren other ) : base( other ) {
            this.localNameAtom = other.localNameAtom; 
            this.nsAtom        = other.nsAtom;
        } 
 
        public override XPathNodeIterator Clone() {
            return new DocumentXPathNodeIterator_ElemChildren( this ); 
        }

        protected override bool Match( XmlNode node ) {
            Debug.Assert( node != null ); 
            Debug.Assert( node.NodeType == XmlNodeType.Element );
            return Ref.Equal(node.LocalName, localNameAtom) && Ref.Equal(node.NamespaceURI, nsAtom); 
        } 
    }
    // Iterate over all elem children and itself and check for the given localName (including the magic value "") and namespace 
    internal sealed class DocumentXPathNodeIterator_ElemChildren_AndSelf : DocumentXPathNodeIterator_ElemChildren {

        internal DocumentXPathNodeIterator_ElemChildren_AndSelf( DocumentXPathNavigator nav, string localNameAtom, string nsAtom )
            : base( nav, localNameAtom, nsAtom ) { 
            Debug.Assert( localNameAtom.Length > 0 );   // Use DocumentXPathNodeIterator_ElemChildren_AndSelf_NoLocalName if localName == String.Empty
        } 
        internal DocumentXPathNodeIterator_ElemChildren_AndSelf( DocumentXPathNodeIterator_ElemChildren_AndSelf other ) : base( other ) { 
        }
 
        public override XPathNodeIterator Clone() {
            return new DocumentXPathNodeIterator_ElemChildren_AndSelf( this );
        }
 
        public override bool MoveNext() {
            if( CurrentPosition == 0 ) { 
                DocumentXPathNavigator nav = (DocumentXPathNavigator)this.Current; 
                XmlNode node = (XmlNode)nav.UnderlyingObject;
                if ( node.NodeType == XmlNodeType.Element && Match( node ) ) { 
                    SetPosition( 1 );
                    return true;
                }
            } 
            return base.MoveNext();
        } 
    } 
}

// 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