diff --git a/elemental-parent/pom.xml b/elemental-parent/pom.xml
index c94611c7a6..fb6d87cc18 100644
--- a/elemental-parent/pom.xml
+++ b/elemental-parent/pom.xml
@@ -374,9 +374,9 @@
3.4.0
- com.code54.mojo
- buildversion-plugin
- 1.0.3
+ com.evolvedbinary.maven.plugins
+ buildversion-maven-plugin
+ 2.0.0
org.apache.maven.plugins
@@ -620,8 +620,8 @@
- com.code54.mojo
- buildversion-plugin
+ com.evolvedbinary.maven.plugins
+ buildversion-maven-plugin
validate
@@ -814,19 +814,4 @@
-
-
- clojars.org
- https://clojars.org/repo
-
-
-
-
-
- central-ossrh-staging
- Central Portal - OSSRH Staging API
- https://ossrh-staging-api.central.sonatype.com/service/local/staging/deploy/maven2/
-
-
-
diff --git a/exist-core/src/main/java/org/exist/Namespaces.java b/exist-core/src/main/java/org/exist/Namespaces.java
index ace3469b7f..e134a7b786 100644
--- a/exist-core/src/main/java/org/exist/Namespaces.java
+++ b/exist-core/src/main/java/org/exist/Namespaces.java
@@ -60,6 +60,7 @@ public interface Namespaces {
String DTD_NS = XMLConstants.XML_DTD_NS_URI;
String SCHEMA_NS = XMLConstants.W3C_XML_SCHEMA_NS_URI;
+ String SCHEMA_NS_PREFIX = "xs";
String SCHEMA_DATATYPES_NS = "http://www.w3.org/2001/XMLSchema-datatypes";
String SCHEMA_INSTANCE_NS = XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI;
diff --git a/exist-core/src/main/java/org/exist/client/CommandlineOptions.java b/exist-core/src/main/java/org/exist/client/CommandlineOptions.java
index 060e5881b0..0db5b0616a 100644
--- a/exist-core/src/main/java/org/exist/client/CommandlineOptions.java
+++ b/exist-core/src/main/java/org/exist/client/CommandlineOptions.java
@@ -83,6 +83,10 @@ public class CommandlineOptions {
.description("do not make embedded mode available")
.defaultValue(false)
.build();
+ private static final Argument noAutoDeployArg = optionArgument("-a", "--no-auto-deploy")
+ .description("Disable auto-deployment of EXPath Packages")
+ .defaultValue(false)
+ .build();
/* gui arguments */
@@ -168,7 +172,7 @@ private static Optional optUri(final ParsedArguments parsedArguments,
public static CommandlineOptions parse(final String[] args) throws ArgumentException, URISyntaxException {
final ParsedArguments arguments = CommandLineParser
- .withArguments(userArg, passwordArg, useSslArg, embeddedArg, embeddedConfigArg, noEmbeddedModeArg)
+ .withArguments(userArg, passwordArg, useSslArg, embeddedArg, embeddedConfigArg, noEmbeddedModeArg, noAutoDeployArg)
.andArguments(noGuiArg, guiQueryDialogArg)
.andArguments(mkColArg, rmColArg, setColArg)
.andArguments(parseDocsArg, getDocArg, rmDocArg)
@@ -189,6 +193,7 @@ public static CommandlineOptions parse(final String[] args) throws ArgumentExcep
final boolean embedded = getBool(arguments, embeddedArg);
final Optional embeddedConfig = getPathOpt(arguments, embeddedConfigArg);
final boolean noEmbeddedMode = getBool(arguments, noEmbeddedModeArg);
+ final boolean noAutoDeploy = getBool(arguments, noAutoDeployArg);
final boolean startGUI = !getBool(arguments, noGuiArg);
final boolean openQueryGUI = getBool(arguments, guiQueryDialogArg);
@@ -233,6 +238,7 @@ public static CommandlineOptions parse(final String[] args) throws ArgumentExcep
embedded,
embeddedConfig,
noEmbeddedMode,
+ noAutoDeploy,
startGUI,
openQueryGUI,
mkCol,
@@ -252,7 +258,7 @@ public static CommandlineOptions parse(final String[] args) throws ArgumentExcep
);
}
- public CommandlineOptions(boolean quiet, boolean verbose, Optional outputFile, Map options, Optional username, Optional password, boolean useSSL, boolean embedded, Optional embeddedConfig, boolean noEmbeddedMode, boolean startGUI, boolean openQueryGUI, Optional mkCol, Optional rmCol, Optional setCol, List parseDocs, Optional getDoc, Optional rmDoc, Optional xpath, List queryFiles, Optional howManyResults, Optional traceQueriesFile, Optional setDoc, Optional xupdateFile, boolean reindex, boolean reindexRecurse) {
+ public CommandlineOptions(boolean quiet, boolean verbose, Optional outputFile, Map options, Optional username, Optional password, boolean useSSL, boolean embedded, Optional embeddedConfig, boolean noEmbeddedMode, boolean noAutoDeploy, boolean startGUI, boolean openQueryGUI, Optional mkCol, Optional rmCol, Optional setCol, List parseDocs, Optional getDoc, Optional rmDoc, Optional xpath, List queryFiles, Optional howManyResults, Optional traceQueriesFile, Optional setDoc, Optional xupdateFile, boolean reindex, boolean reindexRecurse) {
this.quiet = quiet;
this.verbose = verbose;
this.outputFile = outputFile;
@@ -263,6 +269,7 @@ public CommandlineOptions(boolean quiet, boolean verbose, Optional outputF
this.embedded = embedded;
this.embeddedConfig = embeddedConfig;
this.noEmbeddedMode = noEmbeddedMode;
+ this.noAutoDeploy = noAutoDeploy;
this.startGUI = startGUI;
this.openQueryGUI = openQueryGUI;
this.mkCol = mkCol;
@@ -292,6 +299,7 @@ public CommandlineOptions(boolean quiet, boolean verbose, Optional outputF
final boolean embedded;
final Optional embeddedConfig;
final boolean noEmbeddedMode;
+ final boolean noAutoDeploy;
final boolean startGUI;
final boolean openQueryGUI;
diff --git a/exist-core/src/main/java/org/exist/client/InteractiveClient.java b/exist-core/src/main/java/org/exist/client/InteractiveClient.java
index e9b39f175f..7b4ac352af 100644
--- a/exist-core/src/main/java/org/exist/client/InteractiveClient.java
+++ b/exist-core/src/main/java/org/exist/client/InteractiveClient.java
@@ -147,6 +147,7 @@ public class InteractiveClient {
public static final String CREATE_DATABASE = "create-database";
public static final String LOCAL_MODE = "local-mode-opt";
public static final String NO_EMBED_MODE = "NO_EMBED_MODE";
+ public static final String NO_AUTO_DEPLOY = "no-autodeploy";
// values
protected static final String EDIT_CMD = "emacsclient -t $file";
@@ -155,6 +156,7 @@ public class InteractiveClient {
protected static final String SSL_ENABLE_DEFAULT = "FALSE";
protected static final String LOCAL_MODE_DEFAULT = "FALSE";
protected static final String NO_EMBED_MODE_DEFAULT = "FALSE";
+ protected static final String NO_AUTO_DEPLOY_DEFAULT = "FALSE";
protected static final String USER_DEFAULT = SecurityManager.DBA_USER;
protected static final String driver = "org.exist.xmldb.DatabaseImpl";
@@ -173,6 +175,7 @@ public class InteractiveClient {
defaultProps.setProperty(PERMISSIONS, "false");
defaultProps.setProperty(EXPAND_XINCLUDES, "true");
defaultProps.setProperty(SSL_ENABLE, SSL_ENABLE_DEFAULT);
+ defaultProps.setProperty(NO_AUTO_DEPLOY, NO_AUTO_DEPLOY_DEFAULT);
}
protected static final int colSizes[] = new int[]{10, 10, 10, -1};
@@ -333,6 +336,7 @@ protected void connect() throws Exception {
// Configure database
database.setProperty(CREATE_DATABASE, "true");
database.setProperty(SSL_ENABLE, properties.getProperty(SSL_ENABLE));
+ database.setProperty(NO_AUTO_DEPLOY, properties.getProperty(NO_AUTO_DEPLOY));
// secure empty configuration
final String configProp = properties.getProperty(InteractiveClient.CONFIGURATION);
@@ -1971,6 +1975,9 @@ protected void setPropertiesFromCommandLine(final CommandlineOptions options, fi
if(options.noEmbeddedMode) {
props.setProperty(NO_EMBED_MODE, "TRUE");
}
+ if (options.noAutoDeploy) {
+ props.setProperty(NO_AUTO_DEPLOY, "TRUE");
+ }
}
/**
diff --git a/exist-core/src/main/java/org/exist/collections/MutableCollection.java b/exist-core/src/main/java/org/exist/collections/MutableCollection.java
index 59ed38b500..7975d5350b 100644
--- a/exist-core/src/main/java/org/exist/collections/MutableCollection.java
+++ b/exist-core/src/main/java/org/exist/collections/MutableCollection.java
@@ -481,7 +481,7 @@ public MutableDocumentSet allDocs(final DBBroker broker, final MutableDocumentSe
if(recursive && subColls != null) {
// process the child collections
for(final XmldbURI subCol : subColls) {
- try(final Collection child = broker.openCollection(subCol, NO_LOCK)) { // NOTE: the recursive call below to child.addDocs will take a lock
+ try(final Collection child = broker.openCollection(subCol, INTENTION_READ)) { // NOTE: the recursive call below to child.addDocs will take a lock
//A collection may have been removed in the meantime, so check first
if(child != null) {
child.allDocs(broker, docs, recursive, lockMap);
diff --git a/exist-core/src/main/java/org/exist/http/RESTServer.java b/exist-core/src/main/java/org/exist/http/RESTServer.java
index d98d9f5998..f3e4a809e5 100644
--- a/exist-core/src/main/java/org/exist/http/RESTServer.java
+++ b/exist-core/src/main/java/org/exist/http/RESTServer.java
@@ -107,7 +107,6 @@
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.AttributesImpl;
-import org.xml.sax.helpers.XMLFilterImpl;
import xyz.elemental.mediatype.MediaType;
import xyz.elemental.mediatype.MediaTypeResolver;
@@ -336,17 +335,37 @@ public void doGet(final DBBroker broker, final Txn transaction, final HttpServle
query = getParameter(request, Query);
}
}
- final String _var = getParameter(request, Variables);
- List /**/ namespaces = null;
- ElementImpl variables = null;
+
+ @Nullable final String _contextItem = getParameter(request, Context_Item);
+ @Nullable ElementImpl contextItemParam = null;
+ try {
+ if (_contextItem != null) {
+ contextItemParam = parseXML(broker.getBrokerPool(), _contextItem);
+ }
+ } catch (final SAXException e) {
+ final XPathException x = new XPathException(contextItemParam != null ? contextItemParam.getExpression() : null, e.toString());
+ writeXPathException(response, HttpServletResponse.SC_BAD_REQUEST, UTF_8.name(), query, path, x);
+ }
+
+ @Nullable final String _defaultCollection = getParameter(request, Default_Collection);
+ @Nullable ElementImpl defaultCollectionParam = null;
+ try {
+ if (_defaultCollection != null) {
+ defaultCollectionParam = parseXML(broker.getBrokerPool(), _defaultCollection);
+ }
+ } catch (final SAXException e) {
+ final XPathException x = new XPathException(defaultCollectionParam != null ? defaultCollectionParam.getExpression() : null, e.toString());
+ writeXPathException(response, HttpServletResponse.SC_BAD_REQUEST, UTF_8.name(), query, path, x);
+ }
+
+ @Nullable final String _var = getParameter(request, Variables);
+ @Nullable ElementImpl variablesParam = null;
try {
if (_var != null) {
- final NamespaceExtractor nsExtractor = new NamespaceExtractor();
- variables = parseXML(broker.getBrokerPool(), _var, nsExtractor);
- namespaces = nsExtractor.getNamespaces();
+ variablesParam = parseXML(broker.getBrokerPool(), _var);
}
} catch (final SAXException e) {
- final XPathException x = new XPathException(variables != null ? variables.getExpression() : null, e.toString());
+ final XPathException x = new XPathException(variablesParam != null ? variablesParam.getExpression() : null, e.toString());
writeXPathException(response, HttpServletResponse.SC_BAD_REQUEST, UTF_8.name(), query, path, x);
}
@@ -421,7 +440,7 @@ public void doGet(final DBBroker broker, final Txn transaction, final HttpServle
if (query != null) {
// query parameter specified, search method does all the rest of the work
try {
- search(broker, transaction, query, path, namespaces, variables, howmany, start, typed, outputProperties,
+ search(broker, transaction, query, path, null, contextItemParam, defaultCollectionParam, variablesParam, howmany, start, typed, outputProperties,
wrap, cache, request, response);
} catch (final XPathException e) {
@@ -766,15 +785,16 @@ public void doPost(final DBBroker broker, final Txn transaction, final HttpServl
int howmany = 10;
int start = 1;
boolean typed = false;
- ElementImpl variables = null;
+ @Nullable ElementImpl contextItemParam = null;
+ @Nullable ElementImpl defaultCollectionParam = null;
+ @Nullable ElementImpl variablesParam = null;
boolean enclose = true;
boolean cache = false;
String query = null;
try {
final String content = getRequestContent(request);
- final NamespaceExtractor nsExtractor = new NamespaceExtractor();
- final ElementImpl root = parseXML(broker.getBrokerPool(), content, nsExtractor);
+ final ElementImpl root = parseXML(broker.getBrokerPool(), content);
final String rootNS = root.getNamespaceURI();
if (rootNS != null && rootNS.equals(Namespaces.EXIST_NS)) {
@@ -852,8 +872,14 @@ public void doPost(final DBBroker broker, final Txn transaction, final HttpServl
}
query = buf.toString();
+ } else if (Context_Item.xmlKey().equals(child.getLocalName())) {
+ contextItemParam = (ElementImpl) child;
+
+ } else if (Default_Collection.xmlKey().equals(child.getLocalName())) {
+ defaultCollectionParam = (ElementImpl) child;
+
} else if (Variables.xmlKey().equals(child.getLocalName())) {
- variables = (ElementImpl) child;
+ variablesParam = (ElementImpl) child;
} else if (Properties.xmlKey().equals(child.getLocalName())) {
Node node = child.getFirstChild();
@@ -882,7 +908,7 @@ public void doPost(final DBBroker broker, final Txn transaction, final HttpServl
if (query != null) {
try {
- search(broker, transaction, query, path, nsExtractor.getNamespaces(), variables,
+ search(broker, transaction, query, path, null, contextItemParam, defaultCollectionParam, variablesParam,
howmany, start, typed, outputProperties,
enclose, cache, request, response);
} catch (final XPathException e) {
@@ -979,22 +1005,19 @@ public void doPost(final DBBroker broker, final Txn transaction, final HttpServl
}
}
- private ElementImpl parseXML(final BrokerPool pool, final String content,
- final NamespaceExtractor nsExtractor)
- throws SAXException, IOException {
+ private ElementImpl parseXML(final BrokerPool pool, final String content) throws SAXException, IOException {
final InputSource src = new InputSource(new StringReader(content));
final XMLReaderPool parserPool = pool.getParserPool();
XMLReader reader = null;
try {
reader = parserPool.borrowXMLReader();
final SAXAdapter adapter = new SAXAdapter((Expression) null);
- nsExtractor.setContentHandler(adapter);
+
+ reader.setContentHandler(adapter);
reader.setProperty(Namespaces.SAX_LEXICAL_HANDLER, adapter);
- nsExtractor.setParent(reader);
- nsExtractor.parse(src);
+ reader.parse(src);
final Document doc = adapter.getDocument();
-
return (ElementImpl) doc.getDocumentElement();
} finally {
if (reader != null) {
@@ -1003,42 +1026,14 @@ private ElementImpl parseXML(final BrokerPool pool, final String content,
}
}
- private class NamespaceExtractor extends XMLFilterImpl {
-
- final List namespaces = new ArrayList<>();
-
- @Override
- public void startPrefixMapping(final String prefix, final String uri)
- throws SAXException {
- if (!Namespaces.EXIST_NS.equals(uri)) {
- final Namespace ns = new Namespace(prefix, uri);
- namespaces.add(ns);
- }
- super.startPrefixMapping(prefix, uri);
- }
-
- public List getNamespaces() {
- return namespaces;
- }
- }
-
public static class Namespace {
-
- private final String prefix;
- private final String uri;
+ final String prefix;
+ final String uri;
public Namespace(final String prefix, final String uri) {
this.prefix = prefix;
this.uri = uri;
}
-
- public String getPrefix() {
- return prefix;
- }
-
- public String getUri() {
- return uri;
- }
}
/**
@@ -1309,7 +1304,9 @@ private String getRequestContent(final HttpServletRequest request) throws IOExce
* @param query the XQuery
* @param path the path of the request
* @param namespaces any XQuery namespace bindings
- * @param variables any XQuery variable bindings
+ * @param contextItemParam optional XQuery Context Item
+ * @param defaultCollectionParam optional XQuery Default Collection
+ * @param variablesParam any XQuery variable bindings
* @param howmany the number of items in the results to return
* @param start the start position in the results to return
* @param typed whether the result nodes should be typed
@@ -1324,11 +1321,13 @@ private String getRequestContent(final HttpServletRequest request) throws IOExce
* @throws XPathException if the XQuery raises an error
*/
protected void search(final DBBroker broker, final Txn transaction, final String query,
- final String path, final List namespaces,
- final ElementImpl variables, final int howmany, final int start,
- final boolean typed, final Properties outputProperties,
- final boolean wrap, final boolean cache,
- final HttpServletRequest request,
+ final String path, @Nullable final List namespaces,
+ @Nullable final ElementImpl contextItemParam,
+ @Nullable final ElementImpl defaultCollectionParam,
+ @Nullable final ElementImpl variablesParam, final int howmany,
+ final int start, final boolean typed,
+ final Properties outputProperties, final boolean wrap,
+ final boolean cache, final HttpServletRequest request,
final HttpServletResponse response) throws BadRequestException,
PermissionDeniedException, XPathException {
@@ -1398,10 +1397,14 @@ protected void search(final DBBroker broker, final Txn transaction, final String
compilationTime = 0;
}
- declareVariables(context, variables, request, response);
+ setupDefaultCollection(context, defaultCollectionParam);
+ declareVariables(context, variablesParam, request, response);
+
+ @Nullable final Item contextItem = extractContextItem(contextItemParam);
+ final Sequence contextSequence = contextItem != null ? new ValueSequence(contextItem) : null;
final long executeStart = System.currentTimeMillis();
- final Sequence resultSequence = xquery.execute(broker, compiled, null, outputProperties);
+ final Sequence resultSequence = xquery.execute(broker, compiled, contextSequence, outputProperties);
final long executionTime = System.currentTimeMillis() - executeStart;
if (LOG.isDebugEnabled()) {
@@ -1430,35 +1433,80 @@ protected void search(final DBBroker broker, final Txn transaction, final String
}
}
- private void declareNamespaces(final XQueryContext context,
- final List namespaces) throws XPathException {
-
+ private void declareNamespaces(final XQueryContext context, @Nullable final List namespaces) throws XPathException {
if (namespaces == null) {
return;
}
for (final Namespace ns : namespaces) {
- context.declareNamespace(ns.getPrefix(), ns.getUri());
+ context.declareNamespace(ns.prefix, ns.uri);
+ }
+ }
+
+ /**
+ * Extract the Context Item from the Element parameter.
+ *
+ * @param contextItem a parameter specifying the Context Item for the XQuery, or null
+ *
+ * @throws XPathException if an error occurs extracting the Context Item.
+ */
+ private @Nullable Item extractContextItem(@Nullable final ElementImpl contextItem) throws XPathException {
+ if (contextItem == null) {
+ return null;
+ }
+
+ @Nullable final NodeImpl value = contextItem.getFirstChild(new NameTest(Type.ELEMENT, Marshaller.VALUE_ELEMENT_QNAME));
+ if (value == null) {
+ return null;
+ }
+
+ try {
+ return Marshaller.demarshallValue(null, (ElementImpl) value);
+ } catch (final XMLStreamException xe) {
+ throw new XPathException((Expression) null, xe.toString());
+ }
+ }
+
+ private void setupDefaultCollection(final XQueryContext context, @Nullable final ElementImpl defaultCollectionParam) throws XPathException {
+ if (defaultCollectionParam == null) {
+ return;
+ }
+
+ @Nullable final NodeImpl value = defaultCollectionParam.getFirstChild(new NameTest(Type.ELEMENT, Marshaller.SEQUENCE_ELEMENT_QNAME));
+ if (value == null) {
+ return;
+ }
+
+ try {
+ @Nullable final Sequence sequence = Marshaller.demarshall(context, value);
+ if (sequence != null) {
+ context.addDynamicallyAvailableCollection("", (broker, txn, uri) -> sequence);
+ }
+ } catch (final XMLStreamException xe) {
+ throw new XPathException((Expression) null, xe.toString());
}
}
/**
* Pass the request, response and session objects to the XQuery context.
*
- * @param context
- * @param request
- * @param response
- * @throws XPathException
+ * @param context the context for the XQuery
+ * @param variables variable bindings for the XQuery, or null
+ * @param request the HTTP request
+ * @param response the HTTP response
+ *
+ * @throws XPathException if an error occurs declaring variables
*/
private HttpRequestWrapper declareVariables(final XQueryContext context,
- final ElementImpl variables, final HttpServletRequest request,
+ @Nullable final ElementImpl variables,
+ final HttpServletRequest request,
final HttpServletResponse response) throws XPathException {
final HttpRequestWrapper reqw = new HttpRequestWrapper(request, formEncoding, containerEncoding);
final ResponseWrapper respw = new HttpResponseWrapper(response);
context.setHttpContext(new XQueryContext.HttpContext(reqw, respw));
- //enable EXQuery Request Module (if present)
+ // enable EXQuery Request Module (if present)
try {
if(xqueryContextExqueryRequestAttribute != null && cstrHttpServletRequestAdapter != null) {
final HttpRequest exqueryRequestAdapter = cstrHttpServletRequestAdapter.apply(request, () -> (String)context.getBroker().getConfiguration().getProperty(Configuration.BINARY_CACHE_CLASS_PROPERTY));
@@ -1529,7 +1577,7 @@ private void declareExternalAndXQJVariables(final XQueryContext context,
}
// get serialized sequence
- final NodeImpl value = variable.getFirstChild(new NameTest(Type.ELEMENT, Marshaller.SEQUENCE_ELEMENT_QNAME));
+ @Nullable final NodeImpl value = variable.getFirstChild(new NameTest(Type.ELEMENT, Marshaller.SEQUENCE_ELEMENT_QNAME));
final Sequence sequence;
try {
sequence = value == null ? Sequence.EMPTY_SEQUENCE : Marshaller.demarshall(context, value);
@@ -2050,10 +2098,10 @@ protected void writeCollection(final HttpServletResponse response,
serializer.setOutput(writer, defaultProperties);
serializer.startDocument();
- serializer.startPrefixMapping("exist", Namespaces.EXIST_NS);
+ serializer.startPrefixMapping(Namespaces.EXIST_NS_PREFIX, Namespaces.EXIST_NS);
if (wrap) {
- serializer.startElement(Namespaces.EXIST_NS, "result", "exist:result", null);
+ serializer.startElement(Namespaces.EXIST_NS, "result", Namespaces.EXIST_NS_PREFIX + ":result", null);
}
final AttributesImpl attrs = new AttributesImpl();
@@ -2073,8 +2121,7 @@ protected void writeCollection(final HttpServletResponse response,
addPermissionAttributes(attrs, collection.getPermissionsNoLock());
- serializer.startElement(Namespaces.EXIST_NS, "collection",
- "exist:collection", attrs);
+ serializer.startElement(Namespaces.EXIST_NS, "collection", Namespaces.EXIST_NS_PREFIX + ":collection", attrs);
for (final Iterator i = collection.collectionIterator(broker); i.hasNext();) {
final XmldbURI child = i.next();
@@ -2097,8 +2144,8 @@ protected void writeCollection(final HttpServletResponse response,
}
addPermissionAttributes(attrs, childCollection.getPermissionsNoLock());
- serializer.startElement(Namespaces.EXIST_NS, "collection", "exist:collection", attrs);
- serializer.endElement(Namespaces.EXIST_NS, "collection", "exist:collection");
+ serializer.startElement(Namespaces.EXIST_NS, "collection", Namespaces.EXIST_NS_PREFIX + ":collection", attrs);
+ serializer.endElement(Namespaces.EXIST_NS, "collection", Namespaces.EXIST_NS_PREFIX + ":collection");
}
}
@@ -2135,15 +2182,15 @@ protected void writeCollection(final HttpServletResponse response,
}
addPermissionAttributes(attrs, doc.getPermissions());
- serializer.startElement(Namespaces.EXIST_NS, "resource", "exist:resource", attrs);
- serializer.endElement(Namespaces.EXIST_NS, "resource", "exist:resource");
+ serializer.startElement(Namespaces.EXIST_NS, "resource", Namespaces.EXIST_NS_PREFIX + ":resource", attrs);
+ serializer.endElement(Namespaces.EXIST_NS, "resource", Namespaces.EXIST_NS_PREFIX + ":resource");
}
}
- serializer.endElement(Namespaces.EXIST_NS, "collection", "exist:collection");
+ serializer.endElement(Namespaces.EXIST_NS, "collection", Namespaces.EXIST_NS_PREFIX + ":collection");
if (wrap) {
- serializer.endElement(Namespaces.EXIST_NS, "result", "exist:result");
+ serializer.endElement(Namespaces.EXIST_NS, "result", Namespaces.EXIST_NS_PREFIX + ":result");
}
serializer.endDocument();
diff --git a/exist-core/src/main/java/org/exist/http/RESTServerParameter.java b/exist-core/src/main/java/org/exist/http/RESTServerParameter.java
index 31afa0bd49..1fea532519 100644
--- a/exist-core/src/main/java/org/exist/http/RESTServerParameter.java
+++ b/exist-core/src/main/java/org/exist/http/RESTServerParameter.java
@@ -25,7 +25,7 @@
* Enumeration of each Parameter
* used by the RESTServer
*
- * @author Adam Retter
+ * @author Adam Retter
*/
enum RESTServerParameter {
@@ -76,12 +76,44 @@ enum RESTServerParameter {
* encoding? = string
* method? = string>
* (exist:text,
+ * exist:context-item?,
+ * exist:default-collection?
* exist:variables?,
* exist:properties?)
*
*/
Query,
+ /**
+ * Can be used in either the Query String of a GET request
+ * or in the body of a POST request to specify a value
+ * for the XQuery Context item.
+ *
+ * Contexts: GET, POST
+ *
+ * The value of this prarameter, is an XML element with the format
+ *
+ *
+ * (sx:value)
+ *
+ */
+ Context_Item,
+
+ /**
+ * Can be used in either the Query String of a GET request
+ * or in the body of a POST request to specify the values
+ * for the Default Collection of the XQuery Dynamic Context.
+ *
+ * Contexts: GET, POST
+ *
+ * The value of this prarameter, is an XML element with the format
+ *
+ *
+ * (sx:sequence)
+ *
+ */
+ Default_Collection,
+
/**
* Can be used in either the Query String of a GET request
* or in the body of a POST request to specify values for
diff --git a/exist-core/src/main/java/org/exist/jetty/JettyStart.java b/exist-core/src/main/java/org/exist/jetty/JettyStart.java
index ce5e23e20a..a524dd8470 100644
--- a/exist-core/src/main/java/org/exist/jetty/JettyStart.java
+++ b/exist-core/src/main/java/org/exist/jetty/JettyStart.java
@@ -65,12 +65,18 @@
import org.exist.storage.BrokerPool;
import org.exist.util.ConfigurationHelper;
import org.exist.util.FileUtils;
+import org.exist.util.OSUtil;
import org.exist.util.SingleInstanceConfiguration;
+import org.exist.util.SystemExitCodes;
import org.exist.validation.XmlLibraryChecker;
import org.exist.xmldb.DatabaseImpl;
import org.exist.xmldb.ShutdownListener;
import org.xmldb.api.DatabaseManager;
import org.xmldb.api.base.Database;
+import se.softhouse.jargo.Argument;
+import se.softhouse.jargo.ArgumentException;
+import se.softhouse.jargo.CommandLineParser;
+import se.softhouse.jargo.ParsedArguments;
import java.io.IOException;
import java.io.InputStream;
@@ -83,7 +89,10 @@
import java.util.*;
import java.util.stream.Collectors;
+import static org.exist.repo.AutoDeploymentTrigger.AUTODEPLOY_PROPERTY;
+import static org.exist.util.ArgumentUtil.getBool;
import static org.exist.util.ThreadUtils.newGlobalThread;
+import static se.softhouse.jargo.Arguments.*;
/**
* This class provides a main method to start Jetty with eXist. It registers shutdown
@@ -108,6 +117,19 @@ public class JettyStart extends Observable implements LifeCycle.Listener {
private final static int STATUS_STOPPING = 2;
private final static int STATUS_STOPPED = 3;
+ /* general arguments */
+ private static final Argument jettyConfigFilePath = stringArgument()
+ .description("Path to Jetty Config File")
+ .build();
+ private static final Argument existConfigFilePath = stringArgument()
+ .description("Path to Elemental Config File")
+ .build();
+ private static final Argument noAutoDeployArg = optionArgument("-a", "--no-auto-deploy")
+ .description("Disable auto-deployment of EXPath Packages")
+ .defaultValue(false)
+ .build();
+ private static final Argument> helpArg = helpArgument("-h", "--help");
+
@GuardedBy("this") private int status = STATUS_STOPPED;
@GuardedBy("this") private Optional shutdownHookThread = Optional.empty();
@GuardedBy("this") private int primaryPort = 8080;
@@ -116,11 +138,26 @@ public class JettyStart extends Observable implements LifeCycle.Listener {
public static void main(final String[] args) {
try {
CompatibleJavaVersionCheck.checkForCompatibleJavaVersion();
+
+ final ParsedArguments arguments = CommandLineParser
+ .withArguments(jettyConfigFilePath, existConfigFilePath)
+ .andArguments(noAutoDeployArg, helpArg)
+ .programName("startup" + (OSUtil.IS_WINDOWS ? ".bat" : ".sh"))
+ .parse(args);
+
+ final boolean noAutoDeploy = getBool(arguments, noAutoDeployArg);
+ if (noAutoDeploy) {
+ System.setProperty(AUTODEPLOY_PROPERTY, "off");
+ }
+
} catch (final StartException e) {
if (e.getMessage() != null && !e.getMessage().isEmpty()) {
System.err.println(e.getMessage());
}
System.exit(e.getErrorCode());
+ } catch (final ArgumentException e) {
+ System.out.println(e.getMessageAndUsage());
+ System.exit(SystemExitCodes.INVALID_ARGUMENT_EXIT_CODE);
}
final JettyStart start = new JettyStart();
diff --git a/exist-core/src/main/java/org/exist/storage/serializers/Serializer.java b/exist-core/src/main/java/org/exist/storage/serializers/Serializer.java
index 628927d7ad..bf5a5472a9 100644
--- a/exist-core/src/main/java/org/exist/storage/serializers/Serializer.java
+++ b/exist-core/src/main/java/org/exist/storage/serializers/Serializer.java
@@ -52,6 +52,7 @@
import java.util.*;
import javax.annotation.Nullable;
+import javax.xml.XMLConstants;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Source;
import javax.xml.transform.Templates;
@@ -1080,14 +1081,17 @@ public void toSAX(final Sequence seq, int start, final int count, final boolean
attrs.addAttribute(ATTR_SESSION_ID, outputProperties.getProperty(PROPERTY_SESSION_ID));
}
attrs.addAttribute(ATTR_COMPILATION_TIME_QNAME, Long.toString(compilationTime));
- attrs.addAttribute(ATTR_EXECUTION_TIME_QNAME, Long.toString(compilationTime));
+ attrs.addAttribute(ATTR_EXECUTION_TIME_QNAME, Long.toString(executionTime));
if (!documentStarted) {
receiver.startDocument();
documentStarted = true;
}
if (wrap) {
- receiver.startPrefixMapping("exist", Namespaces.EXIST_NS);
+ receiver.startPrefixMapping(Namespaces.EXIST_NS_PREFIX, Namespaces.EXIST_NS);
+ if (typed) {
+ receiver.startPrefixMapping(Namespaces.SCHEMA_NS_PREFIX, Namespaces.SCHEMA_NS);
+ }
receiver.startElement(ELEM_RESULT_QNAME, attrs);
}
@@ -1102,7 +1106,10 @@ public void toSAX(final Sequence seq, int start, final int count, final boolean
if (wrap) {
receiver.endElement(ELEM_RESULT_QNAME);
- receiver.endPrefixMapping("exist");
+ if (typed) {
+ receiver.endPrefixMapping(Namespaces.SCHEMA_NS_PREFIX);
+ }
+ receiver.endPrefixMapping(Namespaces.EXIST_NS_PREFIX);
}
receiver.endDocument();
}
@@ -1174,7 +1181,10 @@ public void toSAX(final Item item, final boolean wrap, final boolean typed) thro
}
if (wrap) {
- receiver.startPrefixMapping("exist", Namespaces.EXIST_NS);
+ receiver.startPrefixMapping(Namespaces.EXIST_NS_PREFIX, Namespaces.EXIST_NS);
+ if (typed) {
+ receiver.startPrefixMapping(Namespaces.SCHEMA_NS_PREFIX, Namespaces.SCHEMA_NS);
+ }
receiver.startElement(ELEM_RESULT_QNAME, attrs);
}
@@ -1182,7 +1192,10 @@ public void toSAX(final Item item, final boolean wrap, final boolean typed) thro
if (wrap) {
receiver.endElement(ELEM_RESULT_QNAME);
- receiver.endPrefixMapping("exist");
+ if (typed) {
+ receiver.endPrefixMapping(Namespaces.SCHEMA_NS_PREFIX);
+ }
+ receiver.endPrefixMapping(Namespaces.EXIST_NS_PREFIX);
}
receiver.endDocument();
diff --git a/exist-core/src/main/java/org/exist/test/ExistEmbeddedServer.java b/exist-core/src/main/java/org/exist/test/ExistEmbeddedServer.java
index 108a6d4be6..bdfae3061a 100644
--- a/exist-core/src/main/java/org/exist/test/ExistEmbeddedServer.java
+++ b/exist-core/src/main/java/org/exist/test/ExistEmbeddedServer.java
@@ -52,6 +52,8 @@ public class ExistEmbeddedServer extends ExternalResource {
private static final Logger LOG = LogManager.getLogger(ExistEmbeddedServer.class);
+ public static final String USE_TEMPORARY_STORAGE_PROPERTY = "exist.use-temporary-storage";
+
private final Optional instanceName;
private final Optional configFile;
private final Optional configProperties;
@@ -94,7 +96,7 @@ public ExistEmbeddedServer(final String instanceName, final Path configFile, fin
this(instanceName, configFile, configProperties, false, false);
}
- public ExistEmbeddedServer(@Nullable final String instanceName, @Nullable final Path configFile, @Nullable final Properties configProperties, @Nullable final boolean disableAutoDeploy, @Nullable final boolean useTemporaryStorage) {
+ public ExistEmbeddedServer(@Nullable final String instanceName, @Nullable final Path configFile, @Nullable final Properties configProperties, final boolean disableAutoDeploy, final boolean useTemporaryStorage) {
this.instanceName = Optional.ofNullable(instanceName);
this.configFile = Optional.ofNullable(configFile);
this.configProperties = Optional.ofNullable(configProperties);
@@ -141,7 +143,8 @@ public void startDb() throws DatabaseConfigurationException, EXistException, IOE
}
});
- if (useTemporaryStorage) {
+ final boolean propUseTemporaryStorage = Boolean.parseBoolean(System.getProperty(USE_TEMPORARY_STORAGE_PROPERTY, "false"));
+ if (useTemporaryStorage || propUseTemporaryStorage) {
if (!temporaryStorage.isPresent()) {
this.temporaryStorage = Optional.of(Files.createTempDirectory("org.exist.test.ExistEmbeddedServer"));
}
@@ -196,7 +199,8 @@ public void stopDb(final boolean clearTemporaryStorage) {
// clear instance variables
pool = null;
- if(useTemporaryStorage && temporaryStorage.isPresent() && clearTemporaryStorage) {
+ final boolean propUseTemporaryStorage = Boolean.parseBoolean(System.getProperty(USE_TEMPORARY_STORAGE_PROPERTY, "false"));
+ if((useTemporaryStorage || propUseTemporaryStorage) && temporaryStorage.isPresent() && clearTemporaryStorage) {
FileUtils.deleteQuietly(temporaryStorage.get());
temporaryStorage = Optional.empty();
}
diff --git a/exist-core/src/main/java/org/exist/test/ExistWebServer.java b/exist-core/src/main/java/org/exist/test/ExistWebServer.java
index da058038fc..00bfcf9d7a 100644
--- a/exist-core/src/main/java/org/exist/test/ExistWebServer.java
+++ b/exist-core/src/main/java/org/exist/test/ExistWebServer.java
@@ -48,6 +48,8 @@ public class ExistWebServer extends ExternalResource {
private static final Logger LOG = LogManager.getLogger(ExistWebServer.class);
+ public static final String USE_TEMPORARY_STORAGE_PROPERTY = "exist.use-temporary-storage";
+
private static final String CONFIG_PROP_FILES = "org.exist.db-connection.files";
private static final String CONFIG_PROP_JOURNAL_DIR = "org.exist.db-connection.recovery.journal-dir";
@@ -113,7 +115,8 @@ protected void before() throws Throwable {
}
if (server == null) {
- if(useTemporaryStorage) {
+ final boolean propUseTemporaryStorage = Boolean.parseBoolean(System.getProperty(USE_TEMPORARY_STORAGE_PROPERTY, "false"));
+ if(useTemporaryStorage || propUseTemporaryStorage) {
this.temporaryStorage = Optional.of(Files.createTempDirectory("org.exist.test.ExistWebServer"));
final String absTemporaryStorage = temporaryStorage.get().toAbsolutePath().toString();
System.setProperty(CONFIG_PROP_FILES, absTemporaryStorage);
@@ -166,7 +169,8 @@ protected void after() {
server.shutdown();
server = null;
- if(useTemporaryStorage && temporaryStorage.isPresent()) {
+ final boolean propUseTemporaryStorage = Boolean.parseBoolean(System.getProperty(USE_TEMPORARY_STORAGE_PROPERTY, "false"));
+ if((useTemporaryStorage || propUseTemporaryStorage) && temporaryStorage.isPresent()) {
FileUtils.deleteQuietly(temporaryStorage.get());
temporaryStorage = Optional.empty();
System.clearProperty(CONFIG_PROP_JOURNAL_DIR);
diff --git a/exist-core/src/main/java/org/exist/util/Collations.java b/exist-core/src/main/java/org/exist/util/Collations.java
index 9cee3cfc9e..f3e3a7a7ac 100644
--- a/exist-core/src/main/java/org/exist/util/Collations.java
+++ b/exist-core/src/main/java/org/exist/util/Collations.java
@@ -274,6 +274,7 @@ public class Collations {
} else if (uri.startsWith("java:")) {
// java class specified: this should be a subclass of
// com.ibm.icu.text.RuleBasedCollator
+ // TODO(AR) RuleBasedCollator is a final class - we should only need to sub-class Collator.class
final String uriClassName = uri.substring("java:".length());
try {
final Class> collatorClass = Class.forName(uriClassName);
diff --git a/exist-core/src/main/java/org/exist/util/Configuration.java b/exist-core/src/main/java/org/exist/util/Configuration.java
index 4c1d44fe9c..0b576890ef 100644
--- a/exist-core/src/main/java/org/exist/util/Configuration.java
+++ b/exist-core/src/main/java/org/exist/util/Configuration.java
@@ -166,16 +166,27 @@ public Configuration(String configFilename, Optional existHomeDirname) thr
// firstly, try to read the configuration from a file within the
// classpath
try {
- is = Configuration.class.getClassLoader().getResourceAsStream(configFilename);
- if(is != null) {
- LOG.info("Reading configuration from classloader");
+ // 1. we try the root of the class hierarchy
+ is = Configuration.class.getClassLoader().getResourceAsStream(configFilename);
+ if (is != null) {
configFilePath = Optional.of(Paths.get(Configuration.class.getClassLoader().getResource(configFilename).toURI()));
+ LOG.info("Reading configuration from Class Loader: " + configFilePath.get());
+ }
+
+ if (is == null) {
+ // 2. we try the package org.exist.util
+ is = Configuration.class.getResourceAsStream(configFilename);
+ if (is != null) {
+ configFilePath = Optional.of(Paths.get(Configuration.class.getResource(configFilename).toURI()));
+ LOG.info("Reading configuration from Classpath org.exist.util: " + configFilePath.get());
+ }
}
- } catch(final Exception e) {
+
+ } catch (final Exception e) {
// EB: ignore and go forward, e.g. in case there is an absolute
// file name for configFileName
- LOG.debug( e );
+ LOG.debug(e);
}
// otherwise, secondly try to read configuration from file. Guess the
diff --git a/exist-core/src/main/java/org/exist/xmldb/DatabaseImpl.java b/exist-core/src/main/java/org/exist/xmldb/DatabaseImpl.java
index 08529a5af7..7d16374f1b 100644
--- a/exist-core/src/main/java/org/exist/xmldb/DatabaseImpl.java
+++ b/exist-core/src/main/java/org/exist/xmldb/DatabaseImpl.java
@@ -50,6 +50,8 @@
import java.util.Map;
import java.util.Optional;
+import static org.exist.repo.AutoDeploymentTrigger.AUTODEPLOY_PROPERTY;
+
/**
* The XMLDB driver class for eXist. This driver manages two different
* internal implementations. The first communicates with a remote
@@ -100,6 +102,8 @@ public class DatabaseImpl implements Database {
private Boolean ssl_allow_self_signed = true;
private Boolean ssl_verify_hostname = false;
+ private Boolean no_autodeploy = false;
+
public DatabaseImpl() {
final String initdb = System.getProperty("exist.initdb");
if (initdb != null) {
@@ -122,6 +126,10 @@ private void configure(final String instanceName) throws XMLDBException {
config.setProperty(Journal.PROPERTY_RECOVERY_JOURNAL_DIR, Paths.get(journalDir));
}
+ if (no_autodeploy) {
+ System.setProperty(AUTODEPLOY_PROPERTY, "off");
+ }
+
BrokerPool.configure(instanceName, 1, 5, config);
if (shutdown != null) {
BrokerPool.getInstance(instanceName).registerShutdownListener(shutdown);
@@ -382,6 +390,7 @@ public String[] getNames() throws XMLDBException {
public final static String DATA_DIR = "data-dir";
public final static String JOURNAL_DIR = "journal-dir";
public final static String SSL_ENABLE = "ssl-enable";
+ public final static String NO_AUTODEPLOY = "no-autodeploy";
public final static String SSL_ALLOW_SELF_SIGNED = "ssl-allow-self-signed";
public final static String SSL_VERIFY_HOSTNAME = "ssl-verify-hostname";
@@ -421,6 +430,10 @@ public String getProperty(final String property) throws XMLDBException {
value = ssl_verify_hostname.toString();
break;
+ case NO_AUTODEPLOY:
+ value = no_autodeploy.toString();
+ break;
+
default:
value = null;
}
@@ -461,6 +474,10 @@ public void setProperty(final String property, final String value) throws XMLDBE
case SSL_VERIFY_HOSTNAME:
this.ssl_verify_hostname = Boolean.valueOf(value);
break;
+
+ case NO_AUTODEPLOY:
+ this.no_autodeploy = Boolean.valueOf(value);
+ break;
}
}
}
diff --git a/exist-core/src/main/java/org/exist/xqj/Marshaller.java b/exist-core/src/main/java/org/exist/xqj/Marshaller.java
index cc941c4f92..9a2997b0fd 100644
--- a/exist-core/src/main/java/org/exist/xqj/Marshaller.java
+++ b/exist-core/src/main/java/org/exist/xqj/Marshaller.java
@@ -57,13 +57,9 @@
import org.exist.xquery.functions.array.ArrayType;
import org.exist.xquery.functions.map.MapType;
import org.exist.xquery.value.*;
-import org.w3c.dom.Comment;
-import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
-import org.w3c.dom.ProcessingInstruction;
-import org.w3c.dom.Text;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
@@ -100,15 +96,13 @@ public class Marshaller {
public final static String NAMESPACE = "http://exist-db.org/xquery/types/serialized";
public final static String PREFIX = "sx";
-
private final static Properties DEFAULT_OUTPUT_PROPERTIES = new Properties();
private final static String VALUE_ELEMENT = "value";
- private final static String VALUE_ELEMENT_QNAME = PREFIX + ":value";
- private final static QName VALUE_QNAME = new QName(VALUE_ELEMENT, NAMESPACE, PREFIX);
+ private final static String VALUE_ELEMENT_PREFIXED_NAME = PREFIX + ":value";
private final static String SEQ_ELEMENT = "sequence";
- private final static String SEQ_ELEMENT_QNAME = PREFIX + ":sequence";
+ private final static String SEQ_ELEMENT_PREFIXED_NAME = PREFIX + ":sequence";
private final static String ATTR_TYPE = "type";
private final static String ATTR_ITEM_TYPE = "item-type";
@@ -116,6 +110,7 @@ public class Marshaller {
private final static String ATTR_NAME = "name";
public final static QName SEQUENCE_ELEMENT_QNAME = new QName(SEQ_ELEMENT, NAMESPACE, PREFIX);
+ public final static QName VALUE_ELEMENT_QNAME = new QName(VALUE_ELEMENT, NAMESPACE, PREFIX);
public final static QName ENTRY_ELEMENT_QNAME = new QName("entry", NAMESPACE, PREFIX);
public final static QName KEY_ELEMENT_QNAME = new QName("key", NAMESPACE, PREFIX);
@@ -133,11 +128,11 @@ public static void marshall(final DBBroker broker, final Sequence seq, final Con
throws XPathException, SAXException {
final AttributesImpl attrs = new AttributesImpl();
attrs.addAttribute("", ATTR_ITEM_TYPE, ATTR_ITEM_TYPE, "CDATA", Type.getTypeName(seq.getItemType()));
- handler.startElement(NAMESPACE, SEQ_ELEMENT, SEQ_ELEMENT_QNAME, attrs);
+ handler.startElement(NAMESPACE, SEQ_ELEMENT, SEQ_ELEMENT_PREFIXED_NAME, attrs);
for (final SequenceIterator i = seq.iterate(); i.hasNext(); ) {
marshallItem(broker, i.nextItem(), handler);
}
- handler.endElement(NAMESPACE, SEQ_ELEMENT, SEQ_ELEMENT_QNAME);
+ handler.endElement(NAMESPACE, SEQ_ELEMENT, SEQ_ELEMENT_PREFIXED_NAME);
}
@@ -157,12 +152,12 @@ public static void marshall(final DBBroker broker, final Sequence seq, final int
final ContentHandler handler) throws XPathException, SAXException {
final AttributesImpl attrs = new AttributesImpl();
attrs.addAttribute("", ATTR_ITEM_TYPE, ATTR_ITEM_TYPE, "CDATA", Type.getTypeName(seq.getItemType()));
- handler.startElement(NAMESPACE, SEQ_ELEMENT, SEQ_ELEMENT_QNAME, attrs);
+ handler.startElement(NAMESPACE, SEQ_ELEMENT, SEQ_ELEMENT_PREFIXED_NAME, attrs);
for (int i = start; i < howmany && i < seq.getItemCount(); i++ ) {
marshallItem(broker, seq.itemAt(i), handler);
}
- handler.endElement(NAMESPACE, SEQ_ELEMENT, SEQ_ELEMENT_QNAME);
+ handler.endElement(NAMESPACE, SEQ_ELEMENT, SEQ_ELEMENT_PREFIXED_NAME);
}
/**
@@ -200,15 +195,15 @@ public static void marshallItem(final DBBroker broker, final Item item, final Co
{type = ((NodeValue)item).getNode().getNodeType();}
attrs.addAttribute("", ATTR_TYPE, ATTR_TYPE, "CDATA", Type.getTypeName(type));
if (Type.subTypeOf(item.getType(), Type.NODE)) {
- handler.startElement(NAMESPACE, VALUE_ELEMENT, VALUE_ELEMENT_QNAME, attrs);
+ handler.startElement(NAMESPACE, VALUE_ELEMENT, VALUE_ELEMENT_PREFIXED_NAME, attrs);
final NodeValue nv = (NodeValue) item;
nv.toSAX(broker, handler, outputProperties);
- handler.endElement(NAMESPACE, VALUE_ELEMENT, VALUE_ELEMENT_QNAME);
+ handler.endElement(NAMESPACE, VALUE_ELEMENT, VALUE_ELEMENT_PREFIXED_NAME);
} else {
- handler.startElement(NAMESPACE, VALUE_ELEMENT, VALUE_ELEMENT_QNAME, attrs);
+ handler.startElement(NAMESPACE, VALUE_ELEMENT, VALUE_ELEMENT_PREFIXED_NAME, attrs);
final String value = item.getStringValue();
handler.characters(value.toCharArray(), 0, value.length());
- handler.endElement(NAMESPACE, VALUE_ELEMENT, VALUE_ELEMENT_QNAME);
+ handler.endElement(NAMESPACE, VALUE_ELEMENT, VALUE_ELEMENT_PREFIXED_NAME);
}
}
@@ -244,13 +239,16 @@ public static Sequence demarshall(final XMLStreamReader parser) throws XMLStream
while (event != XMLStreamConstants.START_ELEMENT) {
event = parser.next();
}
+
if (!NAMESPACE.equals(parser.getNamespaceURI())) {
throw new XMLStreamException("Root element is not in the correct namespace. Expected: " + NAMESPACE);
}
+
if (!SEQ_ELEMENT.equals(parser.getLocalName())) {
- throw new XMLStreamException("Root element should be a " + SEQ_ELEMENT_QNAME);
+ throw new XMLStreamException("Root element should be a " + SEQ_ELEMENT_PREFIXED_NAME);
}
- final ValueSequence result = new ValueSequence();
+
+ Sequence result = Sequence.EMPTY_SEQUENCE;
while ((event = parser.next()) != XMLStreamConstants.END_DOCUMENT) {
switch (event) {
case XMLStreamConstants.START_ELEMENT :
@@ -275,15 +273,22 @@ public static Sequence demarshall(final XMLStreamReader parser) throws XMLStream
} else {
item = new StringValue(null, parser.getElementText()).convertTo(type);
}
+
+ if (result == Sequence.EMPTY_SEQUENCE) {
+ result = new ValueSequence();
+ }
result.add(item);
}
break;
+
case XMLStreamConstants.END_ELEMENT :
- if (NAMESPACE.equals(parser.getNamespaceURI()) && SEQ_ELEMENT.equals(parser.getLocalName()))
- {return result;}
+ if (NAMESPACE.equals(parser.getNamespaceURI()) && SEQ_ELEMENT.equals(parser.getLocalName())) {
+ return result;
+ }
break;
}
}
+
return result;
}
@@ -297,16 +302,21 @@ private static Sequence demarshallSequence(final XQueryContext context, final No
throw new XMLStreamException("Sequence element is not in the correct namespace. Expected: " + NAMESPACE);
}
if (!SEQ_ELEMENT.equals(node.getLocalName())) {
- throw new XMLStreamException("Element should be a " + SEQ_ELEMENT_QNAME);
+ throw new XMLStreamException("Element should be a " + SEQ_ELEMENT_PREFIXED_NAME);
}
return demarshallValues(context, node);
}
private static Sequence demarshallValues(final XQueryContext context, final NodeImpl node) throws XMLStreamException, XPathException {
- final ValueSequence result = new ValueSequence();
final InMemoryNodeSet sxValues = new InMemoryNodeSet();
- node.selectChildren(new NameTest(Type.ELEMENT, VALUE_QNAME), sxValues);
+ node.selectChildren(new NameTest(Type.ELEMENT, VALUE_ELEMENT_QNAME), sxValues);
+
+ if (sxValues.isEmpty()) {
+ return Sequence.EMPTY_SEQUENCE;
+ }
+
+ final ValueSequence result = new ValueSequence(sxValues.size());
for (final SequenceIterator itSxValue = sxValues.iterate(); itSxValue.hasNext();) {
final ElementImpl sxValue = (ElementImpl) itSxValue.nextItem();
final Item item = demarshallValue(context, sxValue);
@@ -315,7 +325,7 @@ private static Sequence demarshallValues(final XQueryContext context, final Node
return result;
}
- private static Item demarshallValue(final XQueryContext context, final ElementImpl sxValue) throws XMLStreamException, XPathException {
+ public static Item demarshallValue(final XQueryContext context, final ElementImpl sxValue) throws XMLStreamException, XPathException {
int type = Type.ITEM;
final String typeName = sxValue.getAttribute(ATTR_TYPE);
if (!typeName.isEmpty()) {
@@ -333,7 +343,8 @@ private static Item demarshallValue(final XQueryContext context, final ElementIm
final InMemoryNodeSet sxEntries = new InMemoryNodeSet();
sxValue.selectChildren(new NameTest(Type.ELEMENT, ENTRY_ELEMENT_QNAME), sxEntries);
- Node item = sxValue.getFirstChild();
+ @Nullable Node item = null;
+ item = sxValue.getFirstChild();
if (type == Type.ATTRIBUTE || (type == Type.ITEM && attrNameString != null)) {
if (attrNameString.isEmpty()) {
@@ -369,50 +380,73 @@ private static Item demarshallValue(final XQueryContext context, final ElementIm
switch (type) {
case Type.ELEMENT:
- if (item instanceof Document) {
- return (ElementImpl) ((DocumentImpl) item).getDocumentElement();
- } else if (!(item instanceof Element)) {
- throw new XMLStreamException("sx:value should only contain an Element if type is " + typeName);
- } else {
- return (ElementImpl) item;
- }
+ do {
+ if (item.getNodeType() == Node.DOCUMENT_NODE) {
+ item = ((DocumentImpl) item).getDocumentElement();
+ }
+
+ if (item.getNodeType() == Node.ELEMENT_NODE) {
+ return (ElementImpl) item;
+ }
+
+ item = item.getNextSibling();
+ } while (item != null);
+
+ throw new XMLStreamException("sx:value must contain an Element if type is " + typeName);
+
case Type.COMMENT:
- if (!(item instanceof Comment)) {
- throw new XMLStreamException("sx:value should only contain a Comment node if type is " + typeName);
- }
- return (CommentImpl) item;
+ do {
+ if (item.getNodeType() == Node.COMMENT_NODE) {
+ return (CommentImpl) item;
+ }
+ item = item.getNextSibling();
+ } while (item != null);
+
+ throw new XMLStreamException("sx:value must contain a Comment node if type is " + typeName);
+
case Type.PROCESSING_INSTRUCTION:
- if (!(item instanceof ProcessingInstruction)) {
- throw new XMLStreamException("sx:value should only contain a Processing Instruction node if type is " + typeName);
- }
- return (ProcessingInstructionImpl) item;
+ do {
+ if (item.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) {
+ return (ProcessingInstructionImpl) item;
+ }
+ item = item.getNextSibling();
+ } while (item != null);
+
+ throw new XMLStreamException("sx:value must contain a Processing Instruction node if type is " + typeName);
+
case Type.TEXT:
- if (!(item instanceof Text)) {
- throw new XMLStreamException("sx:value should only contain a Text node if type is " + typeName);
- }
- return (TextImpl) item;
+ do {
+ if (item.getNodeType() == Node.TEXT_NODE) {
+ return (TextImpl) item;
+ }
+ item = item.getNextSibling();
+ } while (item != null);
+
case Type.DOCUMENT:
default:
- if (item instanceof Document || item instanceof Element) {
- final DocumentBuilderReceiver receiver = new DocumentBuilderReceiver(((NodeImpl) item).getExpression());
- try {
- receiver.startDocument();
- ((NodeImpl) item).copyTo(null, receiver);
- receiver.endDocument();
- } catch (final SAXException e) {
- throw new XPathException(item != null ? ((NodeImpl) item).getExpression() : null, "Error while demarshalling node: " + e.getMessage(), e);
+ do {
+ if (item.getNodeType() == Node.DOCUMENT_NODE || item.getNodeType() == Node.ELEMENT_NODE) {
+ final DocumentBuilderReceiver receiver = new DocumentBuilderReceiver(((NodeImpl) item).getExpression());
+ try {
+ receiver.startDocument();
+ ((NodeImpl) item).copyTo(null, receiver);
+ receiver.endDocument();
+ } catch (final SAXException e) {
+ throw new XPathException(item != null ? ((NodeImpl) item).getExpression() : null, "Error while demarshalling node: " + e.getMessage(), e);
+ }
+ return (NodeImpl) receiver.getDocument();
}
- return (NodeImpl) receiver.getDocument();
- } else {
- throw new XMLStreamException("sx:value should only contain a Node if type is " + typeName);
- }
+ item = item.getNextSibling();
+ } while (item != null);
+
+ throw new XMLStreamException("sx:value must contain a Document or Element if type is " + typeName);
}
- } else if (type == Type.ITEM && !(item instanceof Text)) {
+ } else if (type == Type.ITEM && item.getNodeType() != Node.TEXT_NODE) {
// item() type requested and we have been given a node which is not a text() node
return (NodeImpl) item;
@@ -447,13 +481,13 @@ private static Item demarshallValue(final XQueryContext context, final ElementIm
} else {
// specific non-node type or text()
final StringBuilder data = new StringBuilder();
- while (item != null) {
- if (!(item.getNodeType() == Node.TEXT_NODE || item.getNodeType() == Node.CDATA_SECTION_NODE)) {
- throw new XMLStreamException("sx:value should only contain text if type is " + typeName);
+ do {
+ if (item.getNodeType() == Node.TEXT_NODE || item.getNodeType() == Node.CDATA_SECTION_NODE) {
+ data.append(item.getNodeValue());
}
- data.append(item.getNodeValue());
item = item.getNextSibling();
- }
+ } while (item != null);
+
return new StringValue(data.toString()).convertTo(type);
}
}
diff --git a/exist-core/src/main/java/org/exist/xquery/XQueryContext.java b/exist-core/src/main/java/org/exist/xquery/XQueryContext.java
index 246c1274ce..8c318c66ae 100644
--- a/exist-core/src/main/java/org/exist/xquery/XQueryContext.java
+++ b/exist-core/src/main/java/org/exist/xquery/XQueryContext.java
@@ -1231,6 +1231,7 @@ public DocumentSet getStaticallyKnownDocuments() throws XPathException {
staticDocuments = protectedDocuments.toDocumentSet();
return staticDocuments;
}
+
final MutableDocumentSet ndocs = new DefaultDocumentSet(40);
if (staticDocumentPaths == null) {
@@ -1269,7 +1270,8 @@ public DocumentSet getStaticallyKnownDocuments() throws XPathException {
}
}
}
- staticDocuments = ndocs;
+
+ this.staticDocuments = ndocs;
return staticDocuments;
}
diff --git a/exist-core/src/main/java/org/exist/xquery/functions/fn/ExtCollection.java b/exist-core/src/main/java/org/exist/xquery/functions/fn/ExtCollection.java
index 849ec2af35..012dfc8f62 100644
--- a/exist-core/src/main/java/org/exist/xquery/functions/fn/ExtCollection.java
+++ b/exist-core/src/main/java/org/exist/xquery/functions/fn/ExtCollection.java
@@ -63,6 +63,7 @@
import org.exist.xquery.functions.xmldb.XMLDBModule;
import org.exist.xquery.value.*;
+import javax.annotation.Nullable;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
@@ -114,88 +115,120 @@ public Sequence eval(final Sequence contextSequence, final Item contextItem) thr
context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT ITEM", contextItem.toSequence());
}
}
+
final List args = getParameterValues(contextSequence, contextItem);
- final Sequence result;
- try {
- if (args.isEmpty()) {
- final Sequence docs = toSequence(context.getStaticallyKnownDocuments());
- final Sequence dynamicCollection = context.getDynamicallyAvailableCollection("");
- if (dynamicCollection != null) {
- result = new ValueSequence();
- result.addAll(docs);
- result.addAll(dynamicCollection);
- } else {
- result = docs;
- }
- } else {
- final Sequence dynamicCollection = context.getDynamicallyAvailableCollection(asUri(args.get(0)).toString());
- if (dynamicCollection != null) {
- result = dynamicCollection;
- } else {
- final MutableDocumentSet ndocs = new DefaultDocumentSet();
- for (final String next : args) {
- final XmldbURI uri = new AnyURIValue(this, next).toXmldbURI();
- try (final Collection coll = context.getBroker().openCollection(uri, Lock.LockMode.READ_LOCK)) {
- if (coll == null) {
- if (context.isRaiseErrorOnFailedRetrieval()) {
- throw new XPathException(this, ErrorCodes.FODC0002, "Can not access collection '" + uri + "'");
- }
- } else {
- if (context.inProtectedMode()) {
- context.getProtectedDocs().getDocsByCollection(coll, ndocs);
- } else {
- coll.allDocs(context.getBroker(), ndocs,
- includeSubCollections, context.getProtectedDocs());
- }
- }
- }
- }
- result = toSequence(ndocs);
- }
- }
- } catch (final XPathException e) { //From AnyURIValue constructor
- e.setLocation(line, column);
- Sequence flattenedArgs = Sequence.EMPTY_SEQUENCE;
- try {
- flattenedArgs = argsToSeq(contextSequence, contextItem);
- } catch (final XPathException xe) {
- LOG.warn(e.getMessage(), xe);
- }
- throw new XPathException(this, ErrorCodes.FODC0002, e.getMessage(), flattenedArgs, e);
- } catch (final PermissionDeniedException e) {
- Sequence flattenedArgs = Sequence.EMPTY_SEQUENCE;
- try {
- flattenedArgs = argsToSeq(contextSequence, contextItem);
- } catch (final XPathException xe) {
- LOG.warn(e.getMessage(), xe);
- }
- throw new XPathException(this, ErrorCodes.FODC0002, "Can not access collection '" + e.getMessage() + "'", flattenedArgs, e);
- } catch (final LockException e) {
- Sequence flattenedArgs = Sequence.EMPTY_SEQUENCE;
- try {
- flattenedArgs = argsToSeq(contextSequence, contextItem);
- } catch (final XPathException xe) {
- LOG.warn(e.getMessage(), xe);
+
+ @Nullable final List collectionUris;
+ if (args.isEmpty()) {
+ collectionUris = null;
+ } else {
+ collectionUris = new ArrayList<>(args.size());
+ for (final String arg : args) {
+ collectionUris.add(asUri(arg));
}
- throw new XPathException(this, ErrorCodes.FODC0002, e.getMessage(), flattenedArgs, e);
}
- // iterate through all docs and create the node set
+ final Sequence result = getCollectionItems(collectionUris);
registerUpdateListener();
if (context.getProfiler().isEnabled()) {
context.getProfiler().end(this, "", result);
}
+
return result;
}
- private Sequence argsToSeq(final Sequence contextSequence, final Item contextItem) throws XPathException {
- final ValueSequence sequence = new ValueSequence();
- for (int i = 0; i < getArgumentCount(); i++) {
- final Sequence seq = getArgument(i).eval(contextSequence, contextItem);
- sequence.addAll(seq);
+ protected Sequence getCollectionItems(@Nullable final List collectionUris) throws XPathException {
+ if (collectionUris == null) {
+ // no collection-uri(s)
+ return getDefaultCollectionItems();
+ }
+
+ return getCollectionUriItems(collectionUris);
+ }
+
+ private Sequence getDefaultCollectionItems() throws XPathException {
+ @Nullable Sequence items = null;
+
+ @Nullable final Sequence dynamicCollection = context.getDynamicallyAvailableCollection("");
+ if (dynamicCollection != null) {
+ items = new ValueSequence(dynamicCollection);
+ }
+
+ if (items == null) {
+ final DocumentSet staticallyKnownDocuments = context.getStaticallyKnownDocuments();
+ items = new ValueSequence(staticallyKnownDocuments.getDocumentCount());
+ addAll(staticallyKnownDocuments, items);
+ }
+
+ if (items == null) {
+ items = Sequence.EMPTY_SEQUENCE;
+ }
+
+ return items;
+ }
+
+ private Sequence getCollectionUriItems(final List collectionUris) throws XPathException {
+ @Nullable Sequence items = null;
+ for (final URI collectionUri : collectionUris) {
+ items = getCollectionUriItems(collectionUri, items);
+ }
+
+ if (items == null) {
+ items = Sequence.EMPTY_SEQUENCE;
+ }
+
+ return items;
+ }
+
+ private @Nullable Sequence getCollectionUriItems(final URI collectionUri, @Nullable Sequence items) throws XPathException {
+ @Nullable final Sequence dynamicCollection = context.getDynamicallyAvailableCollection(collectionUri.toString());
+ if (dynamicCollection != null) {
+ if (items == null) {
+ items = dynamicCollection;
+ } else {
+ items.addAll(dynamicCollection);
+ }
+
+ return items;
+
+ } else {
+ @Nullable MutableDocumentSet docs = null;
+
+ final XmldbURI uri = XmldbURI.create(collectionUri);
+ try (@Nullable final Collection coll = context.getBroker().openCollection(uri, Lock.LockMode.READ_LOCK)) {
+ if (coll == null) {
+ if (context.isRaiseErrorOnFailedRetrieval()) {
+ throw new XPathException(this, ErrorCodes.FODC0002, "Can not access collection '" + uri + "'");
+ }
+ } else {
+ docs = new DefaultDocumentSet();
+ if (context.inProtectedMode()) {
+ context.getProtectedDocs().getDocsByCollection(coll, docs);
+ } else {
+ coll.allDocs(context.getBroker(), docs, includeSubCollections, context.getProtectedDocs());
+ }
+ }
+ } catch (final XPathException e) { // From AnyURIValue constructor
+ throw new XPathException(this, ErrorCodes.FODC0002, e.getMessage(), new StringValue(collectionUri.toString()), e);
+ } catch (final PermissionDeniedException e) {
+ throw new XPathException(this, ErrorCodes.FODC0002, "Can not access collection '" + e.getMessage() + "'", new StringValue(collectionUri.toString()), e);
+ } catch (final LockException e) {
+ throw new XPathException(this, ErrorCodes.FODC0002, e.getMessage(), new StringValue(collectionUri.toString()), e);
+ }
+
+ if (docs == null || docs.getDocumentCount() == 0) {
+ return Sequence.EMPTY_SEQUENCE;
+ }
+
+ if (items == null) {
+ items = new ValueSequence(docs.getDocumentCount());
+ } else {
+ addAll(docs, items);
+ }
+
+ return items;
}
- return sequence;
}
private URI asUri(final String path) throws XPathException {
@@ -231,8 +264,7 @@ private List getParameterValues(final Sequence contextSequence, final It
return args;
}
- private Sequence toSequence(final DocumentSet docs) throws XPathException {
- final Sequence result = new ValueSequence();
+ private void addAll(final DocumentSet docs, final Sequence items) throws XPathException {
final LockManager lockManager = context.getBroker().getBrokerPool().getLockManager();
for (final Iterator i = docs.getDocumentIterator(); i.hasNext(); ) {
final DocumentImpl doc = i.next();
@@ -245,7 +277,7 @@ private Sequence toSequence(final DocumentSet docs) throws XPathException {
if (!context.inProtectedMode()) {
dlock = lockManager.acquireDocumentReadLock(doc.getURI());
}
- result.add(new NodeProxy(null, doc));
+ items.add(new NodeProxy(this, doc));
} catch (final LockException e) {
throw new XPathException(this, ErrorCodes.FODC0002, e);
} finally {
@@ -255,8 +287,6 @@ private Sequence toSequence(final DocumentSet docs) throws XPathException {
}
}
}
-
- return result;
}
protected void registerUpdateListener() {
diff --git a/exist-core/src/main/java/org/exist/xquery/functions/fn/FunAnalyzeString.java b/exist-core/src/main/java/org/exist/xquery/functions/fn/FunAnalyzeString.java
index 6c9155be99..add6146168 100644
--- a/exist-core/src/main/java/org/exist/xquery/functions/fn/FunAnalyzeString.java
+++ b/exist-core/src/main/java/org/exist/xquery/functions/fn/FunAnalyzeString.java
@@ -45,9 +45,16 @@
*/
package org.exist.xquery.functions.fn;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
+import net.sf.cglib.proxy.Callback;
+import net.sf.cglib.proxy.Enhancer;
+import net.sf.cglib.proxy.MethodInterceptor;
+import net.sf.cglib.proxy.MethodProxy;
import net.sf.saxon.Configuration;
import net.sf.saxon.om.Item;
import net.sf.saxon.regex.RegexIterator;
@@ -72,6 +79,25 @@
*/
public class FunAnalyzeString extends BasicFunction {
+ /**
+ * Implements a cglib MethodInterceptor to implement the `characters`
+ * method of Saxon 9's net.sf.saxon.regex.RegexIterator$MatchHandler
+ * and Saxon 12's net.sf.saxon.regex.RegexMatchHandler
+ */
+ private static final MethodInterceptor CHARACTERS_INTERCEPTOR = (final Object obj, final Method method, final Object[] args, final MethodProxy proxy) -> {
+ if ("characters".equals(method.getName())) {
+ final MemTreeBuilder builder = ((AbstractSaxonRegexMatchHandler) obj).builder;
+ builder.characters(args[0].toString());
+ return null;
+ }
+ return proxy.invokeSuper(obj, args);
+ };
+
+ @SuppressWarnings("unchecked")
+ private static final Class extends AbstractSaxonRegexMatchHandler> SAXON_MATCH_HANDLER_CLASS = createSaxonMatchHandlerClass();
+ private static final Constructor extends AbstractSaxonRegexMatchHandler> SAXON_MATCH_HANDLER_CLASS_CONSTRUCTOR = getSaxonMatchHandlerClassConstructor(SAXON_MATCH_HANDLER_CLASS);
+ private static final Method SAXON_PROCESS_MATCHING_SUBSTRING_FN = getSaxonProcessMatchingSubstringFunction();
+
private final static QName fnAnalyzeString = new QName("analyze-string", FnModule.NAMESPACE_URI);
private final static QName QN_MATCH = new QName("match", FnModule.NAMESPACE_URI);
@@ -189,26 +215,107 @@ private void analyzeString(final MemTreeBuilder builder, final String input, Str
private void match(final MemTreeBuilder builder, final RegexIterator regexIterator) throws net.sf.saxon.trans.XPathException {
builder.startElement(QN_MATCH, null);
- regexIterator.processMatchingSubstring(new RegexIterator.MatchHandler() {
- @Override
- public void characters(final CharSequence s) {
- builder.characters(s);
+
+ try {
+ Enhancer.registerCallbacks(SAXON_MATCH_HANDLER_CLASS, new Callback[]{ CHARACTERS_INTERCEPTOR });
+ try {
+ final AbstractSaxonRegexMatchHandler matchHandler = SAXON_MATCH_HANDLER_CLASS_CONSTRUCTOR.newInstance(builder);
+ SAXON_PROCESS_MATCHING_SUBSTRING_FN.invoke(regexIterator, matchHandler);
+ } finally {
+ Enhancer.registerCallbacks(SAXON_MATCH_HANDLER_CLASS, null);
}
+ } catch (final InstantiationException | IllegalAccessException | InvocationTargetException e) {
+ throw new net.sf.saxon.trans.XPathException("Unable to dynamically invoke net.sf.saxon.regex.RegexIterator#processMatchingSubstring: " + e.getMessage(), e);
+ }
- @Override
- public void onGroupStart(final int groupNumber) throws net.sf.saxon.trans.XPathException {
- final AttributesImpl attributes = new AttributesImpl();
- attributes.addAttribute("", QN_NR.getLocalPart(), QN_NR.getLocalPart(), "int", Integer.toString(groupNumber));
+ builder.endElement();
+ }
- builder.startElement(QN_GROUP, attributes);
+ private static Method getSaxonProcessMatchingSubstringFunction() {
+ final String saxonVersion = net.sf.saxon.Version.getProductVersion();
+ try {
+ final Class> matchHandlerInterfaceClazz;
+ if (saxonVersion.startsWith("12.")) {
+ matchHandlerInterfaceClazz = getSaxon12MatchHandlerInterfaceClass();
+ } else {
+ matchHandlerInterfaceClazz = getSaxon9MatchHandlerInterfaceClass();
}
- @Override
- public void onGroupEnd(final int groupNumber) throws net.sf.saxon.trans.XPathException {
- builder.endElement();
+ return RegexIterator.class.getMethod("processMatchingSubstring", matchHandlerInterfaceClazz);
+
+ } catch (final ClassNotFoundException | NoSuchMethodException e) {
+ throw new IllegalStateException("Unable to dynamically access Saxon RegexIterator#processMatchingSubstring method: " + e.getMessage(), e);
+ }
+ }
+
+ private static Constructor extends AbstractSaxonRegexMatchHandler> getSaxonMatchHandlerClassConstructor(final Class extends AbstractSaxonRegexMatchHandler> saxonMatchHandlerClass) {
+ try {
+ return saxonMatchHandlerClass.getDeclaredConstructor(MemTreeBuilder.class);
+ } catch (final NoSuchMethodException e) {
+ throw new IllegalStateException("Unable to get constructor of dynamic Saxon Match Handler class: " + e.getMessage(), e);
+ }
+ }
+
+ private static Class extends AbstractSaxonRegexMatchHandler> createSaxonMatchHandlerClass() {
+ final String saxonVersion = net.sf.saxon.Version.getProductVersion();
+ try {
+ if (saxonVersion.startsWith("12.")) {
+ return createSaxon12MatchHandlerClass();
+ } else {
+ return createSaxon9MatchHandlerClass();
}
- });
- builder.endElement();
+ } catch (final ClassNotFoundException e) {
+ throw new IllegalStateException("Unable to dynamically create Saxon Match Handler class: " + e.getMessage(), e);
+ }
+ }
+
+ private static Class> getSaxon12MatchHandlerInterfaceClass() throws ClassNotFoundException {
+ return Class.forName("net.sf.saxon.regex.RegexMatchHandler");
+ }
+
+ private static Class> getSaxon9MatchHandlerInterfaceClass() throws ClassNotFoundException {
+ return Class.forName("net.sf.saxon.regex.RegexIterator$MatchHandler");
+ }
+
+ private static Class extends AbstractSaxonRegexMatchHandler> createSaxon12MatchHandlerClass() throws ClassNotFoundException {
+ final Class> matchHandlerInterfaceClazz = getSaxon12MatchHandlerInterfaceClass();
+ return createSaxonMatchHandlerClass(matchHandlerInterfaceClazz);
+ }
+
+ private static Class extends AbstractSaxonRegexMatchHandler> createSaxon9MatchHandlerClass() throws ClassNotFoundException {
+ final Class> matchHandlerInterfaceClazz = getSaxon9MatchHandlerInterfaceClass();
+ return createSaxonMatchHandlerClass(matchHandlerInterfaceClazz);
+ }
+
+ @SuppressWarnings("unchecked")
+ private static Class extends AbstractSaxonRegexMatchHandler> createSaxonMatchHandlerClass(final Class> saxonMatchHandlerInterface) {
+ final Enhancer enhancer = new Enhancer();
+ enhancer.setSuperclass(AbstractSaxonRegexMatchHandler.class);
+ enhancer.setInterfaces(new Class[]{saxonMatchHandlerInterface});
+ enhancer.setCallbackType(MethodInterceptor.class);
+ return (Class extends AbstractSaxonRegexMatchHandler>) enhancer.createClass();
+ }
+
+ /**
+ * Implements the common methods of Saxon 9's net.sf.saxon.regex.RegexIterator$MatchHandler
+ * and Saxon 12's net.sf.saxon.regex.RegexMatchHandler
+ */
+ private static abstract class AbstractSaxonRegexMatchHandler {
+ private final MemTreeBuilder builder;
+
+ public AbstractSaxonRegexMatchHandler(final MemTreeBuilder builder) {
+ this.builder = builder;
+ }
+
+ public void onGroupStart(final int groupNumber) {
+ final AttributesImpl attributes = new AttributesImpl();
+ attributes.addAttribute("", QN_NR.getLocalPart(), QN_NR.getLocalPart(), "int", Integer.toString(groupNumber));
+ builder.startElement(QN_GROUP, attributes);
+ }
+
+ public void onGroupEnd(final int groupNumber) {
+ builder.endElement();
+ }
}
private void nonMatch(final MemTreeBuilder builder, final Item item) {
diff --git a/exist-core/src/main/java/org/exist/xquery/value/AbstractDateTimeValue.java b/exist-core/src/main/java/org/exist/xquery/value/AbstractDateTimeValue.java
index 8fdb17a09a..1bb2dfbcdb 100644
--- a/exist-core/src/main/java/org/exist/xquery/value/AbstractDateTimeValue.java
+++ b/exist-core/src/main/java/org/exist/xquery/value/AbstractDateTimeValue.java
@@ -126,6 +126,12 @@ protected AbstractDateTimeValue(final Expression expression, String lexicalValue
}
}
+ protected static XMLGregorianCalendar toXMLGregorianCalendar(final GregorianCalendar gregorianCalendar) {
+ final XMLGregorianCalendar xgc = TimeUtils.getInstance().newXMLGregorianCalendar(gregorianCalendar);
+ xgc.normalize();
+ return xgc;
+ }
+
/**
* Utility method that is able to clone a calendar whose year is 0
* (whatever a year 0 means).
diff --git a/exist-core/src/main/java/org/exist/xquery/value/DateTimeStampValue.java b/exist-core/src/main/java/org/exist/xquery/value/DateTimeStampValue.java
index 51a9e5ab88..dd06de9c1b 100644
--- a/exist-core/src/main/java/org/exist/xquery/value/DateTimeStampValue.java
+++ b/exist-core/src/main/java/org/exist/xquery/value/DateTimeStampValue.java
@@ -56,6 +56,7 @@
import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.namespace.QName;
import java.nio.ByteBuffer;
+import java.time.ZonedDateTime;
/**
* @author Radek Hübner
@@ -83,6 +84,15 @@ public DateTimeStampValue(final Expression expression, final String dateTime) th
checkValidTimezone();
}
+ public DateTimeStampValue(final ZonedDateTime zonedDateTime) throws XPathException {
+ this(null, zonedDateTime);
+ }
+
+ public DateTimeStampValue(final Expression expression, final ZonedDateTime zonedDateTime) throws XPathException {
+ super(expression, zonedDateTime);
+ checkValidTimezone();
+ }
+
private void checkValidTimezone() throws XPathException {
if(calendar.getTimezone() == DatatypeConstants.FIELD_UNDEFINED) {
throw new XPathException(getExpression(), ErrorCodes.ERROR, "Unable to create xs:dateTimeStamp, timezone missing.");
diff --git a/exist-core/src/main/java/org/exist/xquery/value/DateTimeValue.java b/exist-core/src/main/java/org/exist/xquery/value/DateTimeValue.java
index a7c6df74a8..0be3dc2459 100644
--- a/exist-core/src/main/java/org/exist/xquery/value/DateTimeValue.java
+++ b/exist-core/src/main/java/org/exist/xquery/value/DateTimeValue.java
@@ -57,6 +57,11 @@
import javax.xml.namespace.QName;
import java.io.IOException;
import java.nio.ByteBuffer;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.OffsetDateTime;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
import java.util.Date;
import java.util.GregorianCalendar;
@@ -90,12 +95,39 @@ public DateTimeValue(@Nullable final Expression expression, final XMLGregorianCa
normalize();
}
+ public DateTimeValue(final Instant instant) {
+ this(null, instant);
+ }
+
+ public DateTimeValue(final Expression expression, final Instant instant) {
+ super(expression, toXMLGregorianCalendar(new Date(instant.toEpochMilli())));
+ normalize();
+ }
+
+ public DateTimeValue(final ZonedDateTime zonedDateTime) {
+ this(null, zonedDateTime);
+ }
+
+ public DateTimeValue(final Expression expression, final ZonedDateTime zonedDateTime) {
+ super(expression, toXMLGregorianCalendar(zonedDateTime));
+ normalize();
+ }
+
+ public DateTimeValue(final LocalDateTime localDateTime) {
+ this(null, localDateTime);
+ }
+
+ public DateTimeValue(final Expression expression, final LocalDateTime localDateTime) {
+ super(expression, toXMLGregorianCalendar(localDateTime));
+ normalize();
+ }
+
public DateTimeValue(final Date date) {
this(null, date);
}
public DateTimeValue(final Expression expression, Date date) {
- super(expression, dateToXMLGregorianCalendar(date));
+ super(expression, toXMLGregorianCalendar(date));
normalize();
}
@@ -115,14 +147,35 @@ public DateTimeValue(final Expression expression, String dateTime) throws XPathE
normalize();
}
- private static XMLGregorianCalendar dateToXMLGregorianCalendar(Date date) {
+ private static XMLGregorianCalendar toXMLGregorianCalendar(final Date date) {
final GregorianCalendar gc = new GregorianCalendar();
gc.setTime(date);
- final XMLGregorianCalendar xgc = TimeUtils.getInstance().newXMLGregorianCalendar(gc);
+ return toXMLGregorianCalendar(gc);
+ }
+
+ private static XMLGregorianCalendar toXMLGregorianCalendar(final LocalDateTime localDateTime) {
+ final XMLGregorianCalendar xgc = TimeUtils.getInstance().newXMLGregorianCalendar();
+ xgc.setYear(localDateTime.getYear());
+ xgc.setMonth(localDateTime.getMonthValue());
+ xgc.setDay(localDateTime.getDayOfMonth());
+ xgc.setHour(localDateTime.getHour());
+ xgc.setMinute(localDateTime.getMinute());
+ xgc.setSecond(localDateTime.getSecond());
+ xgc.setMillisecond(localDateTime.getNano() / 1_000_000);
+ xgc.setTimezone(DatatypeConstants.FIELD_UNDEFINED);
xgc.normalize();
return xgc;
}
+ private static XMLGregorianCalendar toXMLGregorianCalendar(final Instant instant) {
+ return toXMLGregorianCalendar(LocalDateTime.ofInstant(instant, ZoneOffset.UTC));
+ }
+
+ private static XMLGregorianCalendar toXMLGregorianCalendar(final ZonedDateTime zonedDateTime) {
+ final GregorianCalendar gc = GregorianCalendar.from(zonedDateTime);
+ return toXMLGregorianCalendar(gc);
+ }
+
private static XMLGregorianCalendar fillCalendar(XMLGregorianCalendar calendar) {
if (calendar.getHour() == DatatypeConstants.FIELD_UNDEFINED) {
calendar.setHour(0);
@@ -222,6 +275,12 @@ public T toJavaObject(final Class target) throws XPathException {
final ByteBuffer buf = ByteBuffer.allocate(SERIALIZED_SIZE);
serialize(buf);
return (T) buf;
+ } else if (target == ZonedDateTime.class) {
+ return (T) calendar.toGregorianCalendar().toZonedDateTime();
+ } else if (target == OffsetDateTime.class) {
+ return (T) calendar.toGregorianCalendar().toZonedDateTime().toOffsetDateTime();
+ } else if (target == LocalDateTime.class) {
+ return (T)calendar.toGregorianCalendar().toZonedDateTime().toLocalDateTime();
} else {
return super.toJavaObject(target);
}
diff --git a/exist-core/src/main/java/org/exist/xquery/value/DateValue.java b/exist-core/src/main/java/org/exist/xquery/value/DateValue.java
index 8f41a0c8e3..aa16b91af8 100644
--- a/exist-core/src/main/java/org/exist/xquery/value/DateValue.java
+++ b/exist-core/src/main/java/org/exist/xquery/value/DateValue.java
@@ -55,6 +55,7 @@
import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.namespace.QName;
import java.nio.ByteBuffer;
+import java.time.LocalDate;
import java.util.GregorianCalendar;
/**
@@ -93,7 +94,7 @@ public DateValue(final XMLGregorianCalendar calendar) throws XPathException {
this(null, calendar);
}
- public DateValue(final Expression expression, XMLGregorianCalendar calendar) throws XPathException {
+ public DateValue(final Expression expression, final XMLGregorianCalendar calendar) throws XPathException {
super(expression, stripCalendar(cloneXMLGregorianCalendar(calendar)));
}
@@ -182,6 +183,8 @@ public T toJavaObject(final Class target) throws XPathException {
return (T) buf;
} else if (target == Long.class || target == long.class) {
return (T) Long.valueOf(serializeToLong());
+ } else if (target == LocalDate.class) {
+ return (T)calendar.toGregorianCalendar().toZonedDateTime().toLocalDate();
} else {
return super.toJavaObject(target);
}
diff --git a/exist-core/src/main/java/org/exist/xquery/value/DayTimeDurationValue.java b/exist-core/src/main/java/org/exist/xquery/value/DayTimeDurationValue.java
index 94699c00a9..ff4f90be36 100644
--- a/exist-core/src/main/java/org/exist/xquery/value/DayTimeDurationValue.java
+++ b/exist-core/src/main/java/org/exist/xquery/value/DayTimeDurationValue.java
@@ -72,11 +72,11 @@ public class DayTimeDurationValue extends OrderedDurationValue {
public static final Duration CANONICAL_ZERO_DURATION =
TimeUtils.getInstance().newDuration(true, null, null, null, null, null, ZERO_DECIMAL);
- DayTimeDurationValue(final Duration duration) throws XPathException {
+ public DayTimeDurationValue(final Duration duration) throws XPathException {
this(null, duration);
}
- DayTimeDurationValue(final Expression expression, Duration duration) throws XPathException {
+ public DayTimeDurationValue(final Expression expression, Duration duration) throws XPathException {
super(expression, duration);
if (duration.isSet(DatatypeConstants.YEARS) || duration.isSet(DatatypeConstants.MONTHS)) {
throw new XPathException(getExpression(), ErrorCodes.XPTY0004, "the value '" + duration + "' is not an xdt:dayTimeDuration since it specifies year or month values");
diff --git a/exist-core/src/main/java/org/exist/xquery/value/TimeValue.java b/exist-core/src/main/java/org/exist/xquery/value/TimeValue.java
index cfc66d0d80..f3c44eeb5d 100644
--- a/exist-core/src/main/java/org/exist/xquery/value/TimeValue.java
+++ b/exist-core/src/main/java/org/exist/xquery/value/TimeValue.java
@@ -56,6 +56,8 @@
import javax.xml.namespace.QName;
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
+import java.time.LocalTime;
+import java.time.OffsetTime;
import java.util.GregorianCalendar;
/**
@@ -174,6 +176,10 @@ public T toJavaObject(final Class target) throws XPathException {
return (T) buf;
} else if (target == Long.class || target == long.class) {
return (T) Long.valueOf(serializeToLong());
+ } else if (target == OffsetTime.class) {
+ return (T)calendar.toGregorianCalendar().toZonedDateTime().toOffsetDateTime().toOffsetTime();
+ } else if (target == LocalTime.class) {
+ return (T)calendar.toGregorianCalendar().toZonedDateTime().toLocalTime();
} else {
return super.toJavaObject(target);
}
diff --git a/exist-core/src/main/java/org/exist/xquery/value/YearMonthDurationValue.java b/exist-core/src/main/java/org/exist/xquery/value/YearMonthDurationValue.java
index c1d786abd4..e72a498ada 100644
--- a/exist-core/src/main/java/org/exist/xquery/value/YearMonthDurationValue.java
+++ b/exist-core/src/main/java/org/exist/xquery/value/YearMonthDurationValue.java
@@ -71,11 +71,11 @@ public class YearMonthDurationValue extends OrderedDurationValue {
public static final Duration CANONICAL_ZERO_DURATION =
TimeUtils.getInstance().newDuration(true, null, BigInteger.ZERO, null, null, null, null);
- YearMonthDurationValue(final Duration duration) throws XPathException {
+ public YearMonthDurationValue(final Duration duration) throws XPathException {
this(null, duration);
}
- YearMonthDurationValue(final Expression expression, Duration duration) throws XPathException {
+ public YearMonthDurationValue(final Expression expression, Duration duration) throws XPathException {
super(expression, duration);
if (!duration.equals(DurationValue.CANONICAL_ZERO_DURATION)) {
if (duration.isSet(DatatypeConstants.DAYS) ||
diff --git a/exist-core/src/main/xsd/rest-api.xsd b/exist-core/src/main/xsd/rest-api.xsd
index c1edbc8334..3052fbb7b8 100644
--- a/exist-core/src/main/xsd/rest-api.xsd
+++ b/exist-core/src/main/xsd/rest-api.xsd
@@ -35,6 +35,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/exist-core/src/test/java/org/exist/http/RESTExternalVariableTest.java b/exist-core/src/test/java/org/exist/http/RESTExternalVariableTest.java
index 0968c06ba4..452698c03e 100644
--- a/exist-core/src/test/java/org/exist/http/RESTExternalVariableTest.java
+++ b/exist-core/src/test/java/org/exist/http/RESTExternalVariableTest.java
@@ -21,7 +21,7 @@
package org.exist.http;
import com.evolvedbinary.j8fu.tuple.Tuple2;
-import com.googlecode.junittoolbox.ParallelRunner;
+import com.googlecode.junittoolbox.ParallelParameterized;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
@@ -39,7 +39,9 @@
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
import org.w3c.dom.Attr;
+import org.w3c.dom.Node;
import org.xmlunit.diff.DefaultNodeMatcher;
import org.xmlunit.diff.ElementSelectors;
import org.xmlunit.matchers.CompareMatcher;
@@ -50,6 +52,7 @@
import javax.xml.namespace.QName;
import java.io.IOException;
import java.io.InputStream;
+import java.util.Arrays;
import java.util.Map;
import static com.evolvedbinary.j8fu.tuple.Tuple.Tuple;
@@ -66,15 +69,30 @@
import static org.exist.http.RESTExternalVariableTest.UntypedNamedValueRep.value;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
+import static org.xmlunit.matchers.HasXPathMatcher.hasXPath;
/**
* See: [BUG] The JavaDoc comments for variable in the REST API are inconsistent with the implementation.
*
* @author data() {
+ return Arrays.asList(new Object[][] {
+ { "xmlns-prefixed-ns", true },
+ { "xmlns-default-ns", false }
+ });
+ }
+
+ @Parameterized.Parameter
+ public String testTypeName;
+
+ @Parameterized.Parameter(value = 1)
+ public boolean useXmlnsPrefixes;
+
@ClassRule
public static final ExistWebServer existWebServer = new ExistWebServer(true, false, true, true);
@@ -316,13 +334,23 @@ public void queryPostWithExternalVariableStringzSuppliedUntypeds() throws IOExce
@Test
public void queryPostWithExternalVariableUntypedSuppliedUntypedElementValue() throws IOException {
- final ExternalVariableValueRep externalVariable = UntypedValueRep.value("world");
+ final ExternalVariableValueRep externalVariable;
+ if (useXmlnsPrefixes) {
+ externalVariable = UntypedValueRep.value("world");
+ } else {
+ externalVariable = UntypedValueRep.value("world");
+ }
queryPostWithExternalVariable(HttpStatus.OK_200, null, externalVariable);
}
@Test
public void queryPostWithExternalVariableUntypedSuppliedElement() throws IOException {
- final ExternalVariableValueRep externalVariable = value(Type.ELEMENT, "world");
+ final ExternalVariableValueRep externalVariable;
+ if (useXmlnsPrefixes) {
+ externalVariable = value(Type.ELEMENT, "world");
+ } else {
+ externalVariable = value(Type.ELEMENT, "world");
+ }
queryPostWithExternalVariable(HttpStatus.OK_200, null, externalVariable);
}
@@ -339,31 +367,56 @@ public void queryPostWithExternalVariableElementSuppliedEmpty() throws IOExcepti
@Test
public void queryPostWithExternalVariableElementSuppliedElement() throws IOException {
- final ExternalVariableValueRep externalVariable = value(Type.ELEMENT, "world");
+ final ExternalVariableValueRep externalVariable;
+ if (useXmlnsPrefixes) {
+ externalVariable = value(Type.ELEMENT, "world");
+ } else {
+ externalVariable = value(Type.ELEMENT, "world");
+ }
queryPostWithExternalVariable(HttpStatus.OK_200, "element()", externalVariable);
}
@Test
public void queryPostWithExternalVariableElementSuppliedElements() throws IOException {
- final ExternalVariableValueRep[] externalVariable = new ExternalVariableValueRep[] { UntypedValueRep.value("world"), UntypedValueRep.value("see you soon") };
+ final ExternalVariableValueRep[] externalVariable;
+ if (useXmlnsPrefixes) {
+ externalVariable = new ExternalVariableValueRep[] { UntypedValueRep.value("world"), UntypedValueRep.value("see you soon") };
+ } else {
+ externalVariable = new ExternalVariableValueRep[] { UntypedValueRep.value("world"), UntypedValueRep.value("see you soon") };
+ }
queryPostWithExternalVariable(HttpStatus.BAD_REQUEST_400, "element()", externalVariable);
}
@Test
public void queryPostWithExternalVariableElementSuppliedUntyped() throws IOException {
- final ExternalVariableValueRep externalVariable = UntypedValueRep.value("world");
+ final ExternalVariableValueRep externalVariable;
+ if (useXmlnsPrefixes) {
+ externalVariable = UntypedValueRep.value("world");
+ } else {
+ externalVariable = UntypedValueRep.value("world");
+ }
queryPostWithExternalVariable(HttpStatus.OK_200, "element()", externalVariable);
}
@Test
public void queryPostWithExternalVariableUntypedSuppliedUntypedElements() throws IOException {
- final ExternalVariableValueRep[] externalVariable = new ExternalVariableValueRep[] { UntypedValueRep.value("world"), UntypedValueRep.value("see you soon") };
+ final ExternalVariableValueRep[] externalVariable;
+ if (useXmlnsPrefixes) {
+ externalVariable = new ExternalVariableValueRep[] { UntypedValueRep.value("world"), UntypedValueRep.value("see you soon") };
+ } else {
+ externalVariable = new ExternalVariableValueRep[] { UntypedValueRep.value("world"), UntypedValueRep.value("see you soon") };
+ }
queryPostWithExternalVariable(HttpStatus.OK_200, null, externalVariable);
}
@Test
public void queryPostWithExternalVariableUntypedSuppliedElements() throws IOException {
- final ExternalVariableValueRep[] externalVariable = new ExternalVariableValueRep[] { value(Type.ELEMENT, "world"), value(Type.ELEMENT, "see you soon") };
+ final ExternalVariableValueRep[] externalVariable;
+ if (useXmlnsPrefixes) {
+ externalVariable = new ExternalVariableValueRep[] { value(Type.ELEMENT, "world"), value(Type.ELEMENT, "see you soon") };
+ } else {
+ externalVariable = new ExternalVariableValueRep[] { value(Type.ELEMENT, "world"), value(Type.ELEMENT, "see you soon") };
+ }
queryPostWithExternalVariable(HttpStatus.OK_200, null, externalVariable);
}
@@ -380,19 +433,34 @@ public void queryPostWithExternalVariableOptElementSuppliedEmpty() throws IOExce
@Test
public void queryPostWithExternalVariableOptElementSuppliedElement() throws IOException {
- final ExternalVariableValueRep externalVariable = value(Type.ELEMENT, "world");
+ final ExternalVariableValueRep externalVariable;
+ if (useXmlnsPrefixes) {
+ externalVariable = value(Type.ELEMENT, "world");
+ } else {
+ externalVariable = value(Type.ELEMENT, "world");
+ }
queryPostWithExternalVariable(HttpStatus.OK_200, "element()?", externalVariable);
}
@Test
public void queryPostWithExternalVariableOptElementSuppliedElements() throws IOException {
- final ExternalVariableValueRep[] externalVariable = new ExternalVariableValueRep[] { value(Type.ELEMENT, "world"), value(Type.ELEMENT, "see you soon") };
+ final ExternalVariableValueRep[] externalVariable;
+ if (useXmlnsPrefixes) {
+ externalVariable = new ExternalVariableValueRep[] { value(Type.ELEMENT, "world"), value(Type.ELEMENT, "see you soon") };
+ } else {
+ externalVariable = new ExternalVariableValueRep[] { value(Type.ELEMENT, "world"), value(Type.ELEMENT, "see you soon") };
+ }
queryPostWithExternalVariable(HttpStatus.BAD_REQUEST_400, "element()?", externalVariable);
}
@Test
public void queryPostWithExternalVariableOptElementSuppliedUntyped() throws IOException {
- final ExternalVariableValueRep externalVariable = UntypedValueRep.value("world");
+ final ExternalVariableValueRep externalVariable;
+ if (useXmlnsPrefixes) {
+ externalVariable = UntypedValueRep.value("world");
+ } else {
+ externalVariable = UntypedValueRep.value("world");
+ }
queryPostWithExternalVariable(HttpStatus.OK_200, "element()?", externalVariable);
}
@@ -409,25 +477,45 @@ public void queryPostWithExternalVariableElementsSuppliedEmpty() throws IOExcept
@Test
public void queryPostWithExternalVariableElementsSuppliedElement() throws IOException {
- final ExternalVariableValueRep externalVariable = value(Type.ELEMENT, "world");
+ final ExternalVariableValueRep externalVariable;
+ if (useXmlnsPrefixes) {
+ externalVariable = value(Type.ELEMENT, "world");
+ } else {
+ externalVariable = value(Type.ELEMENT, "world");
+ }
queryPostWithExternalVariable(HttpStatus.OK_200, "element()+", externalVariable);
}
@Test
public void queryPostWithExternalVariableElementsSuppliedElements() throws IOException {
- final ExternalVariableValueRep[] externalVariable = new ExternalVariableValueRep[] { value(Type.ELEMENT, "world"), value(Type.ELEMENT, "see you soon") };
+ final ExternalVariableValueRep[] externalVariable;
+ if (useXmlnsPrefixes) {
+ externalVariable = new ExternalVariableValueRep[] { value(Type.ELEMENT, "world"), value(Type.ELEMENT, "see you soon") };
+ } else {
+ externalVariable = new ExternalVariableValueRep[] { value(Type.ELEMENT, "world"), value(Type.ELEMENT, "see you soon") };
+ }
queryPostWithExternalVariable(HttpStatus.OK_200, "element()+", externalVariable);
}
@Test
public void queryPostWithExternalVariableElementsSuppliedUntyped() throws IOException {
- final ExternalVariableValueRep[] externalVariable = new ExternalVariableValueRep[] { UntypedValueRep.value("world") };
+final ExternalVariableValueRep[] externalVariable;
+ if (useXmlnsPrefixes) {
+ externalVariable = new ExternalVariableValueRep[] { UntypedValueRep.value("world") };
+ } else {
+ externalVariable = new ExternalVariableValueRep[] { UntypedValueRep.value("world") };
+ }
queryPostWithExternalVariable(HttpStatus.OK_200, "element()+", externalVariable);
}
@Test
public void queryPostWithExternalVariableElementsSuppliedUntypeds() throws IOException {
- final ExternalVariableValueRep[] externalVariable = new ExternalVariableValueRep[] { UntypedValueRep.value("world"), UntypedValueRep.value("see you soon") };
+ final ExternalVariableValueRep[] externalVariable;
+ if (useXmlnsPrefixes) {
+ externalVariable = new ExternalVariableValueRep[] { UntypedValueRep.value("world"), UntypedValueRep.value("see you soon") };
+ } else {
+ externalVariable = new ExternalVariableValueRep[] { UntypedValueRep.value("world"), UntypedValueRep.value("see you soon") };
+ }
queryPostWithExternalVariable(HttpStatus.OK_200, "element()+", externalVariable);
}
@@ -444,37 +532,67 @@ public void queryPostWithExternalVariableElementzSuppliedEmpty() throws IOExcept
@Test
public void queryPostWithExternalVariableElementzSuppliedElement() throws IOException {
- final ExternalVariableValueRep externalVariable = value(Type.ELEMENT, "world");
+ final ExternalVariableValueRep externalVariable;
+ if (useXmlnsPrefixes) {
+ externalVariable = value(Type.ELEMENT, "world");
+ } else {
+ externalVariable = value(Type.ELEMENT, "world");
+ }
queryPostWithExternalVariable(HttpStatus.OK_200, "element()*", externalVariable);
}
@Test
public void queryPostWithExternalVariableElementzSuppliedElements() throws IOException {
- final ExternalVariableValueRep[] externalVariable = new ExternalVariableValueRep[] { value(Type.ELEMENT, "world"), value(Type.ELEMENT, "see you soon") };
+ final ExternalVariableValueRep[] externalVariable;
+ if (useXmlnsPrefixes) {
+ externalVariable = new ExternalVariableValueRep[] { value(Type.ELEMENT, "world"), value(Type.ELEMENT, "see you soon") };
+ } else {
+ externalVariable = new ExternalVariableValueRep[] { value(Type.ELEMENT, "world"), value(Type.ELEMENT, "see you soon") };
+ }
queryPostWithExternalVariable(HttpStatus.OK_200, "element()*", externalVariable);
}
@Test
public void queryPostWithExternalVariableElementszSuppliedUntyped() throws IOException {
- final ExternalVariableValueRep[] externalVariable = new ExternalVariableValueRep[] { UntypedValueRep.value("world") };
+ final ExternalVariableValueRep[] externalVariable;
+ if (useXmlnsPrefixes) {
+ externalVariable = new ExternalVariableValueRep[] { UntypedValueRep.value("world") };
+ } else {
+ externalVariable = new ExternalVariableValueRep[] { UntypedValueRep.value("world") };
+ }
queryPostWithExternalVariable(HttpStatus.OK_200, "element()*", externalVariable);
}
@Test
public void queryPostWithExternalVariableElementzSuppliedUntypeds() throws IOException {
- final ExternalVariableValueRep[] externalVariable = new ExternalVariableValueRep[] { UntypedValueRep.value("world"), UntypedValueRep.value("see you soon") };
+ final ExternalVariableValueRep[] externalVariable;
+ if (useXmlnsPrefixes) {
+ externalVariable = new ExternalVariableValueRep[] { UntypedValueRep.value("world"), UntypedValueRep.value("see you soon") };
+ } else {
+ externalVariable = new ExternalVariableValueRep[] { UntypedValueRep.value("world"), UntypedValueRep.value("see you soon") };
+ }
queryPostWithExternalVariable(HttpStatus.OK_200, "element()*", externalVariable);
}
@Test
public void queryPostWithExternalVariableUntypedSuppliedUntypedDocument() throws IOException {
- final ExternalVariableValueRep externalVariable = UntypedValueRep.value("world");
+ final ExternalVariableValueRep externalVariable;
+ if (useXmlnsPrefixes) {
+ externalVariable = UntypedValueRep.value("world");
+ } else {
+ externalVariable = UntypedValueRep.value("world");
+ }
queryPostWithExternalVariable(HttpStatus.OK_200, null, externalVariable);
}
@Test
public void queryPostWithExternalVariableUntypedSuppliedDocument() throws IOException {
- final ExternalVariableValueRep externalVariable = value(Type.DOCUMENT, "world");
+ final ExternalVariableValueRep externalVariable;
+ if (useXmlnsPrefixes) {
+ externalVariable = value(Type.DOCUMENT, "world");
+ } else {
+ externalVariable = value(Type.DOCUMENT, "world");
+ }
queryPostWithExternalVariable(HttpStatus.OK_200, null, externalVariable);
}
@@ -491,32 +609,57 @@ public void queryPostWithExternalVariableDocumentSuppliedEmpty() throws IOExcept
@Test
public void queryPostWithExternalVariableDocumentSuppliedDocument() throws IOException {
- final ExternalVariableValueRep externalVariable = value(Type.DOCUMENT, "world");
+ final ExternalVariableValueRep externalVariable;
+ if (useXmlnsPrefixes) {
+ externalVariable = value(Type.DOCUMENT, "world");
+ } else {
+ externalVariable = value(Type.DOCUMENT, "world");
+ }
queryPostWithExternalVariable(HttpStatus.OK_200, "document-node()", externalVariable);
}
@Test
public void queryPostWithExternalVariableDocumentSuppliedDocuments() throws IOException {
- final ExternalVariableValueRep[] externalVariable = new ExternalVariableValueRep[] { UntypedValueRep.value("world"), UntypedValueRep.value("see you soon") };
+ final ExternalVariableValueRep[] externalVariable;
+ if (useXmlnsPrefixes) {
+ externalVariable = new ExternalVariableValueRep[] { UntypedValueRep.value("world"), UntypedValueRep.value("see you soon") };
+ } else {
+ externalVariable = new ExternalVariableValueRep[] { UntypedValueRep.value("world"), UntypedValueRep.value("see you soon") };
+ }
queryPostWithExternalVariable(HttpStatus.BAD_REQUEST_400, "document-node()", externalVariable);
}
@Test
public void queryPostWithExternalVariableDocumentSuppliedUntyped() throws IOException {
- final ExternalVariableValueRep externalVariable = UntypedValueRep.value("world");
+ final ExternalVariableValueRep externalVariable;
+ if (useXmlnsPrefixes) {
+ externalVariable = UntypedValueRep.value("world");
+ } else {
+ externalVariable = UntypedValueRep.value("world");
+ }
final String expectedResponseError = "/db/test/test.xmlerr:XPTY0004 Invalid type for variable $local:my-variable. Expected document-node(), got element()";
queryPostWithExternalVariable(Tuple(HttpStatus.BAD_REQUEST_400, expectedResponseError), "document-node()", externalVariable);
}
@Test
public void queryPostWithExternalVariableUntypedSuppliedUntypedDocuments() throws IOException {
- final ExternalVariableValueRep[] externalVariable = new ExternalVariableValueRep[] { UntypedValueRep.value("world"), UntypedValueRep.value("see you soon") };
+ final ExternalVariableValueRep[] externalVariable;
+ if (useXmlnsPrefixes) {
+ externalVariable = new ExternalVariableValueRep[] { UntypedValueRep.value("world"), UntypedValueRep.value("see you soon") };
+ } else {
+ externalVariable = new ExternalVariableValueRep[] { UntypedValueRep.value("world"), UntypedValueRep.value("see you soon") };
+ }
queryPostWithExternalVariable(HttpStatus.OK_200, null, externalVariable);
}
@Test
public void queryPostWithExternalVariableUntypedSuppliedDocuments() throws IOException {
- final ExternalVariableValueRep[] externalVariable = new ExternalVariableValueRep[] { value(Type.DOCUMENT, "world"), value(Type.DOCUMENT, "see you soon") };
+ final ExternalVariableValueRep[] externalVariable;
+ if (useXmlnsPrefixes) {
+ externalVariable = new ExternalVariableValueRep[] { value(Type.DOCUMENT, "world"), value(Type.DOCUMENT, "see you soon") };
+ } else {
+ externalVariable = new ExternalVariableValueRep[] { value(Type.DOCUMENT, "world"), value(Type.DOCUMENT, "see you soon") };
+ }
queryPostWithExternalVariable(HttpStatus.OK_200, null, externalVariable);
}
@@ -533,19 +676,34 @@ public void queryPostWithExternalVariableOptDocumentSuppliedEmpty() throws IOExc
@Test
public void queryPostWithExternalVariableOptDocumentSuppliedDocument() throws IOException {
- final ExternalVariableValueRep externalVariable = value(Type.DOCUMENT, "world");
+ final ExternalVariableValueRep externalVariable;
+ if (useXmlnsPrefixes) {
+ externalVariable = value(Type.DOCUMENT, "world");
+ } else {
+ externalVariable = value(Type.DOCUMENT, "world");
+ }
queryPostWithExternalVariable(HttpStatus.OK_200, "document-node()?", externalVariable);
}
@Test
public void queryPostWithExternalVariableOptDocumentSuppliedDocuments() throws IOException {
- final ExternalVariableValueRep[] externalVariable = new ExternalVariableValueRep[] { value(Type.DOCUMENT, "world"), value(Type.DOCUMENT, "see you soon") };
+ final ExternalVariableValueRep[] externalVariable;
+ if (useXmlnsPrefixes) {
+ externalVariable = new ExternalVariableValueRep[] { value(Type.DOCUMENT, "world"), value(Type.DOCUMENT, "see you soon") };
+ } else {
+ externalVariable = new ExternalVariableValueRep[] { value(Type.DOCUMENT, "world"), value(Type.DOCUMENT, "see you soon") };
+ }
queryPostWithExternalVariable(HttpStatus.BAD_REQUEST_400, "document-node()?", externalVariable);
}
@Test
public void queryPostWithExternalVariableOptDocumentSuppliedUntyped() throws IOException {
- final ExternalVariableValueRep externalVariable = UntypedValueRep.value("world");
+ final ExternalVariableValueRep externalVariable;
+ if (useXmlnsPrefixes) {
+ externalVariable = UntypedValueRep.value("world");
+ } else {
+ externalVariable = UntypedValueRep.value("world");
+ }
final String expectedResponseError = "/db/test/test.xmlerr:XPTY0004 Invalid type for variable $local:my-variable. Expected document-node(), got element()";
queryPostWithExternalVariable(Tuple(HttpStatus.BAD_REQUEST_400, expectedResponseError), "document-node()?", externalVariable);
}
@@ -563,26 +721,46 @@ public void queryPostWithExternalVariableDocumentsSuppliedEmpty() throws IOExcep
@Test
public void queryPostWithExternalVariableDocumentsSuppliedDocument() throws IOException {
- final ExternalVariableValueRep externalVariable = value(Type.DOCUMENT, "world");
+ final ExternalVariableValueRep externalVariable;
+ if (useXmlnsPrefixes) {
+ externalVariable = value(Type.DOCUMENT, "world");
+ } else {
+ externalVariable = value(Type.DOCUMENT, "world");
+ }
queryPostWithExternalVariable(HttpStatus.OK_200, "document-node()+", externalVariable);
}
@Test
public void queryPostWithExternalVariableDocumentsSuppliedDocuments() throws IOException {
- final ExternalVariableValueRep[] externalVariable = new ExternalVariableValueRep[] { value(Type.DOCUMENT, "world"), value(Type.DOCUMENT, "see you soon") };
+ final ExternalVariableValueRep[] externalVariable;
+ if (useXmlnsPrefixes) {
+ externalVariable = new ExternalVariableValueRep[] { value(Type.DOCUMENT, "world"), value(Type.DOCUMENT, "see you soon") };
+ } else {
+ externalVariable = new ExternalVariableValueRep[] { value(Type.DOCUMENT, "world"), value(Type.DOCUMENT, "see you soon") };
+ }
queryPostWithExternalVariable(HttpStatus.OK_200, "document-node()+", externalVariable);
}
@Test
public void queryPostWithExternalVariableDocumentsSuppliedUntyped() throws IOException {
- final ExternalVariableValueRep[] externalVariable = new ExternalVariableValueRep[] { UntypedValueRep.value("world") };
+ final ExternalVariableValueRep[] externalVariable;
+ if (useXmlnsPrefixes) {
+ externalVariable = new ExternalVariableValueRep[] { UntypedValueRep.value("world") };
+ } else {
+ externalVariable = new ExternalVariableValueRep[] { UntypedValueRep.value("world") };
+ }
final String expectedResponseError = "/db/test/test.xmlerr:XPTY0004 Invalid type for variable $local:my-variable. Expected document-node(), got element()";
queryPostWithExternalVariable(Tuple(HttpStatus.BAD_REQUEST_400, expectedResponseError), "document-node()+", externalVariable);
}
@Test
public void queryPostWithExternalVariableDocumentsSuppliedUntypeds() throws IOException {
- final ExternalVariableValueRep[] externalVariable = new ExternalVariableValueRep[] { UntypedValueRep.value("world"), UntypedValueRep.value("see you soon") };
+ final ExternalVariableValueRep[] externalVariable;
+ if (useXmlnsPrefixes) {
+ externalVariable = new ExternalVariableValueRep[] { UntypedValueRep.value("world"), UntypedValueRep.value("see you soon") };
+ } else {
+ externalVariable = new ExternalVariableValueRep[] { UntypedValueRep.value("world"), UntypedValueRep.value("see you soon") };
+ }
final String expectedResponseError = "/db/test/test.xmlerr:XPTY0004 Invalid type for variable $local:my-variable. Expected document-node(), got element()";
queryPostWithExternalVariable(Tuple(HttpStatus.BAD_REQUEST_400, expectedResponseError), "document-node()+", externalVariable);
}
@@ -600,26 +778,46 @@ public void queryPostWithExternalVariableDocumentzSuppliedEmpty() throws IOExcep
@Test
public void queryPostWithExternalVariableDocumentzSuppliedDocument() throws IOException {
- final ExternalVariableValueRep externalVariable = value(Type.DOCUMENT, "world");
+ final ExternalVariableValueRep externalVariable;
+ if (useXmlnsPrefixes) {
+ externalVariable = value(Type.DOCUMENT, "world");
+ } else {
+ externalVariable = value(Type.DOCUMENT, "world");
+ }
queryPostWithExternalVariable(HttpStatus.OK_200, "document-node()*", externalVariable);
}
@Test
public void queryPostWithExternalVariableDocumentzSuppliedDocuments() throws IOException {
- final ExternalVariableValueRep[] externalVariable = new ExternalVariableValueRep[] { value(Type.DOCUMENT, "world"), value(Type.DOCUMENT, "see you soon") };
+ final ExternalVariableValueRep[] externalVariable;
+ if (useXmlnsPrefixes) {
+ externalVariable = new ExternalVariableValueRep[] { value(Type.DOCUMENT, "world"), value(Type.DOCUMENT, "see you soon") };
+ } else {
+ externalVariable = new ExternalVariableValueRep[] { value(Type.DOCUMENT, "world"), value(Type.DOCUMENT, "see you soon") };
+ }
queryPostWithExternalVariable(HttpStatus.OK_200, "document-node()*", externalVariable);
}
@Test
public void queryPostWithExternalVariableDocumentszSuppliedUntyped() throws IOException {
- final ExternalVariableValueRep[] externalVariable = new ExternalVariableValueRep[] { UntypedValueRep.value("world") };
+ final ExternalVariableValueRep[] externalVariable;
+ if (useXmlnsPrefixes) {
+ externalVariable = new ExternalVariableValueRep[] { UntypedValueRep.value("world") };
+ } else {
+ externalVariable = new ExternalVariableValueRep[] { UntypedValueRep.value("world") };
+ }
final String expectedResponseError = "/db/test/test.xmlerr:XPTY0004 Invalid type for variable $local:my-variable. Expected document-node(), got element()";
queryPostWithExternalVariable(Tuple(HttpStatus.BAD_REQUEST_400, expectedResponseError), "document-node()*", externalVariable);
}
@Test
public void queryPostWithExternalVariableDocumentzSuppliedUntypeds() throws IOException {
- final ExternalVariableValueRep[] externalVariable = new ExternalVariableValueRep[] { UntypedValueRep.value("world"), UntypedValueRep.value("see you soon") };
+ final ExternalVariableValueRep[] externalVariable;
+ if (useXmlnsPrefixes) {
+ externalVariable = new ExternalVariableValueRep[] { UntypedValueRep.value("world"), UntypedValueRep.value("see you soon") };
+ } else {
+ externalVariable = new ExternalVariableValueRep[] { UntypedValueRep.value("world"), UntypedValueRep.value("see you soon") };
+ }
final String expectedResponseError = "/db/test/test.xmlerr:XPTY0004 Invalid type for variable $local:my-variable. Expected document-node(), got element()";
queryPostWithExternalVariable(Tuple(HttpStatus.BAD_REQUEST_400, expectedResponseError), "document-node()*", externalVariable);
}
@@ -1622,6 +1820,75 @@ public void queryPostWithExternalVariableMapzSuppliedUntypeds() throws IOExcepti
queryPostWithExternalVariable(HttpStatus.OK_200, "map(*)*", externalVariable);
}
+ @Test
+ public void queryPostWrappedTypedWithExternalVariableStringConstructElement() throws IOException {
+ queryPostWithExternalVariableStringConstructElement(true, true);
+ }
+
+ @Test
+ public void queryPostWrappedNotTypedWithExternalVariableStringConstructElement() throws IOException {
+ queryPostWithExternalVariableStringConstructElement(true, false);
+ }
+
+ @Test
+ public void queryPostNotWrappedTypedWithExternalVariableStringConstructElement() throws IOException {
+ queryPostWithExternalVariableStringConstructElement(false, true);
+ }
+
+ @Test
+ public void queryPostNotWrappedNotTypedWithExternalVariableStringConstructElement() throws IOException {
+ queryPostWithExternalVariableStringConstructElement(false, false);
+ }
+
+ private void queryPostWithExternalVariableStringConstructElement(final boolean wrap, final boolean typed) throws IOException {
+ final String query;
+ if (useXmlnsPrefixes) {
+ query = "\n" +
+ "\t\n" +
+ "\t\t\n" +
+ "\t\t\t\n" +
+ "\t\t\t\tmy-variable\n" +
+ "\t\t\t\n" +
+ "\t\t\t\n" +
+ "\t\t\t\tgreeting" +
+ "\t\t\t\n" +
+ "\t\t\n" +
+ "\t\n" +
+ "\t\n" +
+ "\n";
+ } else {
+ query = "\n" +
+ "\t\n" +
+ "\t\t\n" +
+ "\t\t\t\n" +
+ "\t\t\t\tmy-variable\n" +
+ "\t\t\t\n" +
+ "\t\t\t\n" +
+ "\t\t\t\tgreeting" +
+ "\t\t\t\n" +
+ "\t\t\n" +
+ "\t\n" +
+ "\t\n" +
+ "\n";
+ }
+
+ final HttpResponse response = doPostWithAuth(getResourceUri(), query);
+ final int resultStatusCode = response.getStatusLine()
+ .getStatusCode();
+
+ assertEquals("Server returned response code: " + resultStatusCode, HttpStatus.OK_200, resultStatusCode);
+
+ //final String actual = "Hello, world.";
+ final String actual = readResponse(response.getEntity());
+ assertThat(actual, hasXPath("//greeting[namespace-uri() = ''][text() = 'Hello, world.']").withNamespaceContext(NS_CONTEXT));
+ }
+
private void queryPostWithExternalVariable(final int expectedResponseCode, @Nullable final String xqExternalVariableType, final ExternalVariableValueRep... externalVariableSequence) throws IOException {
queryPostWithExternalVariable(Tuple(expectedResponseCode, null), externalVariableSequence, xqExternalVariableType, externalVariableSequence);
}
@@ -1791,38 +2058,73 @@ private static boolean isMap(final int xdmType, final ExternalVariableValueRep e
return xdmType == Type.MAP || (xdmType == Type.ITEM && externalVariableValueRep instanceof MapRep);
}
- private static String buildQueryExternalVariable(@Nullable final String xqExternalVariableType, @Nullable final ExternalVariableValueRep... externalVariableSequence) {
+ private String buildQueryExternalVariable(@Nullable final String xqExternalVariableType, @Nullable final ExternalVariableValueRep... externalVariableSequence) {
final StringBuilder builder = new StringBuilder();
- builder.append("\n");
- if (externalVariableSequence!= null) {
- builder.append("\t\n");
- builder.append("\t\t\n");
- builder.append("\t\t\tlocalmy-variable\n");
- buildQueryExternalVariableSequence(builder, 3, externalVariableSequence);
- builder.append("\t\t\n");
- builder.append("\t\n");
- }
+ if (useXmlnsPrefixes) {
+ builder.append("\n");
- builder.append("\t\n");
+ builder.append("\t\t\n");
+ builder.append("\t\t\tlocalmy-variable\n");
+ buildQueryExternalVariableSequence(builder, 3, externalVariableSequence);
+ builder.append("\t\t\n");
+ builder.append("\t\n");
+ }
+
+ builder.append("\t\n");
+ builder.append("\n");
+
+ } else {
+ builder.append("\n");
+
+ if (externalVariableSequence != null) {
+ builder.append("\t\n");
+ builder.append("\t\t\n");
+ builder.append("\t\t\tlocalmy-variable\n");
+ buildQueryExternalVariableSequence(builder, 3, externalVariableSequence);
+ builder.append("\t\t\n");
+ builder.append("\t\n");
+ }
+
+ builder.append("\t\n");
+ builder.append("\n");
}
- builder.append(" external;\n");
- builder.append("$local:my-variable\n");
- builder.append("\t]]>\n");
- builder.append("\n");
return builder.toString();
}
private static final char[] INDENTS = { '\t', '\t', '\t', '\t', '\t', '\t', '\t', '\t', '\t', '\t', '\t', '\t', '\t', '\t', '\t', '\t' };
- private static void buildQueryExternalVariableSequence(final StringBuilder builder, final int indentCount, final ExternalVariableValueRep... externalVariableSequence) {
- builder.append(INDENTS, 0, indentCount).append("\n");
+ private void buildQueryExternalVariableSequence(final StringBuilder builder, final int indentCount, final ExternalVariableValueRep... externalVariableSequence) {
+ if (useXmlnsPrefixes) {
+ builder.append(INDENTS, 0, indentCount).append("\n");
+ } else {
+ builder.append(INDENTS, 0, indentCount).append("\n");
+ }
+
for (final ExternalVariableValueRep externalVariableSequenceItem : externalVariableSequence) {
- builder.append(INDENTS, 0, indentCount + 1).append("\n");
- builder.append(INDENTS, 0, indentCount + 3).append("\n");
+ builder.append(INDENTS, 0, indentCount + 3).append("\n");
+ builder.append(INDENTS, 0, indentCount + 3).append("').append(key.getContent()).append("\n");
+ if (useXmlnsPrefixes) {
+ builder.append('>').append(key.getContent()).append("\n");
+ } else {
+ builder.append('>').append(key.getContent()).append("\n");
+ }
+
buildQueryExternalVariableSequence(builder, indentCount + 3, entryRep.value.values);
- builder.append(INDENTS, 0, indentCount + 2).append("\n");
+
+ if (useXmlnsPrefixes) {
+ builder.append(INDENTS, 0, indentCount + 2).append("\n");
+ } else {
+ builder.append(INDENTS, 0, indentCount + 2).append("\n");
+ }
}
builder.append(INDENTS, 0, indentCount + 1);
@@ -1862,9 +2180,18 @@ private static void buildQueryExternalVariableSequence(final StringBuilder build
builder.append(((ValueRep) externalVariableSequenceItem).getContent());
}
- builder.append("\n");
+ if (useXmlnsPrefixes) {
+ builder.append("\n");
+ } else {
+ builder.append("\n");
+ }
+ }
+
+ if (useXmlnsPrefixes) {
+ builder.append(INDENTS, 0, indentCount).append("\n");
+ } else {
+ builder.append(INDENTS, 0, indentCount).append("\n");
}
- builder.append(INDENTS, 0, indentCount).append("\n");
}
private static String getServerUri() {
diff --git a/exist-core/src/test/java/org/exist/xquery/EmbeddedBinariesTest.java b/exist-core/src/test/java/org/exist/xquery/EmbeddedBinariesTest.java
index 56c3aef0e6..530d4441dd 100644
--- a/exist-core/src/test/java/org/exist/xquery/EmbeddedBinariesTest.java
+++ b/exist-core/src/test/java/org/exist/xquery/EmbeddedBinariesTest.java
@@ -143,7 +143,7 @@ protected QueryResultAccessor executeXQuery(final String
consumer2E.accept(results);
} finally {
- //TODO(AR) performing #runCleanupTasks causes the stream to be closed, so if we do so before we are finished with the results, serialization fails.
+ // NOTE(AR) performing #runCleanupTasks causes the stream to be closed, so if we do so before we are finished with the results, serialization fails.
if (fContext != null) {
fContext.runCleanupTasks();
}
diff --git a/extensions/modules/file/src/test/java/org/exist/xquery/modules/file/EmbeddedBinariesTest.java b/extensions/modules/file/src/test/java/org/exist/xquery/modules/file/EmbeddedBinariesTest.java
index e51cdd042c..cfc3b21fba 100644
--- a/extensions/modules/file/src/test/java/org/exist/xquery/modules/file/EmbeddedBinariesTest.java
+++ b/extensions/modules/file/src/test/java/org/exist/xquery/modules/file/EmbeddedBinariesTest.java
@@ -147,7 +147,7 @@ protected QueryResultAccessor executeXQuery(final String
consumer2E.accept(results);
} finally {
- //TODO(AR) performing #runCleanupTasks causes the stream to be closed, so if we do so before we are finished with the results, serialization fails.
+ // NOTE(AR) performing #runCleanupTasks causes the stream to be closed, so if we do so before we are finished with the results, serialization fails.
if (fContext != null) {
fContext.runCleanupTasks();
}
diff --git a/schema/exist-rest-api.xsd b/schema/exist-rest-api.xsd
index ad34ef5511..da282f56f7 100644
--- a/schema/exist-rest-api.xsd
+++ b/schema/exist-rest-api.xsd
@@ -55,6 +55,26 @@
+
+
+ Context Item for the XQuery
+
+
+
+
+
+
+
+
+
+ Values for the Default Collection of the Dynamic Context
+
+
+
+
+
+
+
Properties to pass to the Serializer.