diff --git a/exist-core/pom.xml b/exist-core/pom.xml index d1c1e77a6e..9a6956048f 100644 --- a/exist-core/pom.xml +++ b/exist-core/pom.xml @@ -780,6 +780,7 @@ src/test/xquery/base-uri.xql src/test/xquery/parenthesizedLocationStep.xml src/test/xquery/tail-recursion.xml + src/test/xquery/indexing/indexes-base-uri.xq src/test/xquery/maps/maps.xqm src/test/xquery/numbers/format-numbers.xql src/test/xquery/util/util.xml @@ -865,6 +866,7 @@ src/main/java/org/exist/dom/QName.java src/main/java/org/exist/dom/memtree/AbstractCharacterData.java src/main/java/org/exist/dom/memtree/AttrImpl.java + src/main/java/org/exist/dom/memtree/CDATASectionImpl.java src/main/java/org/exist/dom/memtree/CommentImpl.java src/main/java/org/exist/dom/memtree/DocumentBuilderReceiver.java src/main/java/org/exist/dom/memtree/DocumentImpl.java @@ -884,6 +886,7 @@ src/test/java/org/exist/dom/persistent/BasicNodeSetTest.java src/main/java/org/exist/dom/persistent/BinaryDocument.java src/test/java/org/exist/dom/persistent/CDataIntergationTest.java + src/main/java/org/exist/dom/persistent/CDATASectionImpl.java src/main/java/org/exist/dom/persistent/CommentImpl.java src/test/java/org/exist/dom/persistent/CommentTest.java src/test/java/org/exist/dom/persistent/DefaultDocumentSetTest.java @@ -1086,6 +1089,7 @@ src/test/java/org/exist/util/CollationsTest.java src/main/java/org/exist/util/Configuration.java src/test/java/org/exist/util/DOMSerializerTest.java + src/main/java/org/exist/util/EXistURISchemeURIResolver.java src/test/java/org/exist/util/LeasableTest.java src/test/java/org/exist/util/MediaTypeResolverTest.java src/main/java/org/exist/util/MimeTable.java @@ -1347,6 +1351,7 @@ src/main/java/org/exist/xquery/functions/fn/transform/Options.java src/main/java/org/exist/xquery/functions/fn/transform/Transform.java src/main/java/org/exist/xquery/functions/fn/transform/TreeUtils.java + src/main/java/org/exist/xquery/functions/fn/transform/URIResolution.java src/test/java/org/exist/xquery/functions/inspect/InspectModuleTest.java src/main/java/org/exist/xquery/functions/integer/WordPicture.java src/main/java/org/exist/xquery/functions/map/MapExpr.java @@ -1390,6 +1395,7 @@ src/test/java/org/exist/xquery/functions/validate/JingSchematronTest.java src/test/java/org/exist/xquery/functions/validate/JingXsdTest.java src/main/java/org/exist/xquery/functions/validation/Jaxp.java + src/main/java/org/exist/xquery/functions/validation/Shared.java src/test/java/org/exist/xquery/functions/xmldb/DbStore2Test.java src/main/java/org/exist/xquery/functions/xmldb/XMLDBGetMimeType.java src/main/java/org/exist/xquery/functions/xmldb/XMLDBLoadFromPattern.java @@ -1491,6 +1497,7 @@ src/test/xquery/parenthesizedLocationStep.xml src/test/xquery/pi.xqm src/test/xquery/tail-recursion.xml + src/test/xquery/indexing/indexes-base-uri.xq src/test/xquery/maps/maps.xqm src/test/xquery/numbers/format-numbers.xql src/test/xquery/securitymanager/acl.xqm @@ -1578,7 +1585,8 @@ src/main/java/org/exist/dom/QName.java src/main/java/org/exist/dom/memtree/AbstractCharacterData.java src/main/java/org/exist/dom/memtree/AttrImpl.java - src/main/java/org/exist/dom/memtree/CommentImpl.java + src/main/java/org/exist/dom/memtree/CDATASectionImpl.java + src/main/java/org/exist/dom/memtree/CommentImpl.java src/main/java/org/exist/dom/memtree/DocumentBuilderReceiver.java src/main/java/org/exist/dom/memtree/DocumentImpl.java src/test/java/org/exist/dom/memtree/DocumentImplTest.java @@ -1605,6 +1613,7 @@ src/test/java/org/exist/dom/persistent/BasicNodeSetTest.java src/main/java/org/exist/dom/persistent/BinaryDocument.java src/test/java/org/exist/dom/persistent/CDataIntergationTest.java + src/main/java/org/exist/dom/persistent/CDATASectionImpl.java src/main/java/org/exist/dom/persistent/CommentImpl.java src/test/java/org/exist/dom/persistent/CommentTest.java src/test/java/org/exist/dom/persistent/DefaultDocumentSetTest.java @@ -1870,6 +1879,7 @@ src/test/java/org/exist/util/CollectionOfArrayIteratorTest.java src/main/java/org/exist/util/Configuration.java src/test/java/org/exist/util/DOMSerializerTest.java + src/main/java/org/exist/util/EXistURISchemeURIResolver.java src/main/java/org/exist/util/IPUtil.java src/main/java/org/exist/util/JREUtil.java src/test/java/org/exist/util/LeasableTest.java @@ -2163,6 +2173,7 @@ src/main/java/org/exist/xquery/functions/fn/transform/Options.java src/main/java/org/exist/xquery/functions/fn/transform/Transform.java src/main/java/org/exist/xquery/functions/fn/transform/TreeUtils.java + src/main/java/org/exist/xquery/functions/fn/transform/URIResolution.java src/test/java/org/exist/xquery/functions/inspect/InspectModuleTest.java src/main/java/org/exist/xquery/functions/integer/WordPicture.java src/main/java/org/exist/xquery/functions/map/MapExpr.java @@ -2213,6 +2224,7 @@ src/test/java/org/exist/xquery/functions/validate/JingSchematronTest.java src/test/java/org/exist/xquery/functions/validate/JingXsdTest.java src/main/java/org/exist/xquery/functions/validation/Jaxp.java + src/main/java/org/exist/xquery/functions/validation/Shared.java src/test/java/org/exist/xquery/functions/xmldb/AbstractXMLDBTest.java src/test/java/org/exist/xquery/functions/xmldb/DbStore2Test.java src/test/java/org/exist/xquery/functions/xmldb/XMLDBAuthenticateTest.java diff --git a/exist-core/src/main/java/org/exist/dom/memtree/CDATASectionImpl.java b/exist-core/src/main/java/org/exist/dom/memtree/CDATASectionImpl.java index 1a2ac78056..84c204af13 100644 --- a/exist-core/src/main/java/org/exist/dom/memtree/CDATASectionImpl.java +++ b/exist-core/src/main/java/org/exist/dom/memtree/CDATASectionImpl.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -25,8 +49,11 @@ import org.exist.xquery.value.Type; import org.w3c.dom.CDATASection; import org.w3c.dom.DOMException; +import org.w3c.dom.Node; import org.w3c.dom.Text; +import javax.annotation.Nullable; + /** * Represents a CDATA section. @@ -48,6 +75,15 @@ public int getItemType() { return Type.CDATA_SECTION; } + @Override + public @Nullable String getBaseURI() { + @Nullable final Node parent = getParentNode(); + if (parent == null) { + return null; + } + return parent.getBaseURI(); + } + @Override public Text splitText(final int offset) throws DOMException { return null; diff --git a/exist-core/src/main/java/org/exist/dom/persistent/AttrImpl.java b/exist-core/src/main/java/org/exist/dom/persistent/AttrImpl.java index 923164c52b..f32aba3022 100644 --- a/exist-core/src/main/java/org/exist/dom/persistent/AttrImpl.java +++ b/exist-core/src/main/java/org/exist/dom/persistent/AttrImpl.java @@ -57,6 +57,7 @@ import org.exist.util.XMLString; import org.exist.util.pool.NodePool; import org.exist.util.serializer.AttrList; +import org.exist.xmldb.XmldbURI; import org.exist.xquery.Expression; import org.w3c.dom.*; @@ -434,7 +435,12 @@ public boolean isId() { public @Nullable String getBaseURI() { @Nullable final Element e = getOwnerElement(); if (e != null) { - return e.getBaseURI(); + @Nullable String strBaseUri = e.getBaseURI(); + if (strBaseUri != null && strBaseUri.startsWith("/db/")) { + // Must be a URI! + strBaseUri = XmldbURI.EMBEDDED_SERVER_URI_PREFIX + strBaseUri; + } + return strBaseUri; } return null; } diff --git a/exist-core/src/main/java/org/exist/dom/persistent/CDATASectionImpl.java b/exist-core/src/main/java/org/exist/dom/persistent/CDATASectionImpl.java index e89bbbba47..6ddede486c 100644 --- a/exist-core/src/main/java/org/exist/dom/persistent/CDATASectionImpl.java +++ b/exist-core/src/main/java/org/exist/dom/persistent/CDATASectionImpl.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -27,12 +51,15 @@ import org.exist.util.ByteConversion; import org.exist.util.UTF8; import org.exist.util.XMLString; +import org.exist.xmldb.XmldbURI; import org.exist.xquery.Expression; import org.w3c.dom.CDATASection; import org.w3c.dom.DOMException; import org.w3c.dom.Node; import org.w3c.dom.Text; +import javax.annotation.Nullable; + public class CDATASectionImpl extends AbstractCharacterData implements CDATASection { public CDATASectionImpl() { @@ -77,6 +104,20 @@ public CDATASectionImpl(final Expression expression, final String data) { } @Override + public @Nullable String getBaseURI() { + @Nullable final Node parent = getParentNode(); + if (parent != null) { + @Nullable String strBaseUri = parent.getBaseURI(); + if (strBaseUri != null && strBaseUri.startsWith("/db/")) { + // Must be a URI! + strBaseUri = XmldbURI.EMBEDDED_SERVER_URI_PREFIX + strBaseUri; + } + return strBaseUri; + } else { + return null; + } + } + /** * Serializes a (persistent DOM) CDATA Section to a byte array * @@ -94,6 +135,7 @@ public CDATASectionImpl(final Expression expression, final String data) { * @return the returned byte array after use must be returned to the ByteArrayPool * by calling {@link ByteArrayPool#releaseByteArray(byte[])} */ + @Override public byte[] serialize() { final int nodeIdLen = nodeId.size(); final byte[] data = ByteArrayPool.getByteArray(LENGTH_SIGNATURE_LENGTH + NodeId.LENGTH_NODE_ID_UNITS + diff --git a/exist-core/src/main/java/org/exist/dom/persistent/CommentImpl.java b/exist-core/src/main/java/org/exist/dom/persistent/CommentImpl.java index 9ad5f108cb..2fb227708c 100644 --- a/exist-core/src/main/java/org/exist/dom/persistent/CommentImpl.java +++ b/exist-core/src/main/java/org/exist/dom/persistent/CommentImpl.java @@ -49,6 +49,7 @@ import org.exist.storage.Signatures; import org.exist.util.ByteConversion; import org.exist.util.pool.NodePool; +import org.exist.xmldb.XmldbURI; import org.exist.xquery.Expression; import org.w3c.dom.Comment; import org.w3c.dom.Node; @@ -92,7 +93,12 @@ public String toString() { public @Nullable String getBaseURI() { @Nullable final Node parent = getParentNode(); if (parent != null) { - return parent.getBaseURI(); + @Nullable String strBaseUri = parent.getBaseURI(); + if (strBaseUri != null && strBaseUri.startsWith("/db/")) { + // Must be a URI! + strBaseUri = XmldbURI.EMBEDDED_SERVER_URI_PREFIX + strBaseUri; + } + return strBaseUri; } else { return null; } diff --git a/exist-core/src/main/java/org/exist/dom/persistent/DocumentImpl.java b/exist-core/src/main/java/org/exist/dom/persistent/DocumentImpl.java index 21903f63f3..de13604b03 100644 --- a/exist-core/src/main/java/org/exist/dom/persistent/DocumentImpl.java +++ b/exist-core/src/main/java/org/exist/dom/persistent/DocumentImpl.java @@ -1592,7 +1592,7 @@ public Node renameNode(final Node n, final String namespaceURI, final String qua @Override public String getBaseURI() { - return getURI().toString(); + return XmldbURI.EMBEDDED_SERVER_URI_PREFIX + getURI().getCollectionPath(); } @Override diff --git a/exist-core/src/main/java/org/exist/dom/persistent/ElementImpl.java b/exist-core/src/main/java/org/exist/dom/persistent/ElementImpl.java index 0f4403f7bf..3c2fe2feec 100644 --- a/exist-core/src/main/java/org/exist/dom/persistent/ElementImpl.java +++ b/exist-core/src/main/java/org/exist/dom/persistent/ElementImpl.java @@ -2021,7 +2021,12 @@ public void setIdAttributeNode(final Attr idAttr, final boolean isId) throws DOM public @Nullable String getBaseURI() { @Nullable final XmldbURI baseURI = calculateBaseURI(); if (baseURI != null) { - return baseURI.toString(); + String strBaseUri = baseURI.toString(); + if (strBaseUri.startsWith("/db/")) { + // Must be a URI! + strBaseUri = XmldbURI.EMBEDDED_SERVER_URI_PREFIX + baseURI; + } + return strBaseUri; } return null; diff --git a/exist-core/src/main/java/org/exist/dom/persistent/ProcessingInstructionImpl.java b/exist-core/src/main/java/org/exist/dom/persistent/ProcessingInstructionImpl.java index 6a42f27b0e..5c2d8124bb 100644 --- a/exist-core/src/main/java/org/exist/dom/persistent/ProcessingInstructionImpl.java +++ b/exist-core/src/main/java/org/exist/dom/persistent/ProcessingInstructionImpl.java @@ -50,6 +50,7 @@ import org.exist.storage.Signatures; import org.exist.util.ByteConversion; import org.exist.util.pool.NodePool; +import org.exist.xmldb.XmldbURI; import org.exist.xquery.Expression; import org.w3c.dom.DOMException; import org.w3c.dom.Node; @@ -154,7 +155,12 @@ public void setData(final String data) { public @Nullable String getBaseURI() { @Nullable final StoredNode parent = getParentStoredNode(); if (parent != null) { - return parent.getBaseURI(); + @Nullable String strBaseUri = parent.getBaseURI(); + if (strBaseUri != null && strBaseUri.startsWith("/db/")) { + // Must be a URI! + strBaseUri = XmldbURI.EMBEDDED_SERVER_URI_PREFIX + strBaseUri; + } + return strBaseUri; } else { return getOwnerDocument().getBaseURI(); } diff --git a/exist-core/src/main/java/org/exist/dom/persistent/TextImpl.java b/exist-core/src/main/java/org/exist/dom/persistent/TextImpl.java index 6c9d9c8971..a0ba26b9ce 100644 --- a/exist-core/src/main/java/org/exist/dom/persistent/TextImpl.java +++ b/exist-core/src/main/java/org/exist/dom/persistent/TextImpl.java @@ -52,6 +52,7 @@ import org.exist.util.ByteConversion; import org.exist.util.UTF8; import org.exist.util.pool.NodePool; +import org.exist.xmldb.XmldbURI; import org.exist.xquery.Expression; import org.w3c.dom.DOMException; import org.w3c.dom.Node; @@ -180,7 +181,12 @@ public Text splitText(final int offset) throws DOMException { public @Nullable String getBaseURI() { @Nullable final Node parent = getParentNode(); if (parent != null) { - return parent.getBaseURI(); + @Nullable String strBaseUri = parent.getBaseURI(); + if (strBaseUri != null && strBaseUri.startsWith("/db/")) { + // Must be a URI! + strBaseUri = XmldbURI.EMBEDDED_SERVER_URI_PREFIX + strBaseUri; + } + return strBaseUri; } else { return null; } diff --git a/exist-core/src/main/java/org/exist/util/EXistURISchemeURIResolver.java b/exist-core/src/main/java/org/exist/util/EXistURISchemeURIResolver.java index f378dee2ef..41628cc190 100644 --- a/exist-core/src/main/java/org/exist/util/EXistURISchemeURIResolver.java +++ b/exist-core/src/main/java/org/exist/util/EXistURISchemeURIResolver.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -56,6 +80,8 @@ private String rewriteScheme(String uri) { uri = uri.replace("exist://localhost/db", "/db"); } else if (uri.startsWith("exist://")) { uri = uri.replace("exist://", "xmldb:exist://"); + } else if (uri.startsWith("exist:/")) { + uri = uri.replace("exist:/", "xmldb:exist:///"); } } diff --git a/exist-core/src/main/java/org/exist/xquery/functions/fn/transform/Options.java b/exist-core/src/main/java/org/exist/xquery/functions/fn/transform/Options.java index 788ade00e6..98ee6dd178 100644 --- a/exist-core/src/main/java/org/exist/xquery/functions/fn/transform/Options.java +++ b/exist-core/src/main/java/org/exist/xquery/functions/fn/transform/Options.java @@ -56,6 +56,7 @@ import org.exist.dom.memtree.NamespaceNode; import org.exist.dom.persistent.NodeProxy; import org.exist.security.PermissionDeniedException; +import org.exist.xmldb.XmldbURI; import org.exist.xquery.ErrorCodes; import org.exist.xquery.XPathException; import org.exist.xquery.XQueryContext; @@ -490,7 +491,13 @@ private Tuple2 getStylesheet(final MapType options) throws XPath final List> results = new ArrayList<>(1); final Optional stylesheetLocation = Options.STYLESHEET_LOCATION.get(options).map(StringValue::getStringValue); if (stylesheetLocation.isPresent()) { - results.add(Tuple(stylesheetLocation.get(), resolveStylesheetLocation(stylesheetLocation.get()))); + final String strStylesheetLocationUri; + if (stylesheetLocation.get().startsWith("/db/")) { + strStylesheetLocationUri = XmldbURI.EMBEDDED_SERVER_URI_PREFIX + stylesheetLocation.get(); + } else { + strStylesheetLocationUri = stylesheetLocation.get(); + } + results.add(Tuple(strStylesheetLocationUri, resolveStylesheetLocation(stylesheetLocation.get()))); } final Optional stylesheetNode = Options.STYLESHEET_NODE.get(options).map(NodeValue::getNode); diff --git a/exist-core/src/main/java/org/exist/xquery/functions/fn/transform/Transform.java b/exist-core/src/main/java/org/exist/xquery/functions/fn/transform/Transform.java index 8cfadd1ccc..215ceea43e 100644 --- a/exist-core/src/main/java/org/exist/xquery/functions/fn/transform/Transform.java +++ b/exist-core/src/main/java/org/exist/xquery/functions/fn/transform/Transform.java @@ -251,22 +251,24 @@ private XsltExecutable compileExecutable(final Options options) throws XPathExce xsltCompiler.setParameter(new net.sf.saxon.s9api.QName(qKey.getPrefix(), qKey.getLocalPart()), value); } - // Take URI resolution into our own hands when there is no base - xsltCompiler.setURIResolver((href, base) -> { - try { - final URI hrefURI = URI.create(href); - if ((!options.resolvedStylesheetBaseURI.isPresent()) && !hrefURI.isAbsolute() && isNullOrEmpty(base)) { - final XPathException resolutionException = new XPathException(fnTransform, - ErrorCodes.XTSE0165, - "transform using a relative href, \n" + - "using option stylesheet-text, but without stylesheet-base-uri"); - throw new TransformerException(resolutionException); + xsltCompiler.setURIResolver(new URIResolution.CompileTimeURIResolver(context, fnTransform) { + @Override public Source resolve(final String href, final String base) throws TransformerException { + // Correct error from URI resolution when there is no base + try { + final URI hrefURI = URI.create(href); + if ((!options.resolvedStylesheetBaseURI.isPresent()) && !hrefURI.isAbsolute() && isNullOrEmpty(base)) { + final XPathException resolutionException = new XPathException(fnTransform, + ErrorCodes.XTSE0165, + "transform using a relative href, \n" + + "using option stylesheet-text, but without stylesheet-base-uri"); + throw new TransformerException(resolutionException); + } + } catch (final IllegalArgumentException e) { + throw new TransformerException(e); } - } catch (final IllegalArgumentException e) { - throw new TransformerException(e); - } - // Pass it back - return null; + // Checked the special error case, defer to eXist resolution + return super.resolve(href, base); + }; }); try { diff --git a/exist-core/src/main/java/org/exist/xquery/functions/fn/transform/URIResolution.java b/exist-core/src/main/java/org/exist/xquery/functions/fn/transform/URIResolution.java new file mode 100644 index 0000000000..c61da90924 --- /dev/null +++ b/exist-core/src/main/java/org/exist/xquery/functions/fn/transform/URIResolution.java @@ -0,0 +1,160 @@ +/* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * + * eXist-db Open Source Native XML Database + * Copyright (C) 2001 The eXist-db Authors + * + * info@exist-db.org + * http://www.exist-db.org + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +package org.exist.xquery.functions.fn.transform; + +import org.exist.dom.persistent.NodeProxy; +import org.exist.security.PermissionDeniedException; +import org.exist.xmldb.XmldbURI; +import org.exist.xquery.ErrorCodes; +import org.exist.xquery.Expression; +import org.exist.xquery.XPathException; +import org.exist.xquery.XQueryContext; +import org.exist.xquery.util.DocUtils; +import org.exist.xquery.value.AnyURIValue; +import org.exist.xquery.value.Sequence; +import org.exist.xquery.value.Type; +import org.w3c.dom.Node; + +import javax.xml.transform.Source; +import javax.xml.transform.TransformerException; +import javax.xml.transform.URIResolver; +import javax.xml.transform.dom.DOMSource; +import java.net.URI; +import java.net.URISyntaxException; + +public class URIResolution { + + /** + * URI resolution, the core should be the same as for fn:resolve-uri + * @param relative URI to resolve + * @param base to resolve against + * @return resolved URI + * @throws URISyntaxException if resolution is not possible + */ + static AnyURIValue resolveURI(final AnyURIValue relative, final AnyURIValue base) throws URISyntaxException, XPathException { + final URI relativeURI = new URI(relative.getStringValue()); + if (relativeURI.isAbsolute()) { + return relative; + } + final URI baseURI = new URI(base.getStringValue() ); + if (!baseURI.isAbsolute()) { + return relative; + } + try { + final XmldbURI xBase = XmldbURI.xmldbUriFor(baseURI); + final URI resolved = xBase.getURI().resolve(relativeURI); + return new AnyURIValue(XmldbURI.XMLDB_URI_PREFIX + resolved); + } catch (URISyntaxException e) { + return new AnyURIValue(baseURI.resolve(relativeURI)); + } + } + + public static class CompileTimeURIResolver implements URIResolver { + + private final XQueryContext xQueryContext; + private final Expression containingExpression; + + public CompileTimeURIResolver(XQueryContext xQueryContext, Expression containingExpression) { + this.xQueryContext = xQueryContext; + this.containingExpression = containingExpression; + } + + @Override + public Source resolve(final String href, final String base) throws TransformerException { + + try { + final AnyURIValue baseURI = new AnyURIValue(base); + final AnyURIValue hrefURI = new AnyURIValue(href); + final AnyURIValue resolved = resolveURI(hrefURI, baseURI); + return resolveDocument(resolved.getStringValue()); + } catch (URISyntaxException e) { + throw new TransformerException( + "Failed to resolve " + href + " against " + base, e); + } catch (XPathException e) { + throw new TransformerException( + "Failed to find document as result of resolving " + href + " against " + base, e); + } + } + + protected Source resolveDocument(final String location) throws XPathException { + return URIResolution.resolveDocument(location, xQueryContext, containingExpression); + } + } + + /** + * Resolve an absolute document location, stylesheet or included source + * + * @param location of the stylesheet + * @return the resolved stylesheet as a source + * @throws XPathException if the item does not exist, or is not a document + */ + static Source resolveDocument(final String location, final XQueryContext xQueryContext, Expression containingExpression) throws XPathException { + + final Sequence document; + try { + document = DocUtils.getDocument(xQueryContext, location); + } catch (final PermissionDeniedException e) { + throw new XPathException(containingExpression, ErrorCodes.FODC0002, + "Can not access '" + location + "'" + e.getMessage()); + } + if (document == null || document.isEmpty()) { + throw new XPathException(containingExpression, ErrorCodes.FODC0002, + "No document found at location '"+ location); + } + if (document.hasOne() && Type.subTypeOf(document.getItemType(), Type.NODE)) { + if (document instanceof NodeProxy) { + final NodeProxy proxy = (NodeProxy) document; + return new DOMSource(proxy.getNode()); + } + else if (document.itemAt(0) instanceof Node) { + final Node node = (Node) document.itemAt(0); + return new DOMSource(node); + } + } + throw new XPathException(containingExpression, ErrorCodes.FODC0002, + "Location '"+ location + "' returns an item which is not a document node"); + } +} \ No newline at end of file diff --git a/exist-core/src/main/java/org/exist/xquery/functions/transform/Transform.java b/exist-core/src/main/java/org/exist/xquery/functions/transform/Transform.java index ccdf90a8cb..178ce328d3 100644 --- a/exist-core/src/main/java/org/exist/xquery/functions/transform/Transform.java +++ b/exist-core/src/main/java/org/exist/xquery/functions/transform/Transform.java @@ -181,7 +181,14 @@ public Sequence eval(Sequence[] args, Sequence contextSequence) throws XPathExce // Parameter 1 & 2 final Sequence inputNode = args[0]; - final Item stylesheetItem = args[1].itemAt(0); + Item stylesheetItem = args[1].itemAt(0); + if (stylesheetItem instanceof StringValue) { + final StringValue sv = (StringValue) stylesheetItem; + if (sv.toString().startsWith("/db/")) { + // adjust /db like URI to xmldb:exist:///db/ like URI + stylesheetItem = new StringValue(XmldbURI.EMBEDDED_SERVER_URI_PREFIX + sv.toString().substring(3)); + } + } // Parse 3rd parameter final Node options = args[2].isEmpty() ? null : ((NodeValue) args[2].itemAt(0)).getNode(); diff --git a/exist-core/src/main/java/org/exist/xquery/functions/validation/Shared.java b/exist-core/src/main/java/org/exist/xquery/functions/validation/Shared.java index 454f9c9833..812f881555 100644 --- a/exist-core/src/main/java/org/exist/xquery/functions/validation/Shared.java +++ b/exist-core/src/main/java/org/exist/xquery/functions/validation/Shared.java @@ -1,4 +1,28 @@ /* + * Elemental + * Copyright (C) 2024, Evolved Binary Ltd + * + * admin@evolvedbinary.com + * https://www.evolvedbinary.com | https://www.elemental.xyz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NOTE: Parts of this file contain code from 'The eXist-db Authors'. + * The original license header is included below. + * + * ===================================================================== + * * eXist-db Open Source Native XML Database * Copyright (C) 2001 The eXist-db Authors * @@ -147,7 +171,7 @@ public static StreamSource getStreamSource(Item item, XQueryContext context) thr if (item instanceof NodeProxy) { final NodeProxy np = (NodeProxy) item; - final String url = "xmldb:exist://" + np.getOwnerDocument().getBaseURI(); + final String url = np.getOwnerDocument().getBaseURI(); LOG.debug("Document detected, adding URL {}", url); streamSource.setSystemId(url); } diff --git a/exist-core/src/test/java/org/exist/xquery/TransformTest.java b/exist-core/src/test/java/org/exist/xquery/TransformTest.java index ce5c3995d9..8cbd50f8a5 100644 --- a/exist-core/src/test/java/org/exist/xquery/TransformTest.java +++ b/exist-core/src/test/java/org/exist/xquery/TransformTest.java @@ -95,6 +95,50 @@ public void transform() throws XMLDBException { "

End Template 1

" + ""); } + + @Test + public void transformWithSameDirectoryImportViaDbLocation() throws XMLDBException { + final String query = + "import module namespace transform='http://exist-db.org/xquery/transform';\n" + + "let $xml := \n" + + "let $xsl := '/db/" + TEST_COLLECTION_NAME + "/same-dir/a.xsl'\n" + + "return transform:transform($xml, $xsl, ())"; + final String result = execQuery(query); + assertEquals("

From A

From B

", result); + } + + @Test + public void transformWithSameDirectoryImportViaXmldbLocation() throws XMLDBException { + final String query = + "import module namespace transform='http://exist-db.org/xquery/transform';\n" + + "let $xml := \n" + + "let $xsl := 'xmldb:exist:///db/" + TEST_COLLECTION_NAME + "/same-dir/a.xsl'\n" + + "return transform:transform($xml, $xsl, ())"; + final String result = execQuery(query); + assertEquals("

From A

From B

", result); + } + + @Test + public void transformWithSameDirectoryImportViaDbNode() throws XMLDBException { + final String query = + "import module namespace transform='http://exist-db.org/xquery/transform';\n" + + "let $xml := \n" + + "let $xsl := doc('/db/" + TEST_COLLECTION_NAME + "/same-dir/a.xsl')\n" + + "return transform:transform($xml, $xsl, ())"; + final String result = execQuery(query); + assertEquals("

From A

From B

", result); + } + + @Test + public void transformWithSameDirectoryImportViaXmldbNode() throws XMLDBException { + final String query = + "import module namespace transform='http://exist-db.org/xquery/transform';\n" + + "let $xml := \n" + + "let $xsl := doc('xmldb:exist:///db/" + TEST_COLLECTION_NAME + "/same-dir/a.xsl')\n" + + "return transform:transform($xml, $xsl, ())"; + final String result = execQuery(query); + assertEquals("

From A

From B

", result); + } private String execQuery(String query) throws XMLDBException { @@ -174,6 +218,29 @@ public void setUp() throws ClassNotFoundException, IllegalAccessException, Insta addXMLDocument(xsl1, doc1, "1.xsl"); addXMLDocument(xsl2, doc2, "2.xsl"); addXMLDocument(xsl3, doc3, "3.xsl"); + + service = (CollectionManagementService) testCollection.getService("CollectionManagementService", "1.0"); + + Collection sameDir = service.createCollection("same-dir"); + assertNotNull(sameDir); + + String docA = "\n" + + "\n"+ + "\n" + + "" + + "

From A

" + + "
" + + "
"; + + String docB = "\n" + + "\n"+ + "" + + "

From B

" + + "
" + + "
"; + + addXMLDocument(sameDir, docA, "a.xsl"); + addXMLDocument(sameDir, docB, "b.xsl"); } @After diff --git a/exist-core/src/test/java/org/exist/xquery/XQueryTest.java b/exist-core/src/test/java/org/exist/xquery/XQueryTest.java index a33248f1d8..6a4a905335 100644 --- a/exist-core/src/test/java/org/exist/xquery/XQueryTest.java +++ b/exist-core/src/test/java/org/exist/xquery/XQueryTest.java @@ -2592,14 +2592,14 @@ public void resolveBaseURI_1841635() throws XMLDBException { ResourceSet result = service.query(query); assertEquals(1, result.getSize()); - assertEquals("/db/test/baseuri.xml", result.getResource(0).getContent().toString()); + assertEquals("xmldb:exist:///db/test/baseuri.xml", result.getResource(0).getContent().toString()); query = "doc('/db/test/baseuri.xml')/Root/Node1/base-uri()"; result = service.query(query); assertEquals(1, result.getSize()); - assertEquals("/db/test/baseuri.xml", result.getResource(0).getContent().toString()); + assertEquals("xmldb:exist:///db/test/baseuri.xml", result.getResource(0).getContent().toString()); query = "doc('/db/test/baseuri.xml')/Root/Node1/Node2/base-uri()"; @@ -2607,14 +2607,14 @@ public void resolveBaseURI_1841635() throws XMLDBException { result = service.query(query); assertEquals(1, result.getSize()); - assertEquals("/db/test/baseuri.xml", result.getResource(0).getContent().toString()); + assertEquals("xmldb:exist:///db/test/baseuri.xml", result.getResource(0).getContent().toString()); query = "doc('/db/test/baseuri.xml')/Root/Node1/Node2/Node3/base-uri()"; result = service.query(query); assertEquals(1, result.getSize()); - assertEquals("/db/test/baseuri.xml", result.getResource(0).getContent().toString()); + assertEquals("xmldb:exist:///db/test/baseuri.xml", result.getResource(0).getContent().toString()); } /** diff --git a/exist-core/src/test/java/org/exist/xquery/functions/fn/transform/FunTransformITTest.java b/exist-core/src/test/java/org/exist/xquery/functions/fn/transform/FunTransformITTest.java index 1ca74a5b9e..aa1a152413 100644 --- a/exist-core/src/test/java/org/exist/xquery/functions/fn/transform/FunTransformITTest.java +++ b/exist-core/src/test/java/org/exist/xquery/functions/fn/transform/FunTransformITTest.java @@ -58,6 +58,47 @@ */ public class FunTransformITTest { + private static final XmldbURI TEST_IMPORT_XSLT_COLLECTION = XmldbURI.create("/db/fn-transform-import-test"); + private static final XmldbURI IMPORT_A_XSLT_NAME = XmldbURI.create("a.xsl"); + private static final XmldbURI IMPORT_B_XSLT_NAME = XmldbURI.create("b.xsl"); + + private static final String IMPORT_A_XSLT = + "\n" + + " \n" + + " \n" + + "

From A

\n" + + "
\n" + + "
"; + + private static final String IMPORT_B_XSLT = + "\n" + + "

From B

\n" + + "
"; + + private static final String SAME_DIR_IMPORT_VIA_DB_LOCATION_QUERY = + "fn:transform(map {\n" + + " \"stylesheet-location\": \"/db/fn-transform-import-test/a.xsl\",\n" + + " \"source-node\": document { }\n" + + "})?output"; + + private static final String SAME_DIR_IMPORT_VIA_XMLDB_LOCATION_QUERY = + "fn:transform(map {\n" + + " \"stylesheet-location\": \"xmldb:exist:///db/fn-transform-import-test/a.xsl\",\n" + + " \"source-node\": document { }\n" + + "})?output"; + + private static final String SAME_DIR_IMPORT_VIA_DB_NODE_QUERY = + "fn:transform(map {\n" + + " \"stylesheet-node\": doc(\"/db/fn-transform-import-test/a.xsl\"),\n" + + " \"source-node\": document { }\n" + + "})?output"; + + private static final String SAME_DIR_IMPORT_VIA_XMLDB_NODE_QUERY = + "fn:transform(map {\n" + + " \"stylesheet-node\": doc(\"xmldb:exist:///db/fn-transform-import-test/a.xsl\"),\n" + + " \"source-node\": document { }\n" + + "})?output"; + private static final XmldbURI TEST_IDENTITY_XSLT_COLLECTION = XmldbURI.create("/db/transform-identity-test"); private static final XmldbURI IDENTITY_XSLT_NAME = XmldbURI.create("xsl-identity.xslt"); @@ -143,6 +184,30 @@ public class FunTransformITTest { @ClassRule public static ExistEmbeddedServer existEmbeddedServer = new ExistEmbeddedServer(true, true); + @Test + public void sameDirectoryImportViaDbLocation() throws XPathException, PermissionDeniedException, EXistException { + final Source expected = Input.fromString("

From A

From B

").build(); + expectQuery(SAME_DIR_IMPORT_VIA_DB_LOCATION_QUERY, expected); + } + + @Test + public void sameDirectoryImportViaXmldbLocation() throws XPathException, PermissionDeniedException, EXistException { + final Source expected = Input.fromString("

From A

From B

").build(); + expectQuery(SAME_DIR_IMPORT_VIA_XMLDB_LOCATION_QUERY, expected); + } + + @Test + public void sameDirectoryImportViaDbNode() throws XPathException, PermissionDeniedException, EXistException { + final Source expected = Input.fromString("

From A

From B

").build(); + expectQuery(SAME_DIR_IMPORT_VIA_DB_NODE_QUERY, expected); + } + + @Test + public void sameDirectoryImportViaXmldbNode() throws XPathException, PermissionDeniedException, EXistException { + final Source expected = Input.fromString("

From A

From B

").build(); + expectQuery(SAME_DIR_IMPORT_VIA_XMLDB_NODE_QUERY, expected); + } + @Test public void identityPersistentDom() throws XPathException, PermissionDeniedException, EXistException { final Source expected = Input.fromString(IDENTITY_XML).build(); @@ -212,6 +277,11 @@ public static void storeResources() throws EXistException, PermissionDeniedExcep Tuple(IDENTITY_XML_NAME, IDENTITY_XML) ); + createCollection(broker, transaction, TEST_IMPORT_XSLT_COLLECTION, + Tuple(IMPORT_A_XSLT_NAME, IMPORT_A_XSLT), + Tuple(IMPORT_B_XSLT_NAME, IMPORT_B_XSLT) + ); + transaction.commit(); } } diff --git a/exist-core/src/test/xquery/base-uri.xql b/exist-core/src/test/xquery/base-uri.xql index 3aff020995..6c36ce40b7 100644 --- a/exist-core/src/test/xquery/base-uri.xql +++ b/exist-core/src/test/xquery/base-uri.xql @@ -118,7 +118,7 @@ function baseuri:cleanup() { declare - %test:assertEquals("-/db/base-uri/test.xml") + %test:assertEquals("-xmldb:exist:///db/base-uri/test.xml") function baseuri:root() { $baseuri:DOCUMENT/base-uri() || "-" || base-uri(doc($baseuri:full_path_document)) }; @@ -131,7 +131,7 @@ function baseuri:sub1() { }; declare - %test:assertEquals("http://example.org/a/","http://example.org/b/","http://example.org/c/","/yy","/db/base-uri/zz") + %test:assertEquals("http://example.org/a/","http://example.org/b/","http://example.org/c/","/yy","xmldb:exist:///db/base-uri/zz") function baseuri:sub2() { for $sub in doc($baseuri:full_path_document)//sub return base-uri($sub) diff --git a/exist-core/src/test/xquery/indexing/indexes-base-uri.xq b/exist-core/src/test/xquery/indexing/indexes-base-uri.xq index 52acaea094..3921c7b2df 100644 --- a/exist-core/src/test/xquery/indexing/indexes-base-uri.xq +++ b/exist-core/src/test/xquery/indexing/indexes-base-uri.xq @@ -1,4 +1,28 @@ (: + : Elemental + : Copyright (C) 2024, Evolved Binary Ltd + : + : admin@evolvedbinary.com + : https://www.evolvedbinary.com | https://www.elemental.xyz + : + : This library is free software; you can redistribute it and/or + : modify it under the terms of the GNU Lesser General Public + : License as published by the Free Software Foundation; version 2.1. + : + : This library is distributed in the hope that it will be useful, + : but WITHOUT ANY WARRANTY; without even the implied warranty of + : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + : Lesser General Public License for more details. + : + : You should have received a copy of the GNU Lesser General Public + : License along with this library; if not, write to the Free Software + : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + : + : NOTE: Parts of this file contain code from 'The eXist-db Authors'. + : The original license header is included below. + : + : ===================================================================== + : : eXist-db Open Source Native XML Database : Copyright (C) 2001 The eXist-db Authors : @@ -50,7 +74,7 @@ function but:tearDown() { declare %test:pending("Each test interferes with each other test, we need to figure out how to have but:tearDown called after every test") - %test:assertEquals("/db/but/a/data/test.xml", "/db/but/a/data/test.xml", "/db/but/b/data/test.xml") + %test:assertEquals("xmldb:exist:///db/but/a/data/test.xml", "xmldb:exist:///db/but/a/data/test.xml", "xmldb:exist:///db/but/b/data/test.xml") function but:base-uri-after-collection-copy() { let $test-col-a-data-uri := xmldb:create-collection($but:test-col-a-uri, "data") let $doc-path := xmldb:store($test-col-a-data-uri, "test.xml", $but:XML) @@ -66,7 +90,7 @@ function but:base-uri-after-collection-copy() { }; declare - %test:assertEquals("/db/but/a/data/test.xml", "/db/but/b/data/test.xml") + %test:assertEquals("xmldb:exist:///db/but/a/data/test.xml", "xmldb:exist:///db/but/b/data/test.xml") function but:base-uri-after-collection-move() { let $test-col-a-data-uri := xmldb:create-collection($but:test-col-a-uri, "data") let $doc-path := xmldb:store($test-col-a-data-uri, "test.xml", $but:XML) @@ -83,7 +107,7 @@ function but:base-uri-after-collection-move() { declare %test:pending("Each test interferes with each other test, we need to figure out how to have but:tearDown called after every test") - %test:assertEquals("/db/but/a/data/test.xml", "/db/but/a/data/test.xml", "/db/but/b/test.xml") + %test:assertEquals("xmldb:exist:///db/but/a/data/test.xml", "xmldb:exist:///db/but/a/data/test.xml", "xmldb:exist:///db/but/b/test.xml") function but:base-uri-after-resource-copy() { let $test-col-a-data-uri := xmldb:create-collection($but:test-col-a-uri, "data") let $doc-path := xmldb:store($test-col-a-data-uri, "test.xml", $but:XML) @@ -100,7 +124,7 @@ function but:base-uri-after-resource-copy() { declare %test:pending("Each test interferes with each other test, we need to figure out how to have but:tearDown called after every test") - %test:assertEquals("/db/but/a/data/test.xml", "/db/but/b/test.xml") + %test:assertEquals("xmldb:exist:///db/but/a/data/test.xml", "xmldb:exist:///db/but/b/test.xml") function but:base-uri-after-resource-move() { let $test-col-a-data-uri := xmldb:create-collection($but:test-col-a-uri, "data") let $doc-path := xmldb:store($test-col-a-data-uri, "test.xml", $but:XML) diff --git a/extensions/indexes/lucene/src/main/java/org/exist/indexing/lucene/AbstractFieldConfig.java b/extensions/indexes/lucene/src/main/java/org/exist/indexing/lucene/AbstractFieldConfig.java index 42c264fdce..76003da71f 100644 --- a/extensions/indexes/lucene/src/main/java/org/exist/indexing/lucene/AbstractFieldConfig.java +++ b/extensions/indexes/lucene/src/main/java/org/exist/indexing/lucene/AbstractFieldConfig.java @@ -172,20 +172,30 @@ protected CompiledXQuery compile(DBBroker broker, String code) { } } - private String resolveURI(String baseURI, String location) { + private String resolveURI(@Nullable final String strBaseUri, final String strLocation) { try { - final URI uri = new URI(location); - if (!uri.isAbsolute() && baseURI != null && baseURI.startsWith(CollectionConfigurationManager.CONFIG_COLLECTION)) { - String base = baseURI.substring(CollectionConfigurationManager.CONFIG_COLLECTION.length()); - final int lastSlash = base.lastIndexOf('/'); - if (lastSlash > -1) { - base = base.substring(0, lastSlash); + final URI uriLocation = new URI(strLocation); + if (!uriLocation.isAbsolute() && strBaseUri != null) { + if (strBaseUri.startsWith(CollectionConfigurationManager.CONFIG_COLLECTION)) { + String base = strBaseUri.substring(CollectionConfigurationManager.CONFIG_COLLECTION.length()); + final int lastSlash = base.lastIndexOf('/'); + if (lastSlash > -1) { + base = base.substring(0, lastSlash); + } + final String resolved = XmldbURI.EMBEDDED_SERVER_URI_PREFIX + base + '/' + strLocation; + return resolved; + } + + if (strBaseUri.startsWith(XmldbURI.EMBEDDED_SERVER_URI_PREFIX + CollectionConfigurationManager.CONFIG_COLLECTION)) { + final String basePath = strBaseUri.substring((XmldbURI.EMBEDDED_SERVER_URI_PREFIX + CollectionConfigurationManager.CONFIG_COLLECTION).length()); + final String locationPath = new URI(basePath).resolve(uriLocation).toString(); + final String resolved = XmldbURI.EMBEDDED_SERVER_URI_PREFIX + locationPath; + return resolved; } - return XmldbURI.EMBEDDED_SERVER_URI_PREFIX + base + '/' + location; } - } catch (URISyntaxException e) { + } catch (final URISyntaxException e) { // ignore and return location } - return location; + return strLocation; } } diff --git a/extensions/indexes/lucene/src/main/java/org/exist/xquery/modules/lucene/Query.java b/extensions/indexes/lucene/src/main/java/org/exist/xquery/modules/lucene/Query.java index d9780e91ec..e2e658f249 100644 --- a/extensions/indexes/lucene/src/main/java/org/exist/xquery/modules/lucene/Query.java +++ b/extensions/indexes/lucene/src/main/java/org/exist/xquery/modules/lucene/Query.java @@ -258,7 +258,7 @@ public NodeSet preSelect(final Sequence contextSequence, final boolean useContex final LuceneIndexWorker index = (LuceneIndexWorker) context.getBroker().getIndexController().getWorkerByIndexId(LuceneIndex.ID); final DocumentSet docs = contextSequence.getDocumentSet(); - final Item key = getKey(contextSequence, null); + @Nullable final Item key = getKey(contextSequence, null); @Nullable final List qnames = contextQNames != null ? Arrays.asList(contextQNames) : null; final QueryOptions options = parseOptions(this, contextSequence, null, 3); try {