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';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'>
<nsx:boundedBy>
<nsx:OtherElement
attributeX='4979'/>
</nsx:boundedBy>
<nsy:member>
<nsx:Element
id='Element_1'>
<nsx:other>a b c</nsx:other>
</nsx:Element>
</nsy:member>
<nsy:member>
<nsx:Element
id='Element_2'
attributeX='4979'>
<nsx:other>a 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">
<nsx:boundedBy>
<nsx:OtherElement attributeX="4979"/>
</nsx:boundedBy>
<nsy:member>
<nsx:Element id="Element_1">
<nsx:other>a b c</nsx:other>
</nsx:Element>
</nsy:member>
<nsy:member>
<nsx:Element id="Element_2" attributeX="4979">
<nsx:other>a 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.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.com]
Gesendet: Dienstag, 23. Mai 2017 12:43
An: Johannes Echterhoff <echterhoff@interactive-instruments.de>
Cc: 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/org/basex/examples/local/RunQueries.java