File: System\Xml\DataDocumentXPathNavigator.cs
Web Access
Project: src\src\libraries\System.Data.Common\src\System.Data.Common.csproj (System.Data.Common)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Data;
using System.Diagnostics.CodeAnalysis;
using System.Xml.XPath;
 
#pragma warning disable 0618 // ignore obsolete warning about XmlDataDocument
 
namespace System.Xml
{
    [RequiresUnreferencedCode(DataSet.RequiresUnreferencedCodeMessage)]
    [RequiresDynamicCode(DataSet.RequiresDynamicCodeMessage)]
    internal sealed class DataDocumentXPathNavigator : XPathNavigator, IHasXmlNode
    {
        private readonly XPathNodePointer _curNode; //pointer to remember the current node position
        private XmlDataDocument _doc;     //pointer to remember the root -- can only be XmlDataDocument for DataDocumentXPathNavigator
        private readonly XPathNodePointer _temp;
 
        internal DataDocumentXPathNavigator(XmlDataDocument doc, XmlNode node)
        {
            _curNode = new XPathNodePointer(this, doc, node);
            _temp = new XPathNodePointer(this, doc, node);
            _doc = doc;
        }
 
        private DataDocumentXPathNavigator(DataDocumentXPathNavigator other)
        {
            _curNode = other._curNode.Clone(this);
            _temp = other._temp.Clone(this);
            _doc = other._doc;
        }
 
        public override XPathNavigator Clone() => new DataDocumentXPathNavigator(this);
 
        internal XPathNodePointer CurNode => _curNode;
        internal XmlDataDocument Document => _doc;
 
        //Convert will deal with nodeType as Attribute or Namespace nodes
        public override XPathNodeType NodeType => _curNode.NodeType;
 
        public override string LocalName => _curNode.LocalName;
 
        public override string NamespaceURI => _curNode.NamespaceURI;
 
        public override string Name => _curNode.Name;
 
        public override string Prefix => _curNode.Prefix;
 
        public override string Value
        {
            get
            {
                XPathNodeType xnt = _curNode.NodeType;
                return xnt == XPathNodeType.Element || xnt == XPathNodeType.Root ? _curNode.InnerText : _curNode.Value!;
            }
        }
 
        public override string BaseURI => _curNode.BaseURI;
 
        public override string XmlLang => _curNode.XmlLang;
 
        public override bool IsEmptyElement => _curNode.IsEmptyElement;
 
        public override XmlNameTable NameTable => _doc.NameTable;
 
        // Attributes
        public override bool HasAttributes => _curNode.AttributeCount > 0;
 
       public override string GetAttribute(string localName, string namespaceURI)
        {
            if (_curNode.NodeType != XPathNodeType.Element)
            {
                return string.Empty; //other type of nodes can't have attributes
            }
 
            _temp.MoveTo(_curNode);
            return _temp.MoveToAttribute(localName, namespaceURI) ? _temp.Value! : string.Empty;
        }
 
        public override string GetNamespace(string name) => _curNode.GetNamespace(name);
 
        public override bool MoveToNamespace(string name) =>
            _curNode.NodeType != XPathNodeType.Element ?
                false : _curNode.MoveToNamespace(name);
 
        public override bool MoveToFirstNamespace(XPathNamespaceScope namespaceScope) =>
            _curNode.NodeType != XPathNodeType.Element ?
                false : _curNode.MoveToFirstNamespace(namespaceScope);
 
        public override bool MoveToNextNamespace(XPathNamespaceScope namespaceScope) =>
            _curNode.NodeType != XPathNodeType.Namespace ?
                false : _curNode.MoveToNextNamespace(namespaceScope);
 
        public override bool MoveToAttribute(string localName, string namespaceURI) =>
            _curNode.NodeType != XPathNodeType.Element ?
                false : //other type of nodes can't have attributes
                _curNode.MoveToAttribute(localName, namespaceURI);
 
        public override bool MoveToFirstAttribute() =>
            _curNode.NodeType != XPathNodeType.Element ?
                false : //other type of nodes can't have attributes
                _curNode.MoveToNextAttribute(true);
 
        public override bool MoveToNextAttribute() =>
            _curNode.NodeType != XPathNodeType.Attribute ?
                false : _curNode.MoveToNextAttribute(false);
 
        // Tree
        public override bool MoveToNext() =>
            _curNode.NodeType == XPathNodeType.Attribute ?
                false : _curNode.MoveToNextSibling();
 
        public override bool MoveToPrevious() =>
            _curNode.NodeType == XPathNodeType.Attribute ?
                false : _curNode.MoveToPreviousSibling();
 
        public override bool MoveToFirst() =>
            _curNode.NodeType == XPathNodeType.Attribute ?
                false : _curNode.MoveToFirst();
 
        public override bool HasChildren => _curNode.HasChildren;
 
        public override bool MoveToFirstChild() => _curNode.MoveToFirstChild();
 
        public override bool MoveToParent() => _curNode.MoveToParent();
 
        public override void MoveToRoot() => _curNode.MoveToRoot();
 
        public override bool MoveTo(XPathNavigator other)
        {
            if (other != null)
            {
                DataDocumentXPathNavigator? otherDataDocXPathNav = other as DataDocumentXPathNavigator;
                if (otherDataDocXPathNav != null && _curNode.MoveTo(otherDataDocXPathNav.CurNode))
                {
                    _doc = _curNode.Document;
                    return true;
                }
            }
            return false;
        }
 
        //doesn't support MoveToId
        public override bool MoveToId(string id) => false;
 
        public override bool IsSamePosition(XPathNavigator other)
        {
            if (other != null)
            {
                DataDocumentXPathNavigator? otherDataDocXPathNav = other as DataDocumentXPathNavigator;
                if (otherDataDocXPathNav != null &&
                    _doc == otherDataDocXPathNav.Document && _curNode.IsSamePosition(otherDataDocXPathNav.CurNode))
                {
                    return true;
                }
            }
            return false;
        }
 
        //the function is only called for XPathNodeList enumerate nodes and
        // shouldn't be promoted to frequently use because it will cause foliation
        XmlNode IHasXmlNode.GetNode() => _curNode.Node!;
 
        public override XmlNodeOrder ComparePosition(XPathNavigator? other)
        {
            if (other == null)
            {
                return XmlNodeOrder.Unknown; // this is what XPathDocument does.
            }
 
            DataDocumentXPathNavigator? otherDataDocXPathNav = other as DataDocumentXPathNavigator;
 
            return otherDataDocXPathNav == null || otherDataDocXPathNav.Document != _doc ?
                XmlNodeOrder.Unknown :
                _curNode.ComparePosition(otherDataDocXPathNav.CurNode);
        }
    }
}