Example #1
0
        //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);
        }