Converts descendant to child steps. @param cc compilation context @param rt root at compile time (can be null) @return original or new expression @throws QueryException query exception
(final CompileContext cc, final Expr rt)
| 622 | * @throws QueryException query exception |
| 623 | */ |
| 624 | private Expr children(final CompileContext cc, final Expr rt) throws QueryException { |
| 625 | // skip optimization... |
| 626 | // - if path does not start with document nodes |
| 627 | // - if index does not exist or is out-dated |
| 628 | // - if several namespaces occur in the input |
| 629 | final Data data = data(); |
| 630 | if(rt == null || !rt.seqType().type.instanceOf(NodeType.DOCUMENT) || |
| 631 | data == null || !data.meta.uptodate || data.defaultNs() == null) return this; |
| 632 | |
| 633 | final int sl = steps.length; |
| 634 | for(int s = 0; s < sl; s++) { |
| 635 | // don't allow predicates in preceding location steps |
| 636 | final Step prev = s > 0 ? axisStep(s - 1) : null; |
| 637 | if(prev != null && prev.exprs.length != 0) break; |
| 638 | |
| 639 | // ignore axes other than descendant, or numeric predicates |
| 640 | final Step curr = axisStep(s); |
| 641 | if(curr == null || curr.axis != DESCENDANT || curr.mayBePositional()) continue; |
| 642 | |
| 643 | // check if child steps can be retrieved for current step |
| 644 | ArrayList<PathNode> nodes = pathNodes(s); |
| 645 | if(nodes == null) continue; |
| 646 | |
| 647 | // cache child steps |
| 648 | final ArrayList<QNm> qNames = new ArrayList<>(); |
| 649 | while(nodes.get(0).parent != null) { |
| 650 | QNm qName = new QNm(data.elemNames.key(nodes.get(0).name)); |
| 651 | // skip children with prefixes |
| 652 | if(qName.hasPrefix()) return this; |
| 653 | for(final PathNode node : nodes) { |
| 654 | if(nodes.get(0).name != node.name) { |
| 655 | qName = null; |
| 656 | break; |
| 657 | } |
| 658 | } |
| 659 | qNames.add(qName); |
| 660 | nodes = PathIndex.parent(nodes); |
| 661 | } |
| 662 | cc.info(QueryText.OPTCHILD_X, steps[s]); |
| 663 | |
| 664 | // build new steps |
| 665 | int ts = qNames.size(); |
| 666 | final Expr[] stps = new Expr[ts + sl - s - 1]; |
| 667 | for(int t = 0; t < ts; t++) { |
| 668 | final Expr[] preds = t == ts - 1 ? ((Preds) steps[s]).exprs : new Expr[0]; |
| 669 | final QNm qName = qNames.get(ts - t - 1); |
| 670 | final Test test = Test.get(Kind.ELEMENT, qName, Scope.LOCAL, null); |
| 671 | stps[t] = Step.get(cc, root, curr.info(), CHILD, test, preds); |
| 672 | } |
| 673 | while(++s < sl) stps[ts++] = steps[s]; |
| 674 | |
| 675 | return get(cc, info, root, stps); |
| 676 | } |
| 677 | return this; |
| 678 | } |
| 679 | |
| 680 | /** |
| 681 | * Tries to rewrite the path to a simple map expression. |