Permalink
Browse files

[ADD] XQuery: simple map ("bang") operator added (XQ30, 3.3.1.1).

      Example (creating 10 elements): (1 to 10) ! <hit>{.}</hit>
  • Loading branch information...
1 parent f549241 commit d32aecc19beaafb1e79689f92cfe8c71dae76939 @ChristianGruen ChristianGruen committed Apr 29, 2012
@@ -1,4 +1,3 @@
-#Sun Nov 27 07:43:18 CET 2011
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
@@ -211,19 +211,7 @@ private Command parse(final Cmd cmd, final boolean s) throws QueryException {
case PASSWORD:
return new Password(password());
case HELP:
- String hc = name(null);
- String form = null;
- if(hc != null) {
- if(hc.equalsIgnoreCase("wiki")) {
- form = hc;
- hc = null;
- } else {
- ip = im;
- hc = consume(Cmd.class, cmd).toString();
- form = name(null);
- }
- }
- return new Help(hc, form);
+ return new Help(name(null));
case EXIT:
return new Exit();
case FLUSH:
@@ -479,7 +467,7 @@ private void consumeWS() {
* @return QueryException query exception
*/
private QueryException help(final StringList alt, final Cmd cmd) {
- return error(alt, SYNTAX_X, cmd.help(true, false));
+ return error(alt, SYNTAX_X, cmd.help(true));
}
/**
@@ -57,44 +57,17 @@
/**
* Returns a help string.
* @param detail show details
- * @param wiki print wiki format
* @return string
*/
- public final String help(final boolean detail, final boolean wiki) {
+ public final String help(final boolean detail) {
final StringBuilder sb = new StringBuilder();
- if(wiki) {
- wiki(sb);
+ if(help == null) {
+ if(detail) sb.append(NOHELP).append(NL);
} else {
- if(help == null) {
- if(detail) sb.append(NOHELP).append(NL);
- } else {
- sb.append(this + " " + help[0] + NL + " " + help[1] + NL);
- if(detail) sb.append(NL + help[2] + NL);
- }
+ sb.append(this + " " + help[0] + NL + " " + help[1] + NL);
+ if(detail) sb.append(NL + help[2] + NL);
}
return sb.toString();
}
-
- /**
- * Returns a help string in the Wiki format.
- * @param sb string builder
- */
- private void wiki(final StringBuilder sb) {
- if(help == null) return;
-
- sb.append("===" + this + "===" + NL + NL);
- sb.append("'''<code>" + this + ' ' + help[0] + "</code>'''" + NL + NL);
-
- for(String s : help[2].split(NL)) {
- if(s.startsWith("- ")) {
- s = s.replaceAll("^- (.*?)(:|$)", "* <code>$1</code>$2");
- } else {
- s = s.replaceAll("^ ", ":");
- s = s.replaceAll("\\[", "<code>[").replaceAll("\\]", "]</code>");
- }
- sb.append(s).append(NL);
- }
- sb.append(NL);
- }
}
}
@@ -19,30 +19,19 @@
* @param arg optional argument
*/
public Help(final String arg) {
- this(arg, null);
- }
-
- /**
- * Default constructor.
- * @param arg optional argument
- * @param format optional format (e.g., Wiki)
- */
- public Help(final String arg, final String format) {
- super(Perm.NONE, arg, format);
+ super(Perm.NONE, arg);
}
@Override
protected boolean run() throws IOException {
final String key = args[0];
- final boolean wiki = args[1] != null;
-
if(key != null) {
final Cmd cmd = getOption(key, Cmd.class);
if(cmd == null) return error(UNKNOWN_CMD_X, this);
- out.print(cmd.help(true, wiki));
+ out.print(cmd.help(true));
} else {
out.println(TRY_SPECIFIC_X);
- for(final Cmd c : Cmd.values()) out.print(c.help(false, wiki));
+ for(final Cmd c : Cmd.values()) out.print(c.help(false));
}
return true;
}
@@ -1585,56 +1585,81 @@ private Expr extension() throws QueryException {
/**
* Parses the "PathExpr" rule.
- * Parses the "RelativePathExpr" rule.
* @return query expression
* @throws QueryException query exception
*/
private Expr path() throws QueryException {
- // XQuery30: bang operator (still to be parsed and implemented)
-
checkInit();
- final int s = consume('/') ? consume('/') ? 2 : 1 : 0;
- if(s > 0) checkAxis(s == 2 ? Axis.DESC : Axis.CHILD);
- im = ip;
-
- final Expr ex = step();
- if(ex == null) {
- if(s == 2) {
- if(more()) checkInit();
- error(PATHMISS, found());
+
+ final ExprList el;
+ Expr root = null;
+ if(consume('/')) {
+ root = new Root(info());
+ el = new ExprList();
+ final Expr ex;
+ if(consume('/')) {
+ // two slashes: absolute descendant path
+ checkAxis(Axis.DESC);
+ add(el, descOrSelf());
+ mark();
+ ex = step();
+ if(ex == null) {
+ // two slashes, but no following step: error
+ if(more()) checkInit();
+ error(PATHMISS, found());
+ }
+ } else {
+ // one slash: absolute child path
+ checkAxis(Axis.CHILD);
+ mark();
+ ex = step();
+ // no more steps: return root expression
+ if(ex == null) return root;
}
- return s == 1 ? new Root(info()) : null;
+ add(el, ex);
+ relativePath(el);
+ } else {
+ // relative path (no preceding slash)
+ mark();
+ final Expr ex = step();
+ if(ex == null) return null;
+ // return non-step expression if no path or map operator follows
+ final boolean nostep = curr() != '/' && (curr() != '!' || next() == '=');
+ if(nostep && !(ex instanceof AxisStep)) return ex;
+ el = new ExprList();
+ if(ex instanceof AxisStep) add(el, ex);
+ else root = ex;
+ relativePath(el);
}
+ return Path.get(info(), root, el.finish());
+ }
- final boolean slash = consume('/');
- final boolean step = ex instanceof AxisStep;
- if(!slash && s == 0 && !step) return ex;
-
- final ExprList el = new ExprList();
- if(s == 2) add(el, descOrSelf());
-
- final Expr root = s > 0 ? new Root(info()) : !step ? ex : null;
- if(root != ex) add(el, ex);
-
- if(slash) {
- do {
- final boolean desc = consume('/');
- im = ip;
- if(desc) add(el, descOrSelf());
- checkAxis(desc ? Axis.DESC : Axis.CHILD);
-
- final Expr st = step();
- if(st == null) error(PATHMISS, found());
- // skip context nodes
- if(!(st instanceof Context)) add(el, st);
- } while(consume('/'));
+ /**
+ * Parses the "RelativePathExpr" rule.
+ * @param el expression list
+ * @throws QueryException query exception
+ */
+ void relativePath(final ExprList el) throws QueryException {
+ while(true) {
+ boolean b = false;
+ if(consume('/')) {
+ if(consume('/')) {
+ add(el, descOrSelf());
+ checkAxis(Axis.DESC);
+ } else {
+ checkAxis(Axis.CHILD);
+ }
+ } else if(next() != '=' && consume('!')) {
+ b = true;
+ } else {
+ return;
+ }
+ mark();
+ Expr st = step();
+ if(st == null) error(PATHMISS, found());
+ if(b) st = new Bang(info(), st);
+ add(el, st);
}
-
- // if no location steps have been added, add trailing self::node() step as
- // replacement for context node to bring results in order
- if(el.isEmpty()) add(el, AxisStep.get(info(), Axis.SELF, Test.NOD));
-
- return Path.get(info(), root, el.finish());
}
/**
@@ -40,8 +40,8 @@
public Catch(final InputInfo ii, final QNm[] c, final QueryContext ctx) {
super(ii, null);
codes = c;
- for(int i = 0; i < QNM.length; i++) vars[i] =
- Var.create(ctx, null, QNM[i], TYPES[i], null);
+ for(int i = 0; i < QNM.length; i++)
+ vars[i] = Var.create(ctx, null, QNM[i], TYPES[i], null);
}
@Override
@@ -16,7 +16,7 @@
import org.basex.util.*;
/**
- * Location Step expression.
+ * Axis step expression.
*
* @author BaseX Team 2005-12, BSD License
* @author Christian Gruen
@@ -0,0 +1,46 @@
+package org.basex.query.path;
+
+import org.basex.query.*;
+import org.basex.query.expr.*;
+import org.basex.query.item.*;
+import org.basex.query.iter.*;
+import org.basex.util.*;
+
+/**
+ * Map ("bang") operator. Only occurs as argument of the {@link MixedPath} expression.
+ *
+ * @author BaseX Team 2005-12, BSD License
+ * @author Christian Gruen
+ */
+public final class Bang extends Single {
+ /**
+ * Constructor.
+ * @param ii input info
+ * @param e expression
+ */
+ public Bang(final InputInfo ii, final Expr e) {
+ super(ii, e);
+ }
+
+ @Override
+ public Expr comp(final QueryContext ctx) throws QueryException {
+ super.comp(ctx);
+ type = expr.type();
+ return this;
+ }
+
+ @Override
+ public Iter iter(final QueryContext ctx) throws QueryException {
+ return ctx.iter(expr);
+ }
+
+ @Override
+ public Value value(final QueryContext ctx) throws QueryException {
+ return ctx.value(expr);
+ }
+
+ @Override
+ public String toString() {
+ return expr.toString();
+ }
+}
@@ -66,6 +66,8 @@ public Iter iter(final QueryContext ctx) throws QueryException {
final int el = steps.length;
for(int ex = 0; ex < el; ex++) {
final Expr e = steps[ex];
+ // map operator: don't remove duplicates and check for nodes
+ final boolean path = !(e instanceof Bang);
final boolean last = ex + 1 == el;
final ValueBuilder vb = new ValueBuilder();
@@ -76,22 +78,24 @@ public Iter iter(final QueryContext ctx) throws QueryException {
// loop through all input items
for(Item it; (it = res.next()) != null;) {
- if(!it.type.isNode()) NODESPATH.thrw(info, this, it.type);
+ if(path && !it.type.isNode()) NODESPATH.thrw(info, this, it.type);
ctx.value = it;
// loop through all resulting items
final Iter ir = ctx.iter(e);
for(Item i; (i = ir.next()) != null;) {
- // set node flag
- if(vb.size() == 0) nodes = i.type.isNode();
- // check if both nodes and atomic values occur in last result
- else if(last && nodes != i.type.isNode()) EVALNODESVALS.thrw(info);
+ if(path) {
+ // set node flag
+ if(vb.size() == 0) nodes = i.type.isNode();
+ // check if both nodes and atomic values occur in last result
+ else if(last && nodes != i.type.isNode()) EVALNODESVALS.thrw(info);
+ }
vb.add(i);
}
ctx.pos++;
}
- if(nodes) {
+ if(nodes && path) {
// remove potential duplicates from node sets
final NodeCache nc = new NodeCache().random();
for(Item it; (it = vb.next()) != null;) nc.add((ANode) it);
@@ -384,7 +384,10 @@ public final void plan(final FElem plan) {
public final String toString() {
final StringBuilder sb = new StringBuilder();
if(root != null) sb.append(root);
- for(final Expr s : steps) sb.append(sb.length() != 0 ? "/" : "").append(s);
+ for(final Expr s : steps) {
+ if(sb.length() != 0) sb.append(s instanceof Bang ? '!' : '/');
+ sb.append(s);
+ }
return sb.toString();
}
}

0 comments on commit d32aecc

Please sign in to comment.