diff --git a/extensions/indexes/range/pom.xml b/extensions/indexes/range/pom.xml
index 4f55d02e27..1cb3ccc2ba 100644
--- a/extensions/indexes/range/pom.xml
+++ b/extensions/indexes/range/pom.xml
@@ -193,6 +193,7 @@
pom.xml
src/test/resources-filtered/conf.xml
src/test/resources/log4j2.xml
+ src/test/xquery/range/conditions.xql
src/main/java/org/exist/indexing/range/RangeIndexAnalyzer.java
src/main/java/org/exist/indexing/range/RangeIndexConfigAttributeCondition.java
src/main/java/org/exist/indexing/range/RangeIndexConfigElement.java
@@ -210,6 +211,7 @@
pom.xml
src/test/resources-filtered/conf.xml
src/test/resources/log4j2.xml
+ src/test/xquery/range/conditions.xql
src/main/java/org/exist/indexing/range/RangeIndexAnalyzer.java
src/main/java/org/exist/indexing/range/RangeIndexConfigAttributeCondition.java
src/main/java/org/exist/indexing/range/RangeIndexConfigElement.java
diff --git a/extensions/indexes/range/src/main/java/org/exist/indexing/range/RangeIndexConfigAttributeCondition.java b/extensions/indexes/range/src/main/java/org/exist/indexing/range/RangeIndexConfigAttributeCondition.java
index 3f2d6c26ea..3953608811 100644
--- a/extensions/indexes/range/src/main/java/org/exist/indexing/range/RangeIndexConfigAttributeCondition.java
+++ b/extensions/indexes/range/src/main/java/org/exist/indexing/range/RangeIndexConfigAttributeCondition.java
@@ -46,6 +46,8 @@
package org.exist.indexing.range;
import org.exist.dom.QName;
+import org.exist.dom.persistent.ElementImpl;
+import org.exist.dom.persistent.NodeImpl;
import org.exist.storage.ElementValue;
import org.exist.storage.NodePath;
import org.exist.util.DatabaseConfigurationException;
@@ -78,8 +80,7 @@
*/
public class RangeIndexConfigAttributeCondition extends RangeIndexConfigCondition{
- private final String attributeName;
- private final QName attribute;
+ private final QName attributeName;
private @Nullable final String value;
private final Operator operator;
private final boolean caseSensitive;
@@ -96,13 +97,23 @@ public RangeIndexConfigAttributeCondition(final Element elem, final NodePath par
"Range index module: Attribute condition cannot be defined for an attribute:" + parentPath);
}
- this.attributeName = elem.getAttribute("attribute");
- if (this.attributeName.isEmpty()) {
+ final String attributeValue = elem.getAttribute("attribute");
+ if (attributeValue.isEmpty()) {
throw new DatabaseConfigurationException("Range index module: Empty or no attribute qname in condition");
}
try {
- this.attribute = new QName(QName.extractLocalName(this.attributeName), XMLConstants.NULL_NS_URI, QName.extractPrefix(this.attributeName), ElementValue.ATTRIBUTE);
+ final String attrLocalName = QName.extractLocalName(attributeValue);
+ @Nullable final String attrPrefix = QName.extractPrefix(attributeValue);
+ if (attrPrefix != null) {
+ @Nullable final String attrNamespace = findNamespaceForPrefix(attrPrefix, (ElementImpl) elem);
+ if (attrNamespace == null) {
+ throw new DatabaseConfigurationException("Range index module: Missing namespace declaration for attribute qname in condition");
+ }
+ this.attributeName = new QName(attrLocalName, attrNamespace, attrPrefix, ElementValue.ATTRIBUTE);
+ } else {
+ this.attributeName = new QName(attrLocalName, XMLConstants.NULL_NS_URI, null, ElementValue.ATTRIBUTE);
+ }
} catch (final QName.IllegalQNameException e) {
throw new DatabaseConfigurationException("Rand index module error: " + e.getMessage(), e);
}
@@ -171,6 +182,24 @@ public RangeIndexConfigAttributeCondition(final Element elem, final NodePath par
}
+ private static @Nullable String findNamespaceForPrefix(final String prefix, ElementImpl contextElem) {
+ while (contextElem != null) {
+ final String namespace = contextElem.getNamespaceForPrefix(prefix);
+ if (namespace != null) {
+ return namespace;
+ }
+
+ @Nullable final Node parentNode = contextElem.getParentNode();
+ if (parentNode != null && parentNode instanceof ElementImpl) {
+ contextElem = (ElementImpl) parentNode;
+ } else {
+ contextElem = null;
+ }
+ }
+
+ return null;
+ }
+
// lazily evaluate lowercase value to convert once when needed
private String getLowercaseValue() {
if (this.lowercaseValue == null) {
@@ -184,8 +213,16 @@ private String getLowercaseValue() {
@Override
public boolean matches(final Node node) {
+ final String attrValue;
+ if (attributeName.hasNamespace()) {
+ attrValue = ((Element) node).getAttributeNS(attributeName.getNamespaceURI(), attributeName.getLocalPart());
+ } else {
+ attrValue = ((Element) node).getAttribute(attributeName.getLocalPart());
+ }
+
return node.getNodeType() == Node.ELEMENT_NODE
- && matchValue(((Element) node).getAttribute(attributeName));
+ && matchValue(attrValue);
+
}
private boolean matchValue(final String testValue) {
@@ -312,7 +349,7 @@ public boolean find(final Predicate predicate) {
}
final QName qname = testStep.getTest().getName();
- if (qname.getNameType() != ElementValue.ATTRIBUTE || !qname.equals(attribute)) {
+ if (qname.getNameType() != ElementValue.ATTRIBUTE || !qname.equals(attributeName)) {
return false;
}
diff --git a/extensions/indexes/range/src/test/xquery/range/conditions.xql b/extensions/indexes/range/src/test/xquery/range/conditions.xql
index a3951eac99..a78572cbd4 100644
--- a/extensions/indexes/range/src/test/xquery/range/conditions.xql
+++ b/extensions/indexes/range/src/test/xquery/range/conditions.xql
@@ -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
:
@@ -36,7 +60,9 @@ declare namespace stats="http://exist-db.org/xquery/profiling";
declare variable $ct:COLLECTION_CONFIG :=
+ xmlns:tei="http://www.tei-c.org/ns/1.0"
+ xmlns:other1="http://other1"
+ xmlns:other2="http://other2">
@@ -59,6 +85,14 @@ declare variable $ct:COLLECTION_CONFIG :=
+
+
+
+
+
+
+
+
@@ -134,7 +168,7 @@ declare variable $ct:COLLECTION_CONFIG :=
declare variable $ct:DATA :=
-
+
conditional fields!
@@ -143,7 +177,7 @@ declare variable $ct:DATA :=
- publiziert
+ publiziert
literarisch
@@ -161,10 +195,11 @@ declare variable $ct:DATA :=
Alexandria
- startswithendswith
- foo
- foo
- literarisch
+ startswithendswith
+ foo
+ foo
+ literarisch
+ other1-not-same-namespace
@@ -533,3 +568,20 @@ function ct:optimize-matches-no-case() {
collection($ct:COLLECTION)//tei:p[matches(@type, "bb")][. = "something"]
};
+(:~
+ : See: https://github.com/eXist-db/exist/issues/5189
+ :)
+declare
+ %test:assertEquals("publiziert", "startswithendswith")
+function ct:other1-index-keys() {
+ range:index-keys-for-field("other1", function($k, $n) { $k }, 10)
+};
+
+(:~
+ : See: https://github.com/eXist-db/exist/issues/5189
+ :)
+declare
+ %test:assertEquals("foo", "literarisch", "startswithendswith")
+function ct:other2-index-keys() {
+ range:index-keys-for-field("other2", function($k, $n) { $k }, 10)
+};
diff --git a/schema/collection.xconf.xsd b/schema/collection.xconf.xsd
index 43574fe1ea..7a40be0898 100644
--- a/schema/collection.xconf.xsd
+++ b/schema/collection.xconf.xsd
@@ -333,7 +333,7 @@
-
+