1 //------------------------------------------------------------------------------
2 // <copyright file="precedingquery.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
8 namespace MS.Internal.Xml.XPath {
11 using System.Xml.XPath;
12 using System.Diagnostics;
13 using System.Collections.Generic;
14 using StackNav = ClonableStack<System.Xml.XPath.XPathNavigator>;
17 // Input assumption: qyInput is in DocOrder.
18 // Preceding of a sequence of nodes will be preceding of last node in DocOrder in that sequence.
19 // Because qyInput is in DO last input is last node in DO. -- "last"
20 // If last node is attribute or namespace move last to it element.
21 // Push this last node and all its ancestors into the ancestorStk. The root node will be the top-most element on the stack.
22 // Create descendent iterator from the root. -- "workIterator"
23 // Advancing workIterator we meet all nodes from the ancestorStk in stack order. Nodes in ancestorStk do no belong to the
24 // the 'preceding' axis and must be ignored.
25 // Last node in ancestorStk is a centinel node; when we pop it from ancestorStk, we should stop iterations.
27 internal sealed class PrecedingQuery : BaseAxisQuery {
28 private XPathNodeIterator workIterator;
29 private StackNav ancestorStk;
31 public PrecedingQuery(Query qyInput, string name, string prefix, XPathNodeType typeTest) : base(qyInput, name, prefix, typeTest) {
32 ancestorStk = new StackNav();
34 private PrecedingQuery(PrecedingQuery other) : base(other) {
35 this.workIterator = Clone(other.workIterator);
36 this.ancestorStk = other.ancestorStk.Clone();
39 public override void Reset() {
45 public override XPathNavigator Advance() {
46 if (workIterator == null) {
47 XPathNavigator last; {
48 XPathNavigator input = qyInput.Advance();
55 } while ((input = qyInput.Advance()) != null);
57 if (last.NodeType == XPathNodeType.Attribute || last.NodeType == XPathNodeType.Namespace) {
63 ancestorStk.Push(last.Clone());
64 } while (last.MoveToParent());
65 // Create workIterator :
66 // last.MoveToRoot(); We are on root already
67 workIterator = last.SelectDescendants(XPathNodeType.All, true);
70 while (workIterator.MoveNext()) {
71 currentNode = workIterator.Current;
72 if (currentNode.IsSamePosition(ancestorStk.Peek())) {
74 if (ancestorStk.Count == 0) {
77 Debug.Assert(qyInput.Advance() == null, "we read all qyInput.Advance() already");
82 if (matches(currentNode)) {
87 Debug.Fail("Algorithm error: we missed the centinel node");
91 public override XPathNodeIterator Clone() { return new PrecedingQuery(this); }
92 public override QueryProps Properties { get { return base.Properties | QueryProps.Reverse; } }