Package org.exist.fluent

Provides classes and interfaces to interact with an embedded instance of the eXist XML database.

See:
          Description

Interface Summary
Document.Listener Listener for events affecting documents.
Folder.Listener Listener for events affecting folders.
Listener The supertype for all listeners on database documents and folders.
 

Class Summary
AttributeBuilder Allows attributes to be added to, replaced in and removed from an existing element in the database.
Database The global entry point to an embedded instance of the eXist database.
DatabaseTestCase A superclass for database unit tests.
DataUtils A bunch of static data conversion utility methods.
Document A document from the database, either binary or XML.
Document.Event An event that concerns a document.
Document.MetadataFacet The metadata facet for this document.
ElementBuilder<K> A builder of DOM trees, meant to be either stand alone or be inserted into pre-existing ones.
Folder A named collection of XML documents in the database.
Folder.Event An event that concerns a folder.
Item An XML item in the database.
ItemList The result of a query on the database, holding a collection of items.
Listener.Event The superclass for all database events.
ListenerManager Internal class not for public use; needs to be public due to external instantiation requirements.
ListenerManager.TriggerDispatcher A centralized trigger listener for eXist that dispatches back to the singleton ListenerManager.
Name An actual or virtual name for a document, augmented with instructions for processing in case of duplication.
NamedResource A named resource in the contents tree of the database: either a folder or a document.
NamedResource.MetadataFacet The metadata facet of a named resource.
NamespaceMap A map of short keys to namespace uris that can be cascaded.
Node A node in the database.
QName A qualified name, consisting of a namespace and a local name.
QueryService Provides facilities for performing queries on a database.
QueryService.QueryAnalysis An access point for running various analyses on a query.
QueryService.Statistics  
QueryService.Statistics.Entry Performance counters for a single query.
Resource A database object that can be further queried.
Source A source of data to be loaded into the database, distinguishing between XML documents and other (binary) documents.
Source.Blob A source of binary data to be loaded into the database.
Source.XML A source of XML data to be loaded into the database.
XMLDocument An XML document from the database.
 

Enum Summary
QueryService.QueryAnalysis.Cardinality The enumeration of recognized cardinalities for parameter and return types.
Trigger An action being undertaken on the database, used to characterize an event.
 

Exception Summary
DatabaseException Signals all errors and failures related to database access.
 

Annotation Types Summary
DatabaseTestCase.ConfigFile An annotation that specifies the path of the config file to use when setting up the database for a test.
 

Package org.exist.fluent Description

Provides classes and interfaces to interact with an embedded instance of the eXist XML database. This API layer takes advantage of Java 5.0 language features to make interaction with the database easier. If you choose to use this API, you should not use any other eXist packages directly or attempt to interface with eXist through other means at the same time.

The API's style is styled after that of the java.util collection classes. Preference is given to using nouns as accessor names directly (e.g. size()) rather than prefixed with set or get (e.g. getSize()). All collection-like classes implement Iterable so that they can be used in JDK 5.0 for-each loops. Many classes offer facets—auxiliary objects that offer access to a themed subset of functionality (e.g. Folder.documents() for functions related to the documents in a folder) or that view the object in a special way (e.g. ItemList.values() that views a list of items as a list of their effective string values). Finally, some classes offer a StringBuffer-style interface for chaining calls, providing a miniature domain specific language within their context (e.g. QueryService or ElementBuilder).

Folders and documents

The entry point to this API is the Database class. After you've started up the database and obtained a handle by logging in a user, you can start accessing the database's contents. The database is laid out as a hierarchy of folders, with the root folder called "/". You can obtain a reference to a folder via Database.getFolder(), or create a folder via Database.createFolder() (supplying an absolute path in each case, e.g. "/top/other").

Each folder also contains documents. You can retrieve them either absolutely, through Database.getDocument(), or locally, through Folder.documents().get(). A document has either binary or XML contents; only the XML documents will be indexed and participate in queries. You can add documents to the database either by loading them from external sources with Folder.documents().load(Name, Source.XML) for XML documents, or Folder.documents().load(Name, Source.Blob) for binary ones. For example, to load all files in a directory into a folder you could do:

void loadDirectoryIntoFolder(File directory, Folder destination) {
  for (File file : directory.listFiles()) {
    if (!file.isFile()) continue;
    // assume that a file is XML iff its filename ends with ".xml"
    boolean xmlFile = file.getName().toLowerCase().endsWith(".xml");
    destination.documents().load(
      Name.keepOverwrite(),
      xmlFile ? Source.xml(file) : Source.blob(file)
    );
  }
}
You can also build XML files element by element directly using Folder.documents().build(Name). This method returns a builder, which accepts a sequence of construction commands ending with commit(). For example, to build this small XML document:
<contact>
  <name kind='first'>Piotr</name>
  <name kind='family'>Kaminski</name>
</contact>
you could use the following code:
void buildContact(Folder folder) {
  folder.documents().build(Name.create("pk-record"))
    .elem("contact")
      .elem("name").attr("kind", "first").text("Piotr").end("name")
      .elem("name").attr("kind", "family").text("Kaminski").end("name")
    .end("contact")
  .commit();

Queries

Once XML documents have been built or loaded into the database, you can query them using XQuery. To run a query, you must first obtain a QueryService, typically by calling query() on any Resource: the query will be executed in the context of the resource from which it was obtained. Some typical resources are folders and documents, but you can also refine your results by querying within the context of an ItemList or Item obtained from a previous query.

Once you're secured a query service, you must call a query execution method appropriate for the kind of result you are expecting. The most general method is all(), which simply returns all results as an ItemList in the order specified by the query (usually document order). If you don't care about the order, you can use unordered(), which may allow the database to further optimize the query's performance. If you know your query will return precisely one item, you should use single(), which will return an Item or fail with a DatabaseException if the query returns an unexpected number of items. If you know the query will return at most one item, you should use optional(), which will return an Item or a special Item placeholder if the result was empty (you can check which one it is with extant() if needed). There are other specialized query methods as well.

When running a query, you often need to pass parameters into the query expression. The easiest way to do this is to add any desired arguments to the query execution call; they will automatically be bound to XQuery variables of the form $_1, $_2, etc. You can also set variables using the let() method.

Here is a sample query over documents of the form given in the previous section. Note that there are no special methods for accessing a node's attributes—queries are used for everything.

void printNames(Folder folder) {
  for (Node contact : folder.query().all("//contact").nodes()) {
    for (Node name : contact.query().all("name").nodes()) {
      System.out.print(name.query().single("@kind").value());
      System.out.print("=");
      System.out.print(name.value());
      System.out.print(" ");
    }
    System.out.println();
  }
}

Namespaces

Every object that might need to interpret XML element tags or attribute names has its own namespace bindings that map prefixes to namespace URIs. Each set of bindings inherits from the bindings of the database object it was derived from, creating a chain that goes all the way back to the original database instance. Thus, setting the desired bindings via Database.namespaceBindings() will make them available throughout your code. On the other hand, any object can add on to and override the namespace bindings without affecting its ancestors to allow for more complicated situations.



Copyright (C) All rights reserved.