Getting filename of an XML file with XQuery
Asked Answered
S

3

9

I store my entities in the eXist XML database and I use a file name (resource id) as an ID of an entity.

Example:

String xquery = "for $movie in collection('/db/movie')//movie "
    + "return $movie";

After executing this query I retrieve org.xmldb.api.base.Resource instance whose content I use to create an entity. When I want to set an id of this entity, I do it like this:

dvd.setId(rs.getId());

The problem is that if I execute query like this:

String xquery = "for $dvd in collection('/db/dvd')//dvd "
        + "return <dvd>"
        + "{$dvd/title}"
        + "{$dvd/type}"
        + "{"
        + "<content>"
        + " {"
        + " for $movie in $dvd/content//movie"
            + "     let $movieIn := doc(concat(\"/db/movie/\", $movie/@id))/movie"
        + "     return "
            + "                    <movie id=\"{$movie/@id}\">"
            + "                          {$movieIn/name}"
            + "                          {$movieIn/director}"
            + "                          {$movieIn/year}"
            + "                          {$movieIn/country}"
            + "                          {$movieIn/actors}"
            + "                          {$movieIn/genres}"
            + "                    </movie>"
        + " }"
        + "</content>"
        + "}"
        + "</dvd>";

rs.getId() returns null. I also tried method getDocumentId() from this class, but it returns null as well. Is there a way of making it return the id of the resource (which is the name of the file which the entity is stored in) ?

If it's not possible, is there a way (function or something) of getting the file name of the file which I'm working with (I mean, the database retrieves data from) with an XQuery query ?

I tried replacing this line:

+ "return <dvd>"

with this:

+ "return <dvd id=\"{$dvd}\">"

(so that I could get the name of the file from the attribute) but it doesn't return the file name.

Schoolboy answered 17/6, 2011 at 13:13 Comment(0)
N
11

You might be looking for fn:base-uri(). See here.

Nilotic answered 17/6, 2011 at 13:25 Comment(4)
Thanks ! Great. But if there is something that returns only the name of the file (not whole uri), let me know please.Schoolboy
You could probably do something like fn:substring-after(fn:base-uri($dvd),fn:static-base-uri()). Or another replace with fn:replace(). I dont know of a function that does it directly.Nilotic
I use fn:substring(fn:base-uri($dvd), 9) (because I know that the uri has always the same length) but thanks for the idea!Schoolboy
I'd suggest to use document-uri( root( $dvd ) ) instead, it returns (as documented on that page) the same, but it prevents potentially issues with base attributes when present...Baca
C
13

Since you're using eXist-db, you can use the util:document-name() function:

util:document-name($dvd)
Clientage answered 11/3, 2013 at 17:22 Comment(0)
N
11

You might be looking for fn:base-uri(). See here.

Nilotic answered 17/6, 2011 at 13:25 Comment(4)
Thanks ! Great. But if there is something that returns only the name of the file (not whole uri), let me know please.Schoolboy
You could probably do something like fn:substring-after(fn:base-uri($dvd),fn:static-base-uri()). Or another replace with fn:replace(). I dont know of a function that does it directly.Nilotic
I use fn:substring(fn:base-uri($dvd), 9) (because I know that the uri has always the same length) but thanks for the idea!Schoolboy
I'd suggest to use document-uri( root( $dvd ) ) instead, it returns (as documented on that page) the same, but it prevents potentially issues with base attributes when present...Baca
T
0

fn:base-uri will return the whole URI rather than the last part of the URI, but you can use a regex solution combined with the fn:base-uri function for a solution that is not dependent on eXist-specific functions.

This particular regex trims the extension with \.\w+$ and captures the filename without extension in capture group 2

declare namespace db="http://basex.org/modules/db";
declare namespace file="http://expath.org/ns/file";
declare variable $path as xs:string external;

let $docs := collection($path)
for $doc in $docs
return
let $file := replace(fn:base-uri($doc),'^(.*/)(.*?)\.\w+$','$2')
return db:replace('13F', $file, $doc)

Alternatively for the whole filename with extension

  let $file := replace(fn:base-uri($doc),'^(.*/)(.*?\.\w+$)','$2')
Tyrolienne answered 30/6, 2016 at 21:3 Comment(4)
Yeah the first answer doesn't actually give a method to get only the file name, rather the whole file path or uri. It's really not answering the question. [xqueryfunctions.com/xq/fn_base-uri.html] And the second is exist-db specific. This ones works with basexdb. I read this in the comments "But if there is something that returns only the name of the file (not whole uri), let me know please" I thought that's what was being asked and wasn't.Tyrolienne
I've edited your answer to include the important parts of your comment into it because it is very useful for people who are just scanning answers. I saw the OP accepted the fn:base-uri answer and thought it did everything the OP wanted. I see now that the comments indicate otherwise. As you can see, people skip comments.Copula
return let $file := is invalid syntax in eXist 2.2, and your regular expressions won't work for files that have no extension (which is quite possible).Copula
Thanks Louis, yeah I didn't put the full code there. I had just just put some partial code to show the regex mostly. The code there now works in basex. It saves a collection of xml documents in basex named by the filename without the extension. I haven't tested in on existdb but db:replace is a basex function I believe so would need adjusting on existdb.Tyrolienne

© 2022 - 2024 — McMap. All rights reserved.