package org.basex.tests.bxapi;
import java.io.*;
import java.util.*;
import java.util.Map.*;
import javax.xml.namespace.*;
import org.basex.core.*;
import org.basex.query.*;
import org.basex.query.iter.*;
import org.basex.query.util.format.*;
import org.basex.query.value.*;
import org.basex.query.value.item.*;
import org.basex.tests.bxapi.xdm.*;
import org.basex.util.*;
import org.basex.util.hash.*;
import org.basex.util.list.*;
/**
* Wrapper for evaluating XQuery expressions.
*
* @author BaseX Team 2005-17, BSD License
* @author Christian Gruen
*/
public final class XQuery implements Iterable<XdmItem>, Closeable {
/** Query processor. */
private final QueryProcessor qp;
/** Query iterator. */
private Iter ir;
/**
* Constructor.
* @param query query
* @param context database context
*/
public XQuery(final String query, final Context context) {
qp = new QueryProcessor(query, context);
}
/**
* Binds an initial context.
* @param value context value to be bound
* @return self reference
* @throws XQueryException exception
*/
public XQuery context(final XdmValue value) {
qp.context(value.internal());
return this;
}
/**
* Binds a variable.
* @param key key
* @param value value to be bound
* @return self reference
* @throws XQueryException exception
*/
public XQuery bind(final String key, final XdmValue value) {
try {
qp.bind(key, value.internal());
return this;
} catch(final QueryException ex) {
throw new XQueryException(ex);
}
}
/**
* Declares a namespace.
* A namespace is undeclared if the {@code uri} is an empty string.
* The default element namespaces is set if the {@code prefix} is empty.
* @param prefix namespace prefix
* @param uri namespace uri
* @return self reference
*/
public XQuery namespace(final String prefix, final String uri) {
try {
qp.namespace(prefix, uri);
return this;
} catch(final QueryException ex) {
throw new XQueryException(ex);
}
}
/**
* Declares a decimal format.
* @param name qname
* @param map format
* @return self reference
*/
public XQuery decimalFormat(final QName name, final HashMap<String, String> map) {
try {
final TokenMap tm = new TokenMap();
for(final Entry<String, String> e : map.entrySet()) {
tm.put(Token.token(e.getKey()), Token.token(e.getValue()));
}
qp.sc.decFormats.put(new QNm(name).id(), new DecFormatter(tm, null));
return this;
} catch(final QueryException ex) {
throw new XQueryException(ex);
}
}
/**
* Adds a collection.
* @param name name of the collection (can be empty string)
* @param paths document paths
* @throws XQueryException exception
*/
public void addCollection(final String name, final String[] paths) {
if(name == null) System.out.println(name);
final StringList sl = new StringList();
for(final String p : paths) sl.add(p);
try {
qp.qc.resources.addCollection(name, sl.toArray(), qp.sc);
} catch(final QueryException ex) {
throw new XQueryException(ex);
}
}
/**
* Returns a collection of document nodes.
* @param name name of the collection (empty string for default collection)
* @return reference
* @throws XQueryException exception
*/
public XdmValue collection(final String name) {
try {
return XdmValue.get(qp.qc.resources.collection(name.isEmpty() ? null :
new QueryInput(name, qp.sc), null));
} catch(final QueryException ex) {
throw new XQueryException(ex);
}
}
/**
* Returns a document node.
* @param name name of the document
* @return reference
* @throws XQueryException exception
*/
public XdmValue document(final String name) {
try {
return XdmItem.get(qp.qc.resources.doc(new QueryInput(name, qp.sc), null));
} catch(final QueryException ex) {
throw new XQueryException(ex);
}
}
/**
* Adds a document.
* @param name name of the document (can be {@code null})
* @param path document path
* @throws XQueryException exception
*/
public void addDocument(final String name, final String path) {
try {
qp.qc.resources.addDoc(name, path, qp.sc);
} catch(final QueryException ex) {
throw new XQueryException(ex);
}
}
/**
* Adds a resource.
* @param name name of the collection
* @param strings document path and encoding
* @throws XQueryException exception
*/
public void addResource(final String name, final String... strings) {
qp.qc.resources.addResource(name, strings);
}
/**
* Adds a module.
* @param uri module uri
* @param file file reference
* @throws XQueryException exception
*/
public void addModule(final String uri, final String file) {
qp.module(uri, file);
}
/**
* Sets the base URI.
* @param base base URI
* @return self reference
* @throws XQueryException exception
*/
public XQuery baseURI(final String base) {
qp.sc.baseURI(base.equals("#UNDEFINED") ? null : base);
return this;
}
/**
* Returns the next item, or {@code null} if all items have been returned.
* @return next result item
* @throws XQueryException exception
*/
public XdmItem next() {
Item it = null;
try {
if(ir == null) ir = qp.iter();
it = ir.next();
return it != null ? XdmItem.get(it) : null;
} catch(final QueryException ex) {
throw new XQueryException(ex);
} finally {
if(it == null) qp.close();
}
}
/**
* Returns the result value.
* @return result value
* @throws XQueryException exception
*/
public XdmValue value() {
try {
final Value v = qp.value();
v.materialize(null);
return XdmValue.get(v);
} catch(final QueryException ex) {
throw new XQueryException(ex);
} finally {
qp.close();
}
}
/**
* Returns the query processor.
* @return query processor
*/
public QueryProcessor qp() {
return qp;
}
@Override
public void close() {
qp.close();
}
@Override
public Iterator<XdmItem> iterator() {
return new Iterator<XdmItem>() {
/** Current item. */
private XdmItem next;
@Override
public boolean hasNext() {
if(next == null) next = XQuery.this.next();
return next != null;
}
@Override
public XdmItem next() {
final XdmItem it = hasNext() ? next : null;
next = null;
return it;
}
@Override
public void remove() {
throw Util.notExpected();
}
};
}
/**
* Returns the string representation of a query result.
* @param query query string
* @param value optional context
* @param context database context
* @return optional expected test suite result
*/
public static String string(final String query, final XdmValue value, final Context context) {
final XdmValue xv = new XQuery(query, context).context(value).value();
return xv.size() == 0 ? "" : xv.getString();
}
@Override
public String toString() {
return qp.query();
}
}