1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System.Collections.Generic; 6 using System.Xml.XPath; 7 using StackNav = MS.Internal.Xml.XPath.ClonableStack<System.Xml.XPath.XPathNavigator>; 8 9 namespace MS.Internal.Xml.XPath 10 { 11 internal sealed class FollSiblingQuery : BaseAxisQuery 12 { 13 private StackNav _elementStk; 14 private List<XPathNavigator> _parentStk; 15 private XPathNavigator _nextInput; 16 FollSiblingQuery(Query qyInput, string name, string prefix, XPathNodeType type)17 public FollSiblingQuery(Query qyInput, string name, string prefix, XPathNodeType type) : base(qyInput, name, prefix, type) 18 { 19 _elementStk = new StackNav(); 20 _parentStk = new List<XPathNavigator>(); 21 } FollSiblingQuery(FollSiblingQuery other)22 private FollSiblingQuery(FollSiblingQuery other) : base(other) 23 { 24 _elementStk = other._elementStk.Clone(); 25 _parentStk = new List<XPathNavigator>(other._parentStk); 26 _nextInput = Clone(other._nextInput); 27 } 28 Reset()29 public override void Reset() 30 { 31 _elementStk.Clear(); 32 _parentStk.Clear(); 33 _nextInput = null; 34 base.Reset(); 35 } 36 Visited(XPathNavigator nav)37 private bool Visited(XPathNavigator nav) 38 { 39 XPathNavigator parent = nav.Clone(); 40 parent.MoveToParent(); 41 for (int i = 0; i < _parentStk.Count; i++) 42 { 43 if (parent.IsSamePosition(_parentStk[i])) 44 { 45 return true; 46 } 47 } 48 _parentStk.Add(parent); 49 return false; 50 } 51 FetchInput()52 private XPathNavigator FetchInput() 53 { 54 XPathNavigator input; 55 do 56 { 57 input = qyInput.Advance(); 58 if (input == null) 59 { 60 return null; 61 } 62 } while (Visited(input)); 63 return input.Clone(); 64 } 65 Advance()66 public override XPathNavigator Advance() 67 { 68 while (true) 69 { 70 if (currentNode == null) 71 { 72 if (_nextInput == null) 73 { 74 _nextInput = FetchInput(); // This can happen at the beginning and at the end 75 } 76 if (_elementStk.Count == 0) 77 { 78 if (_nextInput == null) 79 { 80 return null; 81 } 82 currentNode = _nextInput; 83 _nextInput = FetchInput(); 84 } 85 else 86 { 87 currentNode = _elementStk.Pop(); 88 } 89 } 90 91 while (currentNode.IsDescendant(_nextInput)) 92 { 93 _elementStk.Push(currentNode); 94 currentNode = _nextInput; 95 _nextInput = qyInput.Advance(); 96 if (_nextInput != null) 97 { 98 _nextInput = _nextInput.Clone(); 99 } 100 } 101 102 while (currentNode.MoveToNext()) 103 { 104 if (matches(currentNode)) 105 { 106 position++; 107 return currentNode; 108 } 109 } 110 currentNode = null; 111 } 112 } // Advance 113 Clone()114 public override XPathNodeIterator Clone() { return new FollSiblingQuery(this); } 115 } 116 } 117