//The structure of result is a Filter, variable is current node, body is the match condition. //Previous predicate build logic in XPathPatternBuilder is match from right to left, which have 2^n complexiy when have lots of position predicates. TFS #368771 //Now change the logic to: If predicates contains position/last predicates, given the current node, filter out all the nodes that match the predicates, //and then check if current node is in the result set. public QilNode BuildPredicates(QilNode nodeset, List <QilNode> predicates) { //convert predicates to boolean type List <QilNode> convertedPredicates = new List <QilNode>(predicates.Count); foreach (var predicate in predicates) { convertedPredicates.Add(XPathBuilder.PredicateToBoolean(predicate, _f, _predicateEnvironment)); } QilLoop nodeFilter = (QilLoop)nodeset; QilIterator current = nodeFilter.Variable; //If no last() and position() in predicates, use nodeFilter.Variable to fixup current //because all the predicates only based on the input variable, no matter what other predicates are. if (_predicateEnvironment.numFixupLast == 0 && _predicateEnvironment.numFixupPosition == 0) { foreach (var predicate in convertedPredicates) { nodeFilter.Body = _f.And(nodeFilter.Body, predicate); } nodeFilter.Body = _predicateEnvironment.fixupVisitor.Fixup(nodeFilter.Body, current, null); } //If any preidcate contains last() or position() node, then the current node is based on previous predicates, //for instance, a[...][2] is match second node after filter 'a[...]' instead of second 'a'. else { //filter out the siblings QilIterator parentIter = _f.For(_f.Parent(current)); QilNode sibling = _f.Content(parentIter); //generate filter based on input filter QilLoop siblingFilter = (QilLoop)nodeset.DeepClone(_f.BaseFactory); siblingFilter.Variable.Binding = sibling; siblingFilter = (QilLoop)_f.Loop(parentIter, siblingFilter); //build predicates from left to right to get all the matching nodes QilNode matchingSet = siblingFilter; foreach (var predicate in convertedPredicates) { matchingSet = XPathBuilder.BuildOnePredicate(matchingSet, predicate, /*isReverseStep*/ false, _f, _predicateEnvironment.fixupVisitor, ref _predicateEnvironment.numFixupCurrent, ref _predicateEnvironment.numFixupPosition, ref _predicateEnvironment.numFixupLast); } //check if the matching nodes contains the current node QilIterator matchNodeIter = _f.For(matchingSet); QilNode filterCurrent = _f.Filter(matchNodeIter, _f.Is(matchNodeIter, current)); nodeFilter.Body = _f.Not(_f.IsEmpty(filterCurrent)); //for passing type check, explicit say the result is target type nodeFilter.Body = _f.And(_f.IsType(current, nodeFilter.XmlType), nodeFilter.Body); } SetPriority(nodeset, 0.5); return(nodeset); }