xquerybasexxquery-3.1

If-statement: Incomplete FLWOR expression


I have the following XQuery code in the BaseX editor, but it errors on the if-clause, stating

Incomplete FLWOR expression: expecting 'return'

The code that I am trying to use:

import module namespace functx = 'http://www.functx.com';
declare namespace file = "http://expath.org/ns/file";

let $root := 'E:\basex-index-testing\sonar-small\index'
let $ds := file:dir-separator()

(: get files in sonar-small database :)
for $f in db:list('sonar-small')
  (: remove *.xml from doc name :)
  let $corpus := substring($f, 1, string-length($f) - 4)
  for $alpino in db:open('sonar-small', $f)/treebank/alpino_ds
  (: make sure tree has sentence element :)
  where count($alpino/sentence) > 0
      let $sentenceId := data($alpino/@id)

      for $node in $alpino//node
      (: make sure there are less than 500 descendants, 
      less than 100 and more than 0 children :)
      where count($node//node) < 500 and count($node/node) > 0 
            and count($node/node) < 100
        let $catTop := data($node/@cat)

        (: create indexing pattern based on node's direct children :)
        let $childrenRelCat := ()
        for $child in $node/node
          let $childRel := data($child/@rel)
          (: use children's cat or pt attribute, default to '' :)
          let $childCat := data($child/(@cat, @pt, '')[1])
          (: concatenate childrenRelCat sequence (append to list) :)
          let $childrenRelCat := ($childrenRelCat, 
                                  string-join(($childRel, $childCat), '%'))

        let $bf := string-join(functx:sort($childrenRelCat), '_')
        let $sent := <tree id="{$sentenceId}">{$node}</tree>

        let $dir := concat($root, $ds, $catTop)
        (: this if-clause throws an error: missing return statement, 
        incomplete FWLOR:)
        if (file:exists($dir) and file:is-dir($dir))
          then ()
        else file:create-dir($dir)        

        (: append subtree to pattern-file :)
        file:append($dir || $bf || '-index.xml', $sent)
        (: doesn't have to return anything, but FWLOR demands it... :)
        return $f

It seems that I am missing something crucial in the way how XQuery evaluates expressions or expects them to be ordered. What is wrong in the code above?

(This question is titled almost identically, but the answer provided there does not help as there was another error in the code of that OP.)


Solution

  • I think the real problem here is that you are using the if-expression

    if (file:exists($dir) and file:is-dir($dir))
              then () else file:create-dir($dir) 
    

    in order to achieve side-effects, rather than in order to return a result. Although it's possible for external functions like file:create-dir() to have side effects, it's not really the way XQuery is designed to work, and you therefore need to be very careful about how you use such external functions. Not only that, the detailed rules about what works and what doesn't might vary from one XQuery processor to another.

    In addition, of course, your query has to satisfy the grammar, and the grammar for a FLWOR expression says that it consists of a sequence of clauses each of which is a for, let, where, order-by, .... or return clause. So your "if" expression is misplaced.

    I don't know BaseX, but I think it's likely that the following will work:

    let $dir := concat($root, $ds, $catTop)
    return (
            if (file:exists($dir) and file:is-dir($dir))
              then ()
              else file:create-dir($dir),        
            file:append($dir || $bf || '-index.xml', $sent),
            $f
    )