Hi Christian, Here you are (I hope this is sufficient, actual file content can be found further down below):
· Test.java – A simple QueryModule
· Test.xq – The query I execute from within a UnitTest
· Test.xml – The XML that is queried (in my test, it was either located in C:/BaseXTest or directly accessible in Test.xq – see Test.xq for further details)
· UnitTest – code I used to run the whole test (tested with BaseX Versions 8.5.3 and 8.6) What I noticed: If I do NOT load the XML document from an external file, everything works as expected. Then I get this result:
indirectly: "4979" on element: "4979" on element: "4979" on element: "4979" <test> <result id="Element_1" attributeX="4979"/> <result id="Element_2" attributeX="4979"/> <result id="Element_3" attributeX="4979"/> <result id="SubElement_1" attributeX="4979"/> </test>
If the document IS loaded from an external file (which is what I tried first), I get the following – incorrect - result:
empty: empty-sequence() on element: "4979" on element: "4979" empty: empty-sequence() <test> <result id="Element_1" attributeX=""/> <result id="Element_2" attributeX="4979"/> <result id="Element_3" attributeX="4979"/> <result id="SubElement_1" attributeX=""/> </test>
Here, something appears to be wrong when evaluating parent elements.
Best regards, Johannes
---------- Test.java
import org.basex.api.dom.BXElem; import org.basex.core.Context; import org.basex.query.QueryException; import org.basex.query.QueryModule; import org.basex.query.QueryProcessor; import org.basex.query.value.Value; import org.basex.query.value.node.ANode; import org.basex.query.value.seq.Empty;
public class Test extends QueryModule {
public Value determineAttributeX(Value element) throws QueryException {
String query = "declare namespace nsx = 'http://www.example.org/X%27;declare variable $elmt external; " + "let $elementWithAttributeX := $elmt/ancestor-or-self::*[@attributeX or nsx:boundedBy/*/@attributeX][1] " + "return if (empty($elementWithAttributeX)) then trace((),'empty: ') " + "else if($elementWithAttributeX/@attributeX) then trace($elementWithAttributeX/data(@attributeX),'on element: ') else " + "trace($elementWithAttributeX/nsx:boundedBy/*/data(@attributeX),'indirectly: ')";
Context ctx = queryContext.context;
try (QueryProcessor qp = new QueryProcessor(query, ctx)) {
// Bind to context: qp.bind("elmt", element); qp.context(element);
Value value = qp.value();
return value; } }
public Value parse(Object arg) throws QueryException {
if (arg instanceof ANode) {
ANode node = (ANode) arg;
Value attributeX = determineAttributeX(node); return attributeX;
} else if (arg instanceof BXElem) {
BXElem tmp = (BXElem) arg; ANode node = tmp.getNode();
Value attributeX = determineAttributeX(node); return attributeX;
} else {
return Empty.SEQ; } } }
----------- Test.xq:
import module namespace mod = 'Test';
declare namespace nsx = 'http://www.example.org/X'; declare namespace nsy = 'http://www.example.org/Y';
let $doc := doc('C:/BaseXTest/Test.xml') (:let $doc := <nsy:Collection xmlns:nsx='http://www.example.org/X' xmlns:nsy='http://www.example.org/Y' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance%27%3E nsx:boundedBy <nsx:OtherElement attributeX='4979'/> </nsx:boundedBy> nsy:member <nsx:Element id='Element_1'> nsx:othera b c</nsx:other> </nsx:Element> </nsy:member> nsy:member <nsx:Element id='Element_2' attributeX='4979'> nsx:othera b c</nsx:other> </nsx:Element> </nsy:member> nsy:member <nsx:Element id='Element_3' attributeX='4979'> <nsx:SubElement id='SubElement_1'/> </nsx:Element> </nsy:member> </nsy:Collection>:)
let $elements := $doc//*[@id] return <test> { for $elmt in $elements let $r := mod:parse($elmt) return <result id='{$elmt/@id}' attributeX='{$r}'/> } </test>
---------- Test.xml:
<?xml version="1.0" encoding="UTF-8"?> <nsy:Collection xmlns:nsx="http://www.example.org/X" xmlns:nsy="http://www.example.org/Y" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance%22%3E nsx:boundedBy <nsx:OtherElement attributeX="4979"/> </nsx:boundedBy> nsy:member <nsx:Element id="Element_1"> nsx:othera b c</nsx:other> </nsx:Element> </nsy:member> nsy:member <nsx:Element id="Element_2" attributeX="4979"> nsx:othera b c</nsx:other> </nsx:Element> </nsy:member> nsy:member <nsx:Element id="Element_3" attributeX="4979"> <nsx:SubElement id="SubElement_1"/> </nsx:Element> </nsy:member> </nsy:Collection>
---------- UnitTest:
import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths;
import org.basex.core.BaseXException; import org.basex.core.Context; import org.basex.core.cmd.XQuery; import org.basex.query.QueryException;
public final class ExecuteTestQuery {
/** Database context. */ private static Context context = new Context();
/** * Runs the example code. * @param args (ignored) command-line arguments * @throws IOException if an error occurs while serializing the results * @throws QueryException if an error occurs while evaluating the query * @throws BaseXException if a database command fails */ public static void main(final String[] args) throws IOException, QueryException {
String xq = "src/test/resources/test.xq";
// Evaluate the specified XQuery String query = new String(Files.readAllBytes(Paths.get(xq)));
XQuery xquery = new XQuery(query);
String result = xquery.execute(context);
System.out.println(result); } }
Von: Christian Grün [mailto:christian.gruen@gmail.com] Gesendet: Dienstag, 23. Mai 2017 14:25 An: Johannes Echterhoff echterhoff@interactive-instruments.de Cc: BaseX basex-talk@mailman.uni-konstanz.de Betreff: Re: AW: [basex-talk] Evaluating XPath within custom QueryModule
Could you please provide me with a little, seld-contained example?
Thanks in advance, Christian
Am 23.05.2017 14:14 schrieb "Johannes Echterhoff" <echterhoff@interactive-instruments.demailto:echterhoff@interactive-instruments.de>: Hi Christian, Thank you. This is very useful. One issue, though: in my test, it looks like the ancestors of the element that is processed by the query are not available/accessible. What am I missing? Best regards, Johannes
-----Ursprüngliche Nachricht----- Von: Christian Grün [mailto:christian.gruen@gmail.commailto:christian.gruen@gmail.com] Gesendet: Dienstag, 23. Mai 2017 12:43 An: Johannes Echterhoff <echterhoff@interactive-instruments.demailto:echterhoff@interactive-instruments.de> Cc: basex-talk@mailman.uni-konstanz.demailto:basex-talk@mailman.uni-konstanz.de Betreff: Re: [basex-talk] Evaluating XPath within custom QueryModule
Hi Johannes,
Welcome to the list.
However, I wonder if it is possible to evaluate the expression also within the query module itself, i.e. when method “parse” is called. Is there a way to do so?
Absolutely. You find some examples in [1].
If you your class extends the QueryModule class – which is always recommendable – a function could look as follows:
import org.basex.core.Context; import org.basex.query.QueryModule; import org.basex.query.QueryProcessor; import org.basex.query.value.Value;
public class Module extends QueryModule { public Value elementName(Value elem) throws Exception { // Your query String query = "declare variable $elem external;" + "name($elem), (: element bound to variable :)" + "name(.) (: element bound to context :)";
Context ctx = queryContext.context; QueryProcessor qp = new QueryProcessor(query, ctx); // Bind to context: qp.bind("elem", elem); qp.context(elem); Value value = qp.value();
return value; } }
Hope this helps, Christian
[1] https://github.com/BaseXdb/basex/blob/master/basex-examples/src/main/java/or...