File: System\Xml\Cache\XPathDocumentIterator.cs
Web Access
Project: src\src\libraries\System.Private.Xml\src\System.Private.Xml.csproj (System.Private.Xml)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Xml.XPath;
 
namespace MS.Internal.Xml.Cache
{
    /// <summary>
    /// Base internal class of all XPathDocument XPathNodeIterator implementations.
    /// </summary>
    internal abstract class XPathDocumentBaseIterator : XPathNodeIterator
    {
        protected XPathDocumentNavigator ctxt;
        protected int pos;
 
        /// <summary>
        /// Create a new iterator that is initially positioned on the "ctxt" node.
        /// </summary>
        protected XPathDocumentBaseIterator(XPathDocumentNavigator ctxt)
        {
            this.ctxt = new XPathDocumentNavigator(ctxt);
        }
 
        /// <summary>
        /// Create a new iterator that is a copy of "iter".
        /// </summary>
        protected XPathDocumentBaseIterator(XPathDocumentBaseIterator iter)
        {
            this.ctxt = new XPathDocumentNavigator(iter.ctxt);
            this.pos = iter.pos;
        }
 
        /// <summary>
        /// Return the current navigator.
        /// </summary>
        public override XPathNavigator Current
        {
            get { return this.ctxt; }
        }
 
        /// <summary>
        /// Return the iterator's current position.
        /// </summary>
        public override int CurrentPosition
        {
            get { return this.pos; }
        }
    }
 
 
    /// <summary>
    /// Iterate over all element children with a particular QName.
    /// </summary>
    internal sealed class XPathDocumentElementChildIterator : XPathDocumentBaseIterator
    {
        private readonly string? _localName;
        private readonly string _namespaceUri;
 
        /// <summary>
        /// Create an iterator that ranges over all element children of "parent" having the specified QName.
        /// </summary>
        public XPathDocumentElementChildIterator(XPathDocumentNavigator parent, string name, string namespaceURI) : base(parent)
        {
            ArgumentNullException.ThrowIfNull(namespaceURI);
 
            _localName = parent.NameTable.Get(name);
            _namespaceUri = namespaceURI;
        }
 
        /// <summary>
        /// Create a new iterator that is a copy of "iter".
        /// </summary>
        public XPathDocumentElementChildIterator(XPathDocumentElementChildIterator iter) : base(iter)
        {
            _localName = iter._localName;
            _namespaceUri = iter._namespaceUri;
        }
 
        /// <summary>
        /// Create a copy of this iterator.
        /// </summary>
        public override XPathNodeIterator Clone()
        {
            return new XPathDocumentElementChildIterator(this);
        }
 
        /// <summary>
        /// Position the iterator to the next matching child.
        /// </summary>
        public override bool MoveNext()
        {
            if (this.pos == 0)
            {
                if (!this.ctxt.MoveToChild(_localName, _namespaceUri))
                    return false;
            }
            else
            {
                if (!this.ctxt.MoveToNext(_localName, _namespaceUri))
                    return false;
            }
 
            this.pos++;
            return true;
        }
    }
 
 
    /// <summary>
    /// Iterate over all content children with a particular XPathNodeType.
    /// </summary>
    internal sealed class XPathDocumentKindChildIterator : XPathDocumentBaseIterator
    {
        private readonly XPathNodeType _typ;
 
        /// <summary>
        /// Create an iterator that ranges over all content children of "parent" having the specified XPathNodeType.
        /// </summary>
        public XPathDocumentKindChildIterator(XPathDocumentNavigator parent, XPathNodeType typ) : base(parent)
        {
            _typ = typ;
        }
 
        /// <summary>
        /// Create a new iterator that is a copy of "iter".
        /// </summary>
        public XPathDocumentKindChildIterator(XPathDocumentKindChildIterator iter) : base(iter)
        {
            _typ = iter._typ;
        }
 
        /// <summary>
        /// Create a copy of this iterator.
        /// </summary>
        public override XPathNodeIterator Clone()
        {
            return new XPathDocumentKindChildIterator(this);
        }
 
        /// <summary>
        /// Position the iterator to the next descendant.
        /// </summary>
        public override bool MoveNext()
        {
            if (this.pos == 0)
            {
                if (!this.ctxt.MoveToChild(_typ))
                    return false;
            }
            else
            {
                if (!this.ctxt.MoveToNext(_typ))
                    return false;
            }
 
            this.pos++;
            return true;
        }
    }
 
 
    /// <summary>
    /// Iterate over all element descendants with a particular QName.
    /// </summary>
    internal sealed class XPathDocumentElementDescendantIterator : XPathDocumentBaseIterator
    {
        private readonly XPathDocumentNavigator? _end;
        private readonly string? _localName;
        private readonly string _namespaceUri;
        private bool _matchSelf;
 
        /// <summary>
        /// Create an iterator that ranges over all element descendants of "root" having the specified QName.
        /// </summary>
        public XPathDocumentElementDescendantIterator(XPathDocumentNavigator root, string name, string namespaceURI, bool matchSelf) : base(root)
        {
            ArgumentNullException.ThrowIfNull(namespaceURI);
 
            _localName = root.NameTable.Get(name);
            _namespaceUri = namespaceURI;
            _matchSelf = matchSelf;
 
            // Find the next non-descendant node that follows "root" in document order
            if (root.NodeType != XPathNodeType.Root)
            {
                _end = new XPathDocumentNavigator(root);
                _end.MoveToNonDescendant();
            }
        }
 
        /// <summary>
        /// Create a new iterator that is a copy of "iter".
        /// </summary>
        public XPathDocumentElementDescendantIterator(XPathDocumentElementDescendantIterator iter) : base(iter)
        {
            _end = iter._end;
            _localName = iter._localName;
            _namespaceUri = iter._namespaceUri;
            _matchSelf = iter._matchSelf;
        }
 
        /// <summary>
        /// Create a copy of this iterator.
        /// </summary>
        public override XPathNodeIterator Clone()
        {
            return new XPathDocumentElementDescendantIterator(this);
        }
 
        /// <summary>
        /// Position the iterator to the next descendant.
        /// </summary>
        public override bool MoveNext()
        {
            if (_matchSelf)
            {
                _matchSelf = false;
 
                if (this.ctxt.IsElementMatch(_localName, _namespaceUri))
                {
                    this.pos++;
                    return true;
                }
            }
 
            if (!this.ctxt.MoveToFollowing(_localName, _namespaceUri, _end))
                return false;
 
            this.pos++;
            return true;
        }
    }
 
 
    /// <summary>
    /// Iterate over all content descendants with a particular XPathNodeType.
    /// </summary>
    internal sealed class XPathDocumentKindDescendantIterator : XPathDocumentBaseIterator
    {
        private readonly XPathDocumentNavigator? _end;
        private readonly XPathNodeType _typ;
        private bool _matchSelf;
 
        /// <summary>
        /// Create an iterator that ranges over all content descendants of "root" having the specified XPathNodeType.
        /// </summary>
        public XPathDocumentKindDescendantIterator(XPathDocumentNavigator root, XPathNodeType typ, bool matchSelf) : base(root)
        {
            _typ = typ;
            _matchSelf = matchSelf;
 
            // Find the next non-descendant node that follows "root" in document order
            if (root.NodeType != XPathNodeType.Root)
            {
                _end = new XPathDocumentNavigator(root);
                _end.MoveToNonDescendant();
            }
        }
 
        /// <summary>
        /// Create a new iterator that is a copy of "iter".
        /// </summary>
        public XPathDocumentKindDescendantIterator(XPathDocumentKindDescendantIterator iter) : base(iter)
        {
            _end = iter._end;
            _typ = iter._typ;
            _matchSelf = iter._matchSelf;
        }
 
        /// <summary>
        /// Create a copy of this iterator.
        /// </summary>
        public override XPathNodeIterator Clone()
        {
            return new XPathDocumentKindDescendantIterator(this);
        }
 
        /// <summary>
        /// Position the iterator to the next descendant.
        /// </summary>
        public override bool MoveNext()
        {
            if (_matchSelf)
            {
                _matchSelf = false;
 
                if (this.ctxt.IsKindMatch(_typ))
                {
                    this.pos++;
                    return true;
                }
            }
 
            if (!this.ctxt.MoveToFollowing(_typ, _end))
                return false;
 
            this.pos++;
            return true;
        }
    }
}