2

I cannot seem to get this right. I have a system where the web user is running a jQuery request to add a new document. The code works perfect if the collection they are storing to have no spaces in the name. This code is:

xquery version "3.0";
declare option exist:serialize "method=xhtml media-type=text/html indent=yes";
let $specialty := request:get-parameter("specialty", "")
let $collection := xmldb:encode-uri($specialty)
let $docnum := request:get-parameter("docnum", "")
let $title := request:get-parameter("title", "")
let $file := concat($docnum, '.xml')
let $path := concat($collection, '/', $file)
let $content := <article>
<div
    class="content"
    doc="{$docnum}"
    title="{xmldb:decode($title)}">
    <div
        class="panel">
        <h1>First Panel</h1>
        <p>Content goes here</p>
    </div>
 </div>
 </article>
 return
   let $new_article := xmldb:store($collection, $file, $content, 'application/xml')
      return
        let $changepermiss := sm:chmod($new_article, 'rw-rw----')
           return
             <li
            class="file"
            data-xpath="{$path}"
        >
            <a
                data-xpath="{$path}"
                onclick="doc_open('{$path}')"
                href="#"><span
                    class="glyphicon glyphicon-tags"></span>&#160;&#160;&#160;{$docnum, ': ', xmldb:decode($title)}</a>
        </li>

Now, if the collection name that comes from the request contains a space ... like this (after encoding) ... it fails.

"/db/Test/data/Core/Test%20Collection"

The error is:

exerr:ERROR Could not locate collection: /db/Test/data/Core/Test%20Collection

This occurs at this line: xmldb:store($collection, $file, $content, 'application/xml') with $collection not be recognized because of the space.

Now, to test things out, I run this and it is fine.

    xquery version "3.0";
    declare option exist:serialize "method=xhtml media-type=text/html indent=yes";
    let $test := "/db/EIDO/data/Core/Disease%20Prevention"
    let $content := <article>
        <div
            class="content"
            doc="D777"
            title="Test Document">
            <div
                class="panel">
                <h1>First Panel</h1>
                <p>Content goes here</p>
            </div>
        </div>
    </article>
    return
    let $newdoc := xmldb:store($test, "test.xml", $content, 'application/xml')
    return
        $newdoc

I cannot understand where I am going wrong in trying to reference the collection with a space in xmldb:store.

NOTE: As I said, the code works if there is no space in the name of the collection.

I have tried many combinations of encoding the URL and making a string from it but nothing seems to work.

Kevin Brown
  • 8,805
  • 2
  • 20
  • 38

2 Answers2

1

If your collection or resource names are possibly going to contain characters that need to be encoded, you need to use xmldb:encode-uri() on the names. In your first sample, you encode the collection name ($collection) but not the resource name ($file). In your second sample, you pre-encode the collection name, but the resource name contains no characters that need to be encoded; so you've fully accounted for the encoding.

Take care to ensure that the collection name, as encoded, does exist. If not, you should pre-create the collection. This could actually be the cause of the error you cite.

When you create links to these resources in HTML output, take care not to double-encode them.

You might find it useful to reference an app that handles encoding well. See the source to eXide https://github.com/wolfgangmm/eXide.

Joe Wicentowski
  • 5,159
  • 16
  • 26
1

The answer was permission issue (although I am a bit lost at that). The collection had rw-rw-r-- and the user is in the group and is in fact the owner of the collection.

When I change to include execute (rwxrwxr--) it works as expected. Confusing, but apparently execute permission in required on the collection that is going to be stored into.

Kevin Brown
  • 8,805
  • 2
  • 20
  • 38
  • 1
    Ah, I hadn't considered permissions! Keeping track of encoding has given me enough trouble in the past that I believed it could be the culprit. Yes, `x` is required on the parent collection for adding or overwriting a document. See http://exist-db.org/exist/apps/doc/security.xml#permission-checks. – Joe Wicentowski Dec 26 '16 at 03:08
  • Great question @joewiz. As I said in my answer that I have no idea why that permission would be required to store a document in the collection in the first place and why changing those permissions would change it. But that is the *only* change I made and it works. – Kevin Brown Dec 26 '16 at 03:49
  • Hmm, worth testing. Which version of eXist are you using? – Joe Wicentowski Dec 26 '16 at 03:55
  • Latest I assume, only been building this new system for about two weeks – Kevin Brown Dec 26 '16 at 05:41
  • I already upvoted your answer and upvoting your comment on the permission matrix. That is the best piece of information I have seen in scouring the truly limited documentation. – Kevin Brown Dec 26 '16 at 05:44
  • And probably your answer to your question "why did you second example work" ... likely as I am running that query through oXygen and a different user (dba probably). So your comments and discussion helped considerably, thanks much. It you would like to post or modify your answer I will accept it as it took your comments to lead me to the correct issue. – Kevin Brown Dec 26 '16 at 05:53