2

I'm using BaseX XQJ API to execute xquery queries on XML files within my java application. The following xquery that I constructed nicely generates the output that I want:

let $doc := doc("eprints")
for $i in distinct-values($doc//issn)
let $jn := $doc//paper[issn = $i]/publication
where (count(distinct-values($jn)) > 1)
return <issn num="{$i}">"{$jn}"</issn>

After convincing myself that this query works by testing it in the BaseX application, I implemented this query in java code.

public static void main(String[] args) throws XQException{
    XQDataSource ds = new BaseXXQDataSource();
    ds.setProperty("serverName", "localhost");
    ds.setProperty("port", "1984");
    ds.setProperty("user", "xxxx");
    ds.setProperty("password", "xxxxx");
    ds.setProperty("databaseName", "eprints");

    XQConnection conn = ds.getConnection("admin", "admin");

    XQExpression xqe = conn.createExpression();
    XQResultSequence result = xqe.executeQuery("let $doc := doc(\"eprints\")"+
                                            "for $i in distinct-values($doc//issn)"+
                                            "let $jn := $doc//paper[issn = $i]/publication"+
                                            "where (count(distinct-values($jn)) > 1)"+
                                            "return <issn num='{$i}'>'{jn}'</issn>"

                                            ); 
}

This code however resulted in a error stating that the $jn variable could not be found: Exception in thread "main" javax.xml.xquery.XQQueryException: [XPST0008]: Undefined variable $jn. When looking at the query one can see that $jn actually is defined in the let-statement within the for-statement.

However, when I directly insert the expression assigned to $jn where $jn was used, the code does work correctly:

public static void main(String[] args) throws XQException{
    XQDataSource ds = new BaseXXQDataSource();
    ds.setProperty("serverName", "localhost");
    ds.setProperty("port", "1984");
    ds.setProperty("user", "admin");
    ds.setProperty("password", "admin");
    ds.setProperty("databaseName", "eprints");

    XQConnection conn = ds.getConnection("admin", "admin");

    XQExpression xqe = conn.createExpression();
    XQResultSequence result = xqe.executeQuery("let $doc := doc(\"eprints\")"+
                                            "for $i in distinct-values($doc//issn)"+
                                            "where (count(distinct-values($doc//paper[issn = $i]/publication)) > 1)"+
                                            "return <issn num='{$i}'>'{$doc//paper[issn = $i]/publication}'</issn>"
                                            );    
}

It seems like the BaseX XQJ API is unable to handle queries which have a let-statement within a for-statement. Does anyone know what the cause of the error is?

Thufir
  • 8,216
  • 28
  • 125
  • 273
Niek Tax
  • 841
  • 1
  • 11
  • 30

1 Answers1

3

There's no space between publication and where in your original query (disguised by the string concatenation), so both rows are interpreted as an axis path and a dynamic function application:

let $jn := $doc//paper[issn = $i]/publicationwhere (count(distinct-values($jn)) > 1)

This yields an error because recursive variable definitions aren't allowed. Just insert a space after publication, then it should run fine.

Leo Wörteler
  • 4,191
  • 13
  • 10
  • 1
    Better add a space after/before each line to avoid these problem in general or using some concatenate function which adds them for you. – Jens Erat May 10 '12 at 11:25