Пример #1
0
  /**
   * Evaluates the analyze-string function.
   *
   * @param val input value
   * @param ctx query context
   * @return function result
   * @throws QueryException query exception
   */
  private Item analyzeString(final byte[] val, final QueryContext ctx) throws QueryException {

    final Pattern p = pattern(expr[1], expr.length == 3 ? expr[2] : null, ctx);
    if (p.matcher("").matches()) REGROUP.thrw(info);
    final String str = string(val);
    final Matcher m = p.matcher(str);

    final FElem root = new FElem(Q_ANALYZE, new Atts(FN, FNURI));
    int s = 0;
    while (m.find()) {
      if (s != m.start()) nonmatch(str.substring(s, m.start()), root);
      match(m, str, root, 0);
      s = m.end();
    }
    if (s != str.length()) nonmatch(str.substring(s), root);
    return root;
  }
Пример #2
0
 /**
  * Constructor.
  *
  * @param value value
  * @param type item type
  * @param ii input info
  * @throws QueryException query exception
  */
 private Dur(final byte[] value, final Type type, final InputInfo ii) throws QueryException {
   this(type);
   final String val = Token.string(value).trim();
   final Matcher mt = DUR.matcher(val);
   if (!mt.matches() || val.endsWith("P") || val.endsWith("T")) throw dateError(value, XDURR, ii);
   yearMonth(value, mt, ii);
   dayTime(value, mt, 6, ii);
 }
Пример #3
0
  /**
   * Evaluates the tokenize function.
   *
   * @param ctx query context
   * @return function result
   * @throws QueryException query exception
   */
  private Value tokenize(final QueryContext ctx) throws QueryException {
    final byte[] val = checkEStr(expr[0], ctx);
    final Pattern p = pattern(expr[1], expr.length == 3 ? expr[2] : null, ctx);
    if (p.matcher("").matches()) REGROUP.thrw(info);

    final TokenList tl = new TokenList();
    final String str = string(val);
    if (!str.isEmpty()) {
      final Matcher m = p.matcher(str);
      int s = 0;
      while (m.find()) {
        tl.add(str.substring(s, m.start()));
        s = m.end();
      }
      tl.add(str.substring(s, str.length()));
    }
    return StrSeq.get(tl);
  }
Пример #4
0
  /**
   * Evaluates the replace function.
   *
   * @param val input value
   * @param ctx query context
   * @return function result
   * @throws QueryException query exception
   */
  private Item replace(final byte[] val, final QueryContext ctx) throws QueryException {
    final byte[] rep = checkStr(expr[2], ctx);
    for (int i = 0; i < rep.length; ++i) {
      if (rep[i] == '\\') {
        if (i + 1 == rep.length || rep[i + 1] != '\\' && rep[i + 1] != '$') FUNREPBS.thrw(info);
        ++i;
      }
      if (rep[i] == '$'
          && (i == 0 || rep[i - 1] != '\\')
          && (i + 1 == rep.length || !digit(rep[i + 1]))) FUNREPDOL.thrw(info);
    }

    final Pattern p = pattern(expr[1], expr.length == 4 ? expr[3] : null, ctx);
    if (p.pattern().isEmpty()) REGROUP.thrw(info);

    String r = string(rep);
    if ((p.flags() & Pattern.LITERAL) != 0) {
      r = SLASH.matcher(BSLASH.matcher(r).replaceAll("\\\\\\\\")).replaceAll("\\\\\\$");
    }

    try {
      return Str.get(p.matcher(string(val)).replaceAll(r));
    } catch (final Exception ex) {
      if (ex.getMessage().contains("No group")) REGROUP.thrw(info);
      throw REGPAT.thrw(info, ex);
    }
  }
Пример #5
0
/**
 * Duration item ({@code xs:duration}).
 *
 * @author BaseX Team 2005-16, BSD License
 * @author Christian Gruen
 */
public class Dur extends ADateDur {
  /** Pattern for one or more digits. */
  static final String DP = "(\\d+)";

  /** Date pattern. */
  private static final Pattern DUR =
      Pattern.compile(
          "(-?)P("
              + DP
              + "Y)?("
              + DP
              + "M)?("
              + DP
              + "D)?(T("
              + DP
              + "H)?("
              + DP
              + "M)?((\\d+|\\d*\\.\\d+)?S)?)?");

  /** Number of months. */
  long mon;

  /**
   * Constructor.
   *
   * @param value value
   * @param ii input info
   * @throws QueryException query exception
   */
  public Dur(final byte[] value, final InputInfo ii) throws QueryException {
    this(value, AtomType.DUR, ii);
  }

  /**
   * Constructor.
   *
   * @param type item type
   */
  Dur(final Type type) {
    super(type);
  }

  /**
   * Constructor.
   *
   * @param dur duration
   */
  public Dur(final Dur dur) {
    this(dur, AtomType.DUR);
  }

  /**
   * Constructor.
   *
   * @param dur duration
   * @param type item type
   */
  private Dur(final Dur dur, final Type type) {
    this(type);
    mon = dur.mon;
    sec = dur.sec == null ? BigDecimal.ZERO : dur.sec;
  }

  /**
   * Constructor.
   *
   * @param value value
   * @param type item type
   * @param ii input info
   * @throws QueryException query exception
   */
  private Dur(final byte[] value, final Type type, final InputInfo ii) throws QueryException {
    this(type);
    final String val = Token.string(value).trim();
    final Matcher mt = DUR.matcher(val);
    if (!mt.matches() || val.endsWith("P") || val.endsWith("T")) throw dateError(value, XDURR, ii);
    yearMonth(value, mt, ii);
    dayTime(value, mt, 6, ii);
  }

  /**
   * Initializes the yearMonth component.
   *
   * @param vl value
   * @param mt matcher
   * @param ii input info
   * @throws QueryException query exception
   */
  void yearMonth(final byte[] vl, final Matcher mt, final InputInfo ii) throws QueryException {
    final long y = mt.group(2) != null ? toLong(mt.group(3), true, ii) : 0;
    final long m = mt.group(4) != null ? toLong(mt.group(5), true, ii) : 0;
    mon = y * 12 + m;
    double v = y * 12d + m;
    if (!mt.group(1).isEmpty()) {
      mon = -mon;
      v = -v;
    }
    if (v <= Long.MIN_VALUE || v >= Long.MAX_VALUE) throw DURRANGE_X_X.get(ii, type, vl);
  }

  /**
   * Initializes the dayTime component.
   *
   * @param vl value
   * @param mt matcher
   * @param p first matching position
   * @param ii input info
   * @throws QueryException query exception
   */
  void dayTime(final byte[] vl, final Matcher mt, final int p, final InputInfo ii)
      throws QueryException {

    final long d = mt.group(p) != null ? toLong(mt.group(p + 1), true, ii) : 0;
    final long h = mt.group(p + 3) != null ? toLong(mt.group(p + 4), true, ii) : 0;
    final long m = mt.group(p + 5) != null ? toLong(mt.group(p + 6), true, ii) : 0;
    final BigDecimal s =
        mt.group(p + 7) != null ? toDecimal(mt.group(p + 8), true, ii) : BigDecimal.ZERO;
    sec =
        s.add(BigDecimal.valueOf(d).multiply(DAYSECONDS))
            .add(BigDecimal.valueOf(h).multiply(BD3600))
            .add(BigDecimal.valueOf(m).multiply(BD60));
    if (!mt.group(1).isEmpty()) sec = sec.negate();
    final double v = sec.doubleValue();
    if (v <= Long.MIN_VALUE || v >= Long.MAX_VALUE) throw DURRANGE_X_X.get(ii, type, vl);
  }

  @Override
  public final long yea() {
    return mon / 12;
  }

  @Override
  public final long mon() {
    return mon % 12;
  }

  @Override
  public final long day() {
    return sec.divideToIntegralValue(DAYSECONDS).longValue();
  }

  @Override
  public final long hou() {
    return tim() / 3600;
  }

  @Override
  public final long min() {
    return tim() % 3600 / 60;
  }

  @Override
  public final BigDecimal sec() {
    return sec.remainder(BD60);
  }

  /**
   * Returns the time.
   *
   * @return time
   */
  private long tim() {
    return sec.remainder(DAYSECONDS).longValue();
  }

  @Override
  public byte[] string(final InputInfo ii) {
    final TokenBuilder tb = new TokenBuilder();
    final int ss = sec.signum();
    if (mon < 0 || ss < 0) tb.add('-');
    date(tb);
    time(tb);
    if (mon == 0 && ss == 0) tb.add("T0S");
    return tb.finish();
  }

  /**
   * Adds the date to the specified token builder.
   *
   * @param tb token builder
   */
  final void date(final TokenBuilder tb) {
    tb.add('P');
    final long y = yea();
    if (y != 0) {
      tb.addLong(Math.abs(y));
      tb.add('Y');
    }
    final long m = mon();
    if (m != 0) {
      tb.addLong(Math.abs(m));
      tb.add('M');
    }
    final long d = day();
    if (d != 0) {
      tb.addLong(Math.abs(d));
      tb.add('D');
    }
  }

  /**
   * Adds the time to the specified token builder.
   *
   * @param tb token builder
   */
  final void time(final TokenBuilder tb) {
    if (sec.remainder(DAYSECONDS).signum() == 0) return;
    tb.add('T');
    final long h = hou();
    if (h != 0) {
      tb.addLong(Math.abs(h));
      tb.add('H');
    }
    final long m = min();
    if (m != 0) {
      tb.addLong(Math.abs(m));
      tb.add('M');
    }
    final BigDecimal sc = sec();
    if (sc.signum() == 0) return;
    tb.add(Token.chopNumber(Token.token(sc.abs().toPlainString()))).add('S');
  }

  @Override
  public final boolean eq(
      final Item it, final Collation coll, final StaticContext sc, final InputInfo ii)
      throws QueryException {
    final Dur d = (Dur) (it instanceof Dur ? it : type.cast(it, null, null, ii));
    final BigDecimal s1 = sec == null ? BigDecimal.ZERO : sec;
    final BigDecimal s2 = d.sec == null ? BigDecimal.ZERO : d.sec;
    return mon == d.mon && s1.compareTo(s2) == 0;
  }

  @Override
  public int diff(final Item it, final Collation coll, final InputInfo ii) throws QueryException {
    throw diffError(ii, it, this);
  }

  @Override
  public final Duration toJava() {
    return ADate.DF.newDuration(Token.string(string(null)));
  }

  @Override
  public final int hash(final InputInfo ii) {
    return (int) (31 * mon + (sec == null ? 0 : sec.doubleValue()));
  }

  @Override
  public final String toString() {
    return Util.info("\"%\"", string(null));
  }
}
Пример #6
0
/**
 * String pattern functions.
 *
 * @author BaseX Team 2005-12, BSD License
 * @author Christian Gruen
 */
public final class FNPat extends StandardFunc {
  /** Pattern cache. */
  private final TokenObjMap<Pattern> patterns = new TokenObjMap<Pattern>();

  /** Slash pattern. */
  private static final Pattern SLASH = Pattern.compile("\\$");
  /** Slash pattern. */
  private static final Pattern BSLASH = Pattern.compile("\\\\");

  /** Root element for the analyze-string-result function. */
  private static final QNm Q_ANALYZE = new QNm("fn:analyze-string-result", FNURI);
  /** Element for the analyze-string-result function. */
  private static final QNm Q_MATCH = new QNm("fn:match", FNURI);
  /** Element for the analyze-string-result function. */
  private static final QNm Q_NONMATCH = new QNm("fn:non-match", FNURI);
  /** Element for the analyze-string-result function. */
  private static final QNm Q_MGROUP = new QNm("fn:group", FNURI);
  /** Attribute for the analyze-string-result function. */
  private static final QNm Q_NR = new QNm("nr");

  /**
   * Constructor.
   *
   * @param ii input info
   * @param f function definition
   * @param e arguments
   */
  public FNPat(final InputInfo ii, final Function f, final Expr... e) {
    super(ii, f, e);
  }

  @Override
  public Iter iter(final QueryContext ctx) throws QueryException {
    switch (sig) {
      case TOKENIZE:
        return tokenize(ctx).iter();
      default:
        return super.iter(ctx);
    }
  }

  @Override
  public Value value(final QueryContext ctx) throws QueryException {
    switch (sig) {
      case TOKENIZE:
        return tokenize(ctx);
      default:
        return super.value(ctx);
    }
  }

  @Override
  public Item item(final QueryContext ctx, final InputInfo ii) throws QueryException {
    switch (sig) {
      case MATCHES:
        return matches(checkEStr(expr[0], ctx), ctx);
      case REPLACE:
        return replace(checkEStr(expr[0], ctx), ctx);
      case ANALYZE_STRING:
        return analyzeString(checkEStr(expr[0], ctx), ctx);
      default:
        return super.item(ctx, ii);
    }
  }

  /**
   * Evaluates the match function.
   *
   * @param val input value
   * @param ctx query context
   * @return function result
   * @throws QueryException query exception
   */
  private Item matches(final byte[] val, final QueryContext ctx) throws QueryException {
    final Pattern p = pattern(expr[1], expr.length == 3 ? expr[2] : null, ctx);
    return Bln.get(p.matcher(string(val)).find());
  }

  /**
   * Evaluates the analyze-string function.
   *
   * @param val input value
   * @param ctx query context
   * @return function result
   * @throws QueryException query exception
   */
  private Item analyzeString(final byte[] val, final QueryContext ctx) throws QueryException {

    final Pattern p = pattern(expr[1], expr.length == 3 ? expr[2] : null, ctx);
    if (p.matcher("").matches()) REGROUP.thrw(info);
    final String str = string(val);
    final Matcher m = p.matcher(str);

    final FElem root = new FElem(Q_ANALYZE, new Atts(FN, FNURI));
    int s = 0;
    while (m.find()) {
      if (s != m.start()) nonmatch(str.substring(s, m.start()), root);
      match(m, str, root, 0);
      s = m.end();
    }
    if (s != str.length()) nonmatch(str.substring(s), root);
    return root;
  }

  /**
   * Processes a match.
   *
   * @param m matcher
   * @param str string
   * @param par parent
   * @param g group number
   * @return next group number and position in string
   */
  private static int[] match(final Matcher m, final String str, final FElem par, final int g) {

    final FElem nd = new FElem(g == 0 ? Q_MATCH : Q_MGROUP, new Atts(FN, FNURI));
    if (g > 0) nd.add(Q_NR, token(g));

    final int start = m.start(g), end = m.end(g), gc = m.groupCount();
    int[] pos = {g + 1, start}; // group and position in string
    while (pos[0] <= gc && m.end(pos[0]) <= end) {
      final int st = m.start(pos[0]);
      if (st >= 0) { // group matched
        if (pos[1] < st) nd.add(str.substring(pos[1], st));
        pos = match(m, str, nd, pos[0]);
      } else pos[0]++; // skip it
    }
    if (pos[1] < end) {
      nd.add(str.substring(pos[1], end));
      pos[1] = end;
    }
    par.add(nd);
    return pos;
  }

  /**
   * Processes a non-match.
   *
   * @param text text
   * @param par root node
   */
  private static void nonmatch(final String text, final FElem par) {
    par.add(new FElem(Q_NONMATCH, new Atts(FN, FNURI)).add(text));
  }

  /**
   * Evaluates the replace function.
   *
   * @param val input value
   * @param ctx query context
   * @return function result
   * @throws QueryException query exception
   */
  private Item replace(final byte[] val, final QueryContext ctx) throws QueryException {
    final byte[] rep = checkStr(expr[2], ctx);
    for (int i = 0; i < rep.length; ++i) {
      if (rep[i] == '\\') {
        if (i + 1 == rep.length || rep[i + 1] != '\\' && rep[i + 1] != '$') FUNREPBS.thrw(info);
        ++i;
      }
      if (rep[i] == '$'
          && (i == 0 || rep[i - 1] != '\\')
          && (i + 1 == rep.length || !digit(rep[i + 1]))) FUNREPDOL.thrw(info);
    }

    final Pattern p = pattern(expr[1], expr.length == 4 ? expr[3] : null, ctx);
    if (p.pattern().isEmpty()) REGROUP.thrw(info);

    String r = string(rep);
    if ((p.flags() & Pattern.LITERAL) != 0) {
      r = SLASH.matcher(BSLASH.matcher(r).replaceAll("\\\\\\\\")).replaceAll("\\\\\\$");
    }

    try {
      return Str.get(p.matcher(string(val)).replaceAll(r));
    } catch (final Exception ex) {
      if (ex.getMessage().contains("No group")) REGROUP.thrw(info);
      throw REGPAT.thrw(info, ex);
    }
  }

  /**
   * Evaluates the tokenize function.
   *
   * @param ctx query context
   * @return function result
   * @throws QueryException query exception
   */
  private Value tokenize(final QueryContext ctx) throws QueryException {
    final byte[] val = checkEStr(expr[0], ctx);
    final Pattern p = pattern(expr[1], expr.length == 3 ? expr[2] : null, ctx);
    if (p.matcher("").matches()) REGROUP.thrw(info);

    final TokenList tl = new TokenList();
    final String str = string(val);
    if (!str.isEmpty()) {
      final Matcher m = p.matcher(str);
      int s = 0;
      while (m.find()) {
        tl.add(str.substring(s, m.start()));
        s = m.end();
      }
      tl.add(str.substring(s, str.length()));
    }
    return StrSeq.get(tl);
  }

  /**
   * Returns a regular expression pattern.
   *
   * @param pattern input pattern
   * @param modifier modifier item
   * @param ctx query context
   * @return pattern modifier
   * @throws QueryException query exception
   */
  private Pattern pattern(final Expr pattern, final Expr modifier, final QueryContext ctx)
      throws QueryException {

    final byte[] pat = checkStr(pattern, ctx);
    final byte[] mod = modifier != null ? checkStr(modifier, ctx) : null;
    final TokenBuilder tb = new TokenBuilder(pat);
    if (mod != null) tb.add(0).add(mod);
    final byte[] key = tb.finish();
    Pattern p = patterns.get(key);
    if (p == null) {
      p = RegExParser.parse(pat, mod, ctx.sc.xquery3(), info);
      patterns.add(key, p);
    }
    return p;
  }

  @Override
  public boolean xquery3() {
    return sig == ANALYZE_STRING;
  }

  @Override
  public boolean uses(final Use u) {
    return u == Use.X30 && xquery3() || u == Use.CNS && sig == ANALYZE_STRING || super.uses(u);
  }
}
Пример #7
0
 /**
  * Evaluates the match function.
  *
  * @param val input value
  * @param ctx query context
  * @return function result
  * @throws QueryException query exception
  */
 private Item matches(final byte[] val, final QueryContext ctx) throws QueryException {
   final Pattern p = pattern(expr[1], expr.length == 3 ? expr[2] : null, ctx);
   return Bln.get(p.matcher(string(val)).find());
 }