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