Hi Johannes,
To find the weak spot, I decided to further simplify your example (I have attached the result).
It’s good to use the internal BaseX value types as Java function argument, such as Value or ANode. If you use Object, the function input will be copied and converted to a standard Java type, which is a DOM element in this case (represented by BXElem). This node will be a full copy of the original node, without its ancestors (otherwise, it would get huge if you work with large databases).
Hope this helps, Christian
On Tue, May 23, 2017 at 4:03 PM, Johannes Echterhoff echterhoff@interactive-instruments.de wrote:
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:OtherElement
attributeX='4979'/>
</nsx:boundedBy>
<nsx:Element
id='Element_1'>
nsx:othera b c</nsx:other>
</nsx:Element>
</nsy:member>
<nsx:Element
id='Element_2'
attributeX='4979'>
nsx:othera b c</nsx:other>
</nsx:Element>
</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:OtherElement attributeX="4979"/>
</nsx:boundedBy>
<nsx:Element id="Element_1">
nsx:othera b c</nsx:other>
</nsx:Element>
</nsy:member>
<nsx:Element id="Element_2" attributeX="4979">
nsx:othera b c</nsx:other>
</nsx:Element>
</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/or...