Project

Profile

Help

No file I/O with file:* functions in Oxygen XQuery transformation scenario - what am I doing wrong?

Added by C. M. Sperberg-McQueen almost 2 years ago

Consider the following XQuery module:

declare namespace file = "http://expath.org/ns/file";

let $e := <doc>This is a test.</doc>,
    $dir0 := '/home/cmsmcq/2022/github/Aparecium/tests',
    $dir1 := $dir0 || '/saxon-create-dir-test',
    $dummy := file:create-dir($dir1)

return ($e, file:write($e, $dir1 || '/saxon-write-file-test.xml'))

When I open this module in Oxygen and set up an XQuery transformation scenario to evaluate it, it shows me the expected result, which is a document which looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<doc>This is a test.</doc>

But no directory is created at /home/cmsmcq/2022/github/Aparecium/tests/saxon-create-dir-test, and no file named 'saxon-write-file-test.xml' is written. The same is true if the return clause uses $dir0 instead of $dir1.

Have I misunderstood what file:create-dir() and file:write() do, or invoked them in unexpected ways? Is there something I need to do in Oxygen to allow the calls to file:* functions to make changes to the file system?

Thanks for any clarification you can provide.


Replies (6)

Please register to reply

RE: No file I/O with file:* functions in Oxygen XQuery transformation scenario - what am I doing wrong? - Added by Michael Kay almost 2 years ago

In the case of file:create-dir, I think the obvious explanation that the variable $dummy is never evaluated because it is never used. You could get around that, for example, by adding the reference $dummy to the start of your return clause`. The Saxon optimizer does make concessions where it knows that function calls have side-effects, but evaluating an unused variable isn't one of them.

It's less clear to me why file:write does nothing. I shall try a little test.

RE: No file I/O with file:* functions in Oxygen XQuery transformation scenario - what am I doing wrong? - Added by C. M. Sperberg-McQueen almost 2 years ago

My apologies. I should have Read The Fine Manual.

The first thing to do is to get the call correct: file:write() takes the file path first, and the item sequence second, so the call should be

file:write($dir1 || 'test.xml',  $e)

not vice versa.

When I make that correction, the result is a fatal error:

System ID: /home/cmsmcq/2022/github/Aparecium/tests/saxon-trial.xquery

Scenario: Run-the-query

XQuery file: /home/cmsmcq/2022/github/Aparecium/tests/saxon-trial.xquery

Engine name: Saxon-PE XQuery 9.9.1.7

Severity: fatal

Problem ID: file:unknown-encoding

Description: Failed to write to file /home/cmsmcq/2022/github/Aparecium/tests/saxon-create-dir-test/saxon-write-file-test.xml: /home/cmsmcq/2022/github/Aparecium/tests/saxon-create-dir-test/saxon-write-file-test.xml (No such file or directory)

Start location: 10:25

This makes me wonder whether the call to create-dir() is getting optimized out of existence, since the variable $dummy is never again referred to.. And indeed if in the Oxygen preferences menu under "XML / XSLT-XQuery / XQuery / Saxon-HE/PE/EE" I unclick the checkbox labeled Enable optimization ("-opt"), the directory is created and the file is written as normal.

Other things being equal, in my real usage scenario (as opposed to this test) I would like optimization turned on since the queries are sometimes slow.

So now I think my question is: is there a way to prevent the call to create-dir() from being optimized out of existence?

RE: No file I/O with file:* functions in Oxygen XQuery transformation scenario - what am I doing wrong? - Added by Michael Kay almost 2 years ago

I think you've simply got the parameters of file:write in the wrong order.

This query works for me:

declare namespace file = 'http://expath.org/ns/file'; 
let $e := <doc>This is a test.</doc>, 
     $dir0 := '/Users/mike/Desktop', 
     $dir1 := $dir0 || '/saxon-create-dir-test', 
     $dummy := file:create-dir($dir1) 
     return ($dummy, $e, file:write($dir1 || '/saxon-write-file-test.xml', $e))

I said that the Saxon optimizer "makes concessions". The main concession it makes is that internally, it declares file:write() to have a return type of item()*, rather than empty-sequence(), which means that the optimizer cannot take advantage of knowing in advance that the result will be an empty sequence; therefore, if the function call appears in a sequence-expression (using the comma operator), it gets evaluated.

RE: No file I/O with file:* functions in Oxygen XQuery transformation scenario - what am I doing wrong? - Added by C. M. Sperberg-McQueen almost 2 years ago

For the record, the call to create-dir() behaves as expected in the following modified test, even with optimization turned on.

declare namespace file = "http://expath.org/ns/file";

let $e := <doc>This is a new test.</doc>,
    $dir0 := '/home/cmsmcq/2022/github/Aparecium/tests',
    $dir1 := concat($dir0, '/saxon-create-dir-test-2'),
    $path := concat($dir1, file:create-dir($dir1), '/saxon-write-file-test-2', '.xml')
    (: $dummy := file:create-dir($dir1) :)

return ($e, file:write($path, $e))

If anyone reading this forum knows a simpler way to ensure the evaluation of the create-dir() call, I would be glad to learn.

RE: No file I/O with file:* functions in Oxygen XQuery transformation scenario - what am I doing wrong? - Added by Michael Kay almost 2 years ago

If anyone reading this forum knows a simpler way to ensure the evaluation of the create-dir() call, I would be glad to learn.

The golden rule is: put the function call in a context where, if it were to return something other than an empty sequence, the final result of the query would be different.

    (1-6/6)

    Please register to reply