Hello, I am writing a custom QueryModule that can be used to parse information from a given XML element. The module has a function like the following:
public ParsedType parse (Object arg) throws QueryException { if (arg instanceof ANode) { return utils.parse((ANode) arg); } else if (arg instanceof BXElem) { return utils.parse((Element) arg); } else { ... } }
It turned out that parsing requires additional information that can be found either on the XML element itself or - more importantly for my question - in one of its ancestors. The XPath expression to determine the information looks like this: <context XML element>/ancestor-or-self::*[@attributeX or nsX:SomeElement/*/@attributeX][1]. I can evaluate this expression in the XQuery before calling method "parse" from my custom query module, and add the value of attributeX as an argument. To do so, I actually have a function to determine the value of attributeX:
declare function local:determineAttributeX($elmt as element()) { let $elementWithAttributeX := $elmt/ancestor-or-self::*[@attributeX or nsX:SomeElement/*/@attributeX][1] return if (empty($elementWithAttributeX)) then () else if($elementWithAttributeX/@attributeX) then $ elementWithAttributeX/data(@attributeX) else $ elementWithAttributeX/nsX:SomeElement/*/data(@attributeX) };
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? That would reduce the complexity of the XQuery that calls "parse" (and the value of "attributeX" is always of interest when "parse" is called, so ideally "parse" can determine the value itself). I searched the internet (the archive of this mailing list as well as stackoverflow) for quite some time but could not find an answer to this question. Any help would therefore be greatly appreciated. Best regards, Johannes Echterhoff
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...
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...
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
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...
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...
Hi Christian, Thank you for investigating. I'll update the methods in my query module as you suggested. Best regards, Johannes
-----Ursprüngliche Nachricht----- Von: Christian Grün [mailto:christian.gruen@gmail.com] Gesendet: Donnerstag, 25. Mai 2017 16:43 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
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/j ava/org/basex/examples/local/RunQueries.java
basex-talk@mailman.uni-konstanz.de