Hello, I'm finding no easy way to extract the contents of a collection to a filesystem directory. For example, In database "myDB", I have a number of XML files inside a collection named "myCollection" (a subfolder of "myDB"). I'm looking for a command or function to extract those files to "myHardDriveDirectory" in my filesystem. I tried file:write(), but it works only with a single file. I also tried db:export(), but it outputs the entire database, which is overkill. So, I ended up doing this:
for $doc in collection('myDB/myCollection')return file:write('D:\myHardDriveDirectory'||$doc/pathToADateAttribute||' Report.xml', $doc) It works (I get a bunch of "2015-01-20 Report.xml" files), but I had to use a FLWOR and dynamically construct each of the names of the files to be written to disk. This could be made much simpler with something like: db:export('myDB/myCollection', 'D:\myHardDriveDirectory') I may be missing some other way to do this. But, in case there is no alternative, would you please consider enhancing db:export() to support outputting collections (or any equivalent solution you may deem better)? It would be great to have that shipped in BaseX 8.
I had also set up Webdav to try the quick drag-and-drop way, but unfortunately it has several bugs and had to stop using it.
Bonus question: Is there a way to do the reverse operation with some function/command? That is, get the XML files in a filesystem directory to replace any namesake XML files in a specific collection? db:replace() works with a single file only, according to the documentation. db:add() works with filesystem directories, but would create duplicate resources in the database, instead of replacing the existing ones.
The only ways I've found so far are: First by using the GUI; I have to delete the entire collection and rebuild it with the "Add resources" dialog box. The second way is to use db:delete() on the collection and then db:add(). But both are lengthy/verbose ways of doing this. Is there already a better way? If not, do you think it may be possible to also enhance db:replace() for it to work with filesystem directories and database collections?
Thank you very much for any help. Alex
Hi Alex,
So, I ended up doing this:
I would have done it similar:
let $target := 'D:\myHardDriveDirectory' for $doc in db:open('myDB', 'myCollection') let $path := $target || db:path($doc) return ( file:create-dir(file:parent($path)), file:write($path, $doc) )
db:export('myDB/myCollection', 'D:\myHardDriveDirectory')
I'll think about your suggestion. As the database argument of all other db functions only contains the name of database, I am a bit hesitant to change this. For now, I have added the above XQuery snippet to the documentation [1]
I had also set up Webdav to try the quick drag-and-drop way, but unfortunately it has several bugs and had to stop using it.
WebDAV should be slower as other operations, because each file is requested one by one, but it should work as well. Unfortunately, however, many of the WebDAV clients use different ways to address WebDAV server. Which one did you use?
Bonus question: Is there a way to do the reverse operation with some function/command?
Once again, for now, I recommend you to use XQuery for that [2]:
let $source := '/home/john/xml/source' for $file in file:list($source, true()) let $path := $source || $file where not(file:is-dir($path)) return db:replace('db', $file, doc($path))
Hope this helps, Christian
[1] http://docs.basex.org/wiki/Database_Module#db:export [2] http://docs.basex.org/wiki/Database_Module#db:replace
basex-talk@mailman.uni-konstanz.de