XQuery/Using Triggers to assign identifiers

MotivationEdit

You want to automagically assign unique identifiers to all new incoming documents or XML nodes: no matter if they are created from a controller that you scripted, if they are resulting from an HTTP PUT operation in a REST call, if they are the product of a webdav COPY operation, or uploaded from the java admin RPC client.

MethodEdit

We will create a trigger that will fire on all document store operations. The trigger will modify the document to be stored in the database. Our identifier will be taken from the output of the util:uuid() function. A simple assignment will do due diligence. No special authority, such as an incremental counter, will be necessary.

System ConfigurationEdit

This example assumes that the documents that you want to tag with identifiers live below /db/my-collection. eXist triggers are declared in a configuration file that is placed in the /db/system/config area with the above path added to it. Such a file with the relevant lines will look like this:

/db/system/config/db/my-collection/collection.xconf

<collection xmlns="http://exist-db.org/collection-config/1.0">
  <triggers>
    <trigger event="store" class="org.exist.collections.triggers.XQueryTrigger">
       <parameter name="url" value="xmldb:exist://localhost/db/triggers/assign-id.xq"/>
    </trigger>
  </triggers>
</collection>

Now every time a store or update event happens to this collection the XQuery script /db/triggers/assign-id.xq gets run.

Beware! You cannot, due to limitations of current (<=1.5dev) design, attach more than one xquery script to the same trigger event. Only the trigger declared last for an event will be used.

XQuery ScriptEdit

The script will add the uuid as an attribute to the root element of the incoming document, overwriting any uuid attribute that is already there.

NOTE: These examples do not work reliably: As soon as your xquery causes exceptions in the thread that it runs in, then there is a great chance, that it will hang indefinitely, eg. if you store a binary resource below the path it works on. Further operations on the processed resource then will NOT trigger the script until a restart of the whole database.

xquery version "1.0";
 
(:
  An XQueryTrigger that
  adds a uuid to all documents
  when they are stored in the database.
:)
 
declare namespace util="http://exist-db.org/xquery/util";
 
declare variable $local:triggerEvent external;
declare variable $local:eventType external;
declare variable $local:collectionName external;
declare variable $local:documentName external;
declare variable $local:document external;
 
declare variable $local:coll := "/db/my-collection";
declare variable $local:uuid := string($local:document/@uuid);
declare variable $local:match := collection($local:coll)/*[@uuid = $local:uuid];
 
(:
  This is still the xquery prolog:
  from my experiments, an xquery trigger MUST NOT hava an xquery body.
  A severe limit: no conditionals allowed, just straight procedural action.
:)
 
util:log('debug', '### assign-id.xq trigger fired ###'),
 
update insert attribute {'uuid'} {util:uuid()} into doc($local:documentName)/*,
 
util:log('debug', '### assign-id.xq trigger done ###')

ReferencesEdit

Guide to configuring eXist triggers

Last modified on 21 February 2013, at 13:06