No file I/O with file:* functions in Oxygen XQuery transformation scenario - what am I doing wrong?
Added by C. M. Sperberg-McQueen over 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 over 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 over 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 over 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 over 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 over 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.
Please register to reply