Esempio n. 1
0
  /**
   * Checks if the specified step will never yield results.
   *
   * @param rt root value
   * @param s index of step
   * @return {@code true} if steps will never yield results
   */
  private boolean emptyPath(final Value rt, final int s) {
    final Step step = axisStep(s);
    if (step == null) return false;

    final Axis axis = step.axis;
    if (s == 0) {
      // first location step:
      if (root instanceof CAttr) {
        // @.../child:: / @.../descendant::
        if (axis == CHILD || axis == DESC) return true;
      } else if (root instanceof Root
          || root instanceof CDoc
          || rt != null && rt.type == NodeType.DOC) {
        if (axis == SELF || axis == ANCORSELF) {
          if (step.test != Test.NOD && step.test != Test.DOC) return true;
        } else if (axis == CHILD || axis == DESC) {
          if (step.test == Test.DOC || step.test == Test.ATT) return true;
        } else if (axis == DESCORSELF) {
          if (step.test == Test.ATT) return true;
        } else {
          return true;
        }
      }
    } else {
      // remaining steps:
      final Step last = axisStep(s - 1);
      if (last == null) return false;

      // .../self:: / .../descendant-or-self::
      if (axis == SELF || axis == DESCORSELF) {
        if (step.test == Test.NOD) return false;
        // @.../..., text()/...
        if (last.axis == ATTR && step.test.type != NodeType.ATT
            || last.test == Test.TXT && step.test != Test.TXT) return true;
        if (axis == DESCORSELF) return false;

        // .../self::
        final QNm name = step.test.name, lastName = last.test.name;
        if (lastName == null
            || name == null
            || lastName.local().length == 0
            || name.local().length == 0) return false;
        // ...X/...Y
        return !name.eq(lastName);
      }
      // .../following-sibling:: / .../preceding-sibling::
      if (axis == FOLLSIBL || axis == PRECSIBL) return last.axis == ATTR;
      // .../descendant:: / .../child:: / .../attribute::
      if (axis == DESC || axis == CHILD || axis == ATTR)
        return last.axis == ATTR
            || last.test == Test.TXT
            || last.test == Test.COM
            || last.test == Test.PI
            || axis == ATTR && step.test == Test.NSP;
      // .../parent:: / .../ancestor::
      if (axis == PARENT || axis == ANC) return last.test == Test.DOC;
    }
    return false;
  }
Esempio n. 2
0
  /**
   * Converts descendant to child steps.
   *
   * @param qc query context
   * @param rt root value
   * @return original or new expression
   */
  private Expr children(final QueryContext qc, final Value rt) {
    // skip if index does not exist or is out-dated, or if several namespaces occur in the input
    final Data data = rt.data();
    if (data == null || !data.meta.uptodate || data.nspaces.globalNS() == null) return this;

    Path path = this;
    final int sl = steps.length;
    for (int s = 0; s < sl; s++) {
      // don't allow predicates in preceding location steps
      final Step prev = s > 0 ? axisStep(s - 1) : null;
      if (prev != null && prev.preds.length != 0) break;

      // ignore axes other than descendant, or numeric predicates
      final Step curr = axisStep(s);
      if (curr == null || curr.axis != DESC || curr.has(Flag.FCS)) continue;

      // check if child steps can be retrieved for current step
      ArrayList<PathNode> nodes = pathNodes(data, s);
      if (nodes == null) continue;

      // cache child steps
      final ArrayList<QNm> qnm = new ArrayList<>();
      while (nodes.get(0).parent != null) {
        QNm nm = new QNm(data.elemNames.key(nodes.get(0).name));
        // skip children with prefixes
        if (nm.hasPrefix()) return this;
        for (final PathNode p : nodes) {
          if (nodes.get(0).name != p.name) nm = null;
        }
        qnm.add(nm);
        nodes = PathSummary.parent(nodes);
      }
      qc.compInfo(OPTCHILD, steps[s]);

      // build new steps
      int ts = qnm.size();
      final Expr[] stps = new Expr[ts + sl - s - 1];
      for (int t = 0; t < ts; t++) {
        final Expr[] preds = t == ts - 1 ? ((Preds) steps[s]).preds : new Expr[0];
        final QNm nm = qnm.get(ts - t - 1);
        final NameTest nt =
            nm == null ? new NameTest(false) : new NameTest(nm, Kind.NAME, false, null);
        stps[t] = Step.get(info, CHILD, nt, preds);
      }
      while (++s < sl) stps[ts++] = steps[s];
      path = get(info, root, stps);
      break;
    }

    // check if all steps yield results; if not, return empty sequence
    final ArrayList<PathNode> nodes = pathNodes(qc);
    if (nodes != null && nodes.isEmpty()) {
      qc.compInfo(OPTPATH, path);
      return Empty.SEQ;
    }

    return path;
  }
Esempio n. 3
0
  /**
   * Finds similar function names and throws an error message.
   *
   * @param name function name
   * @param ii input info
   * @throws QueryException query exception
   */
  public void funError(final QNm name, final InputInfo ii) throws QueryException {
    // find global function
    Functions.get().error(name, ii);

    // find similar local function
    final Levenshtein ls = new Levenshtein();
    final byte[] nm = lc(name.local());
    for (final UserFunc f : funcs) {
      if (ls.similar(nm, lc(f.name.local()), 0)) {
        FUNSIMILAR.thrw(ii, name.string(), f.name.string());
      }
    }
  }
Esempio n. 4
0
  /**
   * Adds a local function.
   *
   * @param fun function instance
   * @param ii input info
   * @return function id
   * @throws QueryException query exception
   */
  public int add(final UserFunc fun, final InputInfo ii) throws QueryException {
    final QNm name = fun.name;
    final byte[] uri = name.uri();
    if (uri.length == 0) FUNNONS.thrw(ii, name.string());

    if (NSGlobal.reserved(uri)) {
      if (fun.declared) NAMERES.thrw(ii, name.string());
      funError(name, ii);
    }

    final byte[] ln = name.local();
    for (int l = 0; l < funcs.length; ++l) {
      final QNm qn = funcs[l].name;
      final byte[] u = qn.uri();
      final byte[] nm = qn.local();

      if (eq(ln, nm) && eq(uri, u) && fun.args.length == funcs[l].args.length) {
        // declare function that has been called before
        if (!funcs[l].declared) {
          funcs[l] = fun;
          return l;
        }
        // duplicate declaration
        FUNCDEFINED.thrw(ii, fun.name.string());
      }
    }
    // add function skeleton
    funcs = Array.add(funcs, fun);
    calls = Array.add(calls, new UserFuncCall[0]);
    return funcs.length - 1;
  }
Esempio n. 5
0
 /**
  * Returns an index to the specified function, or {@code -1}.
  *
  * @param name name of the function
  * @param args optional arguments
  * @return function instance
  */
 private int indexOf(final QNm name, final Expr[] args) {
   for (int id = 0; id < funcs.length; ++id) {
     if (name.eq(funcs[id].name) && args.length == funcs[id].args.length) return id;
   }
   return -1;
 }
Esempio n. 6
0
  /**
   * Converts descendant to child steps.
   *
   * @param ctx query context
   * @param data data reference
   * @return path
   */
  Expr children(final QueryContext ctx, final Data data) {
    // skip path check if no path index exists, or if it is out-of-date
    if (!data.meta.uptodate || data.nspaces.globalNS() == null) return this;

    Path path = this;
    for (int s = 0; s < steps.length; ++s) {
      // don't allow predicates in preceding location steps
      final Step prev = s > 0 ? axisStep(s - 1) : null;
      if (prev != null && prev.preds.length != 0) break;

      // ignore axes other than descendant, or numeric predicates
      final Step curr = axisStep(s);
      if (curr == null || curr.axis != DESC || curr.has(Flag.FCS)) continue;

      // check if child steps can be retrieved for current step
      ArrayList<PathNode> pn = pathNodes(data, s);
      if (pn == null) continue;

      // cache child steps
      final ArrayList<QNm> qnm = new ArrayList<>();
      while (pn.get(0).par != null) {
        QNm nm = new QNm(data.tagindex.key(pn.get(0).name));
        // skip children with prefixes
        if (nm.hasPrefix()) return this;
        for (final PathNode p : pn) {
          if (pn.get(0).name != p.name) nm = null;
        }
        qnm.add(nm);
        pn = PathSummary.parent(pn);
      }
      ctx.compInfo(OPTCHILD, steps[s]);

      // build new steps
      int ts = qnm.size();
      final Expr[] stps = new Expr[ts + steps.length - s - 1];
      for (int t = 0; t < ts; ++t) {
        final Expr[] preds = t == ts - 1 ? ((Preds) steps[s]).preds : new Expr[0];
        final QNm nm = qnm.get(ts - t - 1);
        final NameTest nt =
            nm == null ? new NameTest(false) : new NameTest(nm, Mode.LN, false, null);
        stps[t] = Step.get(info, CHILD, nt, preds);
      }
      while (++s < steps.length) stps[ts++] = steps[s];
      path = get(info, root, stps);
      break;
    }

    // check if the all children in the path exist; don't test with namespaces
    if (data.nspaces.size() == 0) {
      LOOP:
      for (int s = 0; s < path.steps.length; ++s) {
        // only verify child steps; ignore namespaces
        final Step st = path.axisStep(s);
        if (st == null || st.axis != CHILD) break;
        if (st.test.mode == Mode.ALL || st.test.mode == null) continue;
        if (st.test.mode != Mode.LN) break;

        // check if one of the addressed nodes is on the correct level
        final int name = data.tagindex.id(st.test.name.local());
        for (final PathNode pn : data.paths.desc(name, Data.ELEM)) {
          if (pn.level() == s + 1) continue LOOP;
        }
        ctx.compInfo(OPTPATH, path);
        return Empty.SEQ;
      }
    }
    return path;
  }
Esempio n. 7
0
 /**
  * Checks if the location path contains steps that will never yield results.
  *
  * @param stps step array
  * @param ctx query context
  */
 void voidStep(final Expr[] stps, final QueryContext ctx) {
   for (int l = 0; l < stps.length; ++l) {
     final Step s = axisStep(l);
     if (s == null) continue;
     final Axis sa = s.axis;
     if (l == 0) {
       if (root instanceof CAttr) {
         // @.../child:: / @.../descendant::
         if (sa == CHILD || sa == DESC) {
           ctx.compInfo(WARNDESC, root);
           return;
         }
       } else if (root instanceof Root
           || root instanceof Value && ((Value) root).type == NodeType.DOC
           || root instanceof CDoc) {
         if (sa != CHILD
             && sa != DESC
             && sa != DESCORSELF
             && (sa != SELF && sa != ANCORSELF || s.test != Test.NOD && s.test != Test.DOC)) {
           ctx.compInfo(WARNDOC, root, sa);
           return;
         }
       }
     } else {
       final Step ls = axisStep(l - 1);
       if (ls == null) continue;
       final Axis lsa = ls.axis;
       boolean warning = true;
       if (sa == SELF || sa == DESCORSELF) {
         // .../self:: / .../descendant-or-self::
         if (s.test == Test.NOD) continue;
         // @.../..., text()/...
         warning =
             lsa == ATTR && s.test.type != NodeType.ATT
                 || ls.test == Test.TXT && s.test != Test.TXT;
         if (!warning) {
           if (sa == DESCORSELF) continue;
           // .../self::
           final QNm n0 = ls.test.name;
           final QNm n1 = s.test.name;
           if (n0 == null || n1 == null || n0.local().length == 0 || n1.local().length == 0)
             continue;
           // ...X/...Y
           warning = !n1.eq(n0);
         }
       } else if (sa == FOLLSIBL || sa == PRECSIBL) {
         // .../following-sibling:: / .../preceding-sibling::
         warning = lsa == ATTR;
       } else if (sa == DESC || sa == CHILD || sa == ATTR) {
         // .../descendant:: / .../child:: / .../attribute::
         warning =
             lsa == ATTR
                 || ls.test == Test.TXT
                 || ls.test == Test.COM
                 || ls.test == Test.PI
                 || sa == ATTR && s.test == Test.NSP;
       } else if (sa == PARENT || sa == ANC) {
         // .../parent:: / .../ancestor::
         warning = ls.test == Test.DOC;
       }
       if (warning) {
         ctx.compInfo(WARNSELF, s);
         return;
       }
     }
   }
 }