@Override public NodeIter iter(final QueryContext ctx) throws QueryException { final Value v = checkCtx(ctx); if (!v.type.isNode()) NODESPATH.thrw(input, AxisStep.this, v.type); final AxisIter ai = axis.iter((ANode) v); final NodeCache nc = new NodeCache(); for (ANode n; (n = ai.next()) != null; ) if (test.eval(n)) nc.add(n.finish()); // evaluate predicates for (final Expr p : preds) { ctx.size = nc.size(); ctx.pos = 1; int c = 0; for (int n = 0; n < nc.size(); ++n) { ctx.value = nc.get(n); final Item i = p.test(ctx, input); if (i != null) { // assign score value nc.get(n).score(i.score()); nc.item[c++] = nc.get(n); } ctx.pos++; } nc.size(c); } return nc; }
/** * Returns the value of the specified attribute, or {@code null}. * * @param name attribute to be found * @return attribute value */ public byte[] attribute(final QNm name) { final AxisIter ai = attributes(); while (true) { final ANode node = ai.next(); if (node == null) return null; if (node.qname().eq(name)) return node.atom(); } }
/** * Returns the uri for the specified prefix. * * @param pref prefix * @param ctx query context * @return uri */ public final byte[] uri(final byte[] pref, final QueryContext ctx) { final Atts at = ns(); if (at != null) { final int i = at.get(pref); if (i != -1) return at.val[i]; final ANode n = parent(); if (n != null) return n.uri(pref, ctx); } return pref.length == 0 ? Token.EMPTY : null; }
@Override public URI getNodeUri() throws XQException { opened(); if (!it.node()) throw new BXQException(NODE); final ANode node = (ANode) it; try { return new URI(Token.string(node.base())); } catch (final URISyntaxException ex) { throw new BXQException(ex.toString()); } }
/** * Removes unused namespaces. * * @param node to be modified */ private static void noPreserve(final ANode node) { final Atts ns = node.namespaces(); final byte[] pref = node.qname().prefix(); for (int i = ns.size() - 1; i >= 0; i--) { boolean f = eq(ns.name(i), pref); final AxisIter atts = node.attributes(); for (ANode it; f && (it = atts.next()) != null; ) { f |= eq(it.qname().prefix(), pref); } if (!f) ns.delete(i); } }
/** * Inherits namespaces. * * @param node to be modified * @param nsp in-scope namespaces */ private static void inherit(final ANode node, final Atts nsp) { final Atts ns = node.namespaces(); for (int a = nsp.size() - 1; a >= 0; a--) { final byte[] pref = nsp.name(a); if (!ns.contains(pref)) ns.add(pref, nsp.string(a)); } }
/** * Returns the namespace hierarchy. * * @param nsInherit copy-namespaces inherit * @return namespaces [LW][LK] Namespaces: this isn't enough */ public final Atts nsScope(final boolean nsInherit) { final Atts ns = new Atts(); ANode n = this; do { final Atts nns = n.ns(); if (!nsInherit) return nns; if (nns != null) { for (int a = nns.size - 1; a >= 0; a--) { final byte[] key = nns.key[a]; if (!ns.contains(key)) ns.add(key, nns.val[a]); } } n = n.parent(); } while (n != null && n.type == NodeType.ELM); return ns; }
/** * Executes a prepared statement. * * @param stmt prepared statement * @param ctx query context * @return result * @throws QueryException query exception */ private NodeCache executePrepStmt(final PreparedStatement stmt, final QueryContext ctx) throws QueryException { // Get parameters for prepared statement final ANode params = (ANode) checkType(expr[1].item(ctx, input), NodeType.ELM); if (!params.qname().eq(E_PARAMS)) PARWHICH.thrw(input, params.qname()); try { final int placeCount = stmt.getParameterMetaData().getParameterCount(); // Check if number of parameters equals number of place holders if (placeCount != countParams(params)) PARAMS.thrw(input); else setParameters(params.children(), stmt); final boolean result = stmt.execute(); return result ? buildResult(stmt.getResultSet()) : new NodeCache(); } catch (final SQLException ex) { throw SQLEXC.thrw(input, ex.getMessage()); } }
/** * Builds full-text information. * * @param nd node to be added * @return number of added nodes */ TokenList build(final ANode nd) { // check full-text mode if (!(nd instanceof DBNode)) return null; // check if full-text data exists for the current node final DBNode node = (DBNode) nd; return build(node.data, node.pre, nd.string()); }
@Override public void prepare() throws QueryException { // build data with all documents, to prevent dirty reads md = new MemData(data); for (final Item d : docs) { final MemData docData; if (d.node()) { // adding a document node final ANode doc = (ANode) d; if (doc.ndType() != NodeType.DOC) UPDOCTYPE.thrw(input, doc); docData = new MemData(data); new DataBuilder(docData).build(doc); } else if (d.str()) { // adding file(s) from a path final String docpath = string(d.atom(input)); final String nm = ctx.mprop.random(data.meta.name); final DirParser p = new DirParser(IO.get(docpath), ctx.prop); final MemBuilder b = new MemBuilder(nm, p, ctx.prop); try { docData = b.build(); } catch (final IOException e) { throw DOCERR.thrw(input, docpath); } } else { throw STRNODTYPE.thrw(input, this, d.type); } md.insert(md.meta.size, -1, docData); } // set new names, if needed final IntList pres = md.doc(); if (pres.size() == 1 && name != null) { // name is specified and a single document is added: set the name final byte[] nm = path == null ? name : concat(path, SLASH, name); md.update(pres.get(0), Data.DOC, nm); } else if (path != null) { // path is specified: replace the path of each new document for (int i = 0, is = pres.size(); i < is; i++) { final int d = pres.get(i); final byte[] old = md.text(d, true); final int p = lastIndexOf(old, '/'); final byte[] nm = p < 0 ? old : subtoken(old, p + 1); md.update(d, Data.DOC, concat(path, SLASH, nm)); } } }
/** * Extracts connection options. * * @param arg argument with options * @param root expected root element * @param ctx query context * @return options * @throws QueryException query exception */ private TokenObjMap<Object> options(final int arg, final QNm root, final QueryContext ctx) throws QueryException { // initialize token map final TokenObjMap<Object> tm = new TokenObjMap<Object>(); // argument does not exist... if (arg >= expr.length) return tm; // empty sequence... final Item it = expr[arg].item(ctx, input); if (it == null) return tm; // XQuery map: convert to internal map if (it instanceof Map) return ((Map) it).tokenJavaMap(input); // no element: convert XQuery map to internal map if (!it.type().eq(SeqType.ELM)) throw NODFUNTYPE.thrw(input, this, it.type); // parse nodes ANode node = (ANode) it; if (!node.qname().eq(root)) PARWHICH.thrw(input, node.qname()); // interpret query parameters final AxisIter ai = node.children(); while ((node = ai.next()) != null) { final QNm qn = node.qname(); if (!qn.uri().eq(Uri.uri(SQLURI))) PARWHICH.thrw(input, qn); tm.add(qn.ln(), node.children().next()); } return tm; }
/** * Returns the path nodes that are the result of this step. * * @param nodes initial path nodes * @param data data reference * @return resulting path nodes, or {@code null} if nodes cannot be evaluated */ final ObjList<PathNode> nodes(final ObjList<PathNode> nodes, final Data data) { // skip steps with predicates or different namespaces if (preds.length != 0 || data.nspaces.globalNS() == null) return null; // check restrictions on node type int kind = -1, name = 0; if (test.type != null) { kind = ANode.kind(test.type); if (kind == Data.PI) return null; if (test.test == Name.NAME) { // element/attribute test (*:ln) final Names names = kind == Data.ATTR ? data.atnindex : data.tagindex; name = names.id(((NameTest) test).ln); } else if (test.test != null && test.test != Name.ALL) { // skip namespace and standard tests return null; } } // skip axes other than descendant, child, and attribute if (axis != Axis.ATTR && axis != Axis.CHILD && axis != Axis.DESC && axis != Axis.DESCORSELF && axis != Axis.SELF) return null; final ObjList<PathNode> tmp = new ObjList<PathNode>(); for (final PathNode n : nodes) { if (axis == Axis.SELF || axis == Axis.DESCORSELF) { if (kind == -1 || kind == n.kind && (name == 0 || name == n.name)) { if (!tmp.contains(n)) tmp.add(n); } } if (axis != Axis.SELF) add(n, tmp, name, kind); } return tmp; }
@Override public FElem item(final QueryContext ctx, final InputInfo ii) throws QueryException { final int s = prepare(ctx); try { // adds in-scope namespaces final Atts ns = new Atts(); for (int i = 0; i < nspaces.size(); ++i) { ns.add(nspaces.name(i), nspaces.string(i)); } // create and check QName final QNm nm = qname(ctx, ii); final byte[] cp = nm.prefix(), cu = nm.uri(); if (eq(cp, XML) ^ eq(cu, XMLURI)) CEXML.thrw(input, cu, cp); if (eq(cu, XMLNSURI)) CEINV.thrw(input, cu); if (eq(cp, XMLNS)) CEINV.thrw(input, cp); // analyze element namespace unless it is "xml" if (!eq(cp, XML)) { // request namespace for the specified uri final byte[] uri = ctx.sc.ns.uri(cp); // check if element has a namespace if (nm.hasURI()) { // add to statically known namespaces if (!comp && (uri == null || !eq(uri, cu))) ctx.sc.ns.add(cp, cu); // add to in-scope namespaces if (!ns.contains(cp)) ns.add(cp, cu); } else { // element has no namespace: assign default uri nm.uri(uri); } } // create child and attribute nodes final Constr constr = new Constr(ii, ctx).add(expr); if (constr.errAtt) NOATTALL.thrw(input); if (constr.errNS) NONSALL.thrw(input); if (constr.duplAtt != null) (comp ? CATTDUPL : ATTDUPL).thrw(input, constr.duplAtt); if (constr.duplNS != null) DUPLNSCONS.thrw(input, constr.duplNS); // create node final FElem node = new FElem(nm, constr.children, constr.atts, ns); // add namespaces from constructor final Atts cns = constr.nspaces; for (int a = 0; a < cns.size(); ++a) { addNS(cns.name(a), cns.string(a), ns); } // update parent references of attributes and add namespaces for (int a = 0; a < constr.atts.size(); ++a) { constr.atts.get(a).parent(node); final ANode att = constr.atts.get(a); final QNm qnm = att.qname(); // skip attributes without prefixes or URIs if (!qnm.hasPrefix() || !qnm.hasURI()) continue; // skip XML namespace final byte[] apref = qnm.prefix(); if (eq(apref, XML)) continue; final byte[] auri = qnm.uri(); final byte[] npref = addNS(apref, auri, ns); if (npref != null) { constr.atts.item[a] = new FAttr(new QNm(concat(npref, COLON, qnm.local()), auri), att.string()); } } // add inherited namespaces final Atts stack = ctx.sc.ns.stack(); for (int a = stack.size() - 1; a >= 0; a--) { final byte[] pref = stack.name(a); if (!ns.contains(pref)) ns.add(pref, stack.string(a)); } // update parent references of children for (int c = 0; c < constr.children.size(); ++c) { final ANode child = constr.children.get(c).parent(node); // add inherited and remove unused namespaces if (child.type == NodeType.ELM) { if (ctx.sc.nsInherit) inherit(child, ns); if (!ctx.sc.nsPreserve) noPreserve(child); child.optimize(); } } // return generated and optimized node return node.optimize(); } finally { ctx.sc.ns.size(s); } }
/** * Adds children of a sub node. * * @param ch child nodes * @param nc node cache */ protected final void addDesc(final AxisMoreIter ch, final NodeCache nc) { for (ANode n; (n = ch.next()) != null; ) { nc.add(n.finish()); addDesc(n.children(), nc); } }
/** * Sets the parameters of a prepared statement. * * @param params parameters * @param stmt prepared statement * @throws QueryException query exception */ private void setParameters(final AxisMoreIter params, final PreparedStatement stmt) throws QueryException { int i = 0; for (ANode next; (next = params.next()) != null; ) { // Check name if (!next.qname().eq(E_PARAM)) PARWHICH.thrw(input, next.qname()); final AxisIter attrs = next.attributes(); byte[] paramType = null; boolean isNull = false; for (ANode attr; (attr = attrs.next()) != null; ) { // Attribute "type" if (eq(attr.nname(), TYPE)) paramType = attr.atom(); // Attribute "null" else if (eq(attr.nname(), NULL)) isNull = attr.atom() != null && Bln.parse(attr.atom(), input); // Not expected attribute else throw NOTEXPATTR.thrw(input, string(attr.nname())); } if (paramType == null) NOPARAMTYPE.thrw(input); final byte[] v = next.atom(); isNull |= v.length == 0; setParam(++i, stmt, paramType, isNull ? null : string(v), isNull); } }
/** * Counts the numbers of <sql:parameter/> elements. * * @param params element <sql:parameter/> * @return number of parameters */ private long countParams(final ANode params) { final AxisIter ch = params.children(); long c = ch.size(); if (c == -1) do ++c; while (ch.next() != null); return c; }