The quickest way to learn how to use the APIs is as follows:
Every Galax API has functions for:
This chapter describes how to use each kind of functions.
Galax currently supports application-program interfaces for the O’Caml, C, and Java programming languages.
All APIs support the same set of functions; only their names differ in each language API. This file describes the API functions. The interfaces for each language are defined in:
If you use the C API, see Section 6.5.1 “Memory Management in C API”.
Example programs that use these APIs are in:
To try out the API programs, edit examples/Makefile.config to set up your environment, then execute: cd $GALAXHOME/examples; make all.
This will compile and run the examples. Each directory contains a "test" program that exercises every function in the API and an "example" programs that illustrates some simple uses of the API.
The Galax query engine is implemented in O’Caml. This means that values in the native language (C or Java) are converted into values in the XQuery data model (which are represented are by O’Caml objects) before sending them to the Galax engine. The APIs provide functions for converting between native-language values and XQuery data-model values.
There are two kinds of Galax libraries: byte code and native code. The C and Java libraries require native code libraries, and Java requires dynamically linked libraries. Here are the libraries:
O’Caml libraries in $GALAXHOME/lib/caml:
C libraries in $GALAXHOME/lib/c:
Java libraries in $GALAXHOME/lib/java:
Note that Java applications MUST link with a dynamically linked library and that C applications MAY link with a dynamically linked library.
For Linux users, set LD_LIBRARY_PATH to $GALAXHOME/lib/c:$GALAXHOME/lib/java.
The Makefiles in examples/c_api and examples/java_api show how to compile, link, and run applications that use the C and Java APIs.
The simplest API functions allow you to evaluate an XQuery statement in a string. If the statement is an update, these functions return the empty list, otherwise if the statement is an Xquery expression, these functions return a list of XML values.
The example programs in $(GALAXHOME)/examples/caml_api/example.ml, $(GALAXHOME)/examples/c_api/example.c, $(GALAXHOME)/examples/java_api/Example.java illustrate how to use these query evaluation functions.
Galax accepts input (documents and queries) from files, string buffers, channels and HTTP, and emits output (XML values) in files, string buffers, channels, and formatters. See $(GALAXHOME)/lib/caml/galax_io.mli.
All the evaluation functions require a processing context. The default processing context is constructed by calling the function Processing_context.default_processing_context():
val default_processing_context : unit -> processing_context
There are three ways to evaluate an XQuery statement:
val eval_statement_with_context_item : Processing_context.processing_context -> Galax_io.input_spec -> Galax_io.input_spec -> item list
Bind the context item (the XPath "." expression) to the XML document in the resource named by the second argument, and evaluate the XQuery statement in the third argument.
val eval_statement_with_context_item_as_xml : Processing_context.processing_context -> item -> Galax_io.input_spec -> item list
Bind the context item (the XPath "." expression) to the XML value in the second argument and evaluate the XQuery statement in the third argument.
val eval_statement_with_variables_as_xml : Processing_context.processing_context -> (string * item list) list -> Galax_io.input_spec -> item list
The second argument is a list of variable name and XML value pairs. Bind each variable to the corresponding XML value and evaluate the XQuery statement in the third argument.
Sometimes you need more control over query evaluation, because, for example, you want to load XQuery libraries and/or main modules and evaluate statements incrementally. The following two sections describe the API functions that provide finer-grained control.
In the XQuery data model, a value is a sequence (or list) of items. An item is either an node or an atomic value. An node is an element, attribute, text, comment, or processing-instruction. An atomic value is one of the nineteen XML Schema data types plus the XQuery type xs:untypedAtomic.
The Galax APIs provide constructors for the following data model values:
The constructor functions for atomic values take values in the native language and return atomic values in the XQuery data model. For example, the O’Caml constructor:
val atomicFloat : float -> atomicFloat
takes an O’Caml float value (as defined in the Datatypes module) and returns a float in the XQuery data model. Similarly, the C constructor:
extern galax_err galax_atomicDecimal(int i, atomicDecimal *decimal);
takes a C integer value and returns a decimal in the XQuery data model.
The constructor functions for nodes typically take other data model values as arguments. For example, the O’Caml constructor for elements:
val elementNode : atomicQName * attribute list * node list * atomicQName -> element
takes a QName value, a list of attribute nodes, a list of children nodes, and the QName of the element’s type. Simliarly, the C constructor for text nodes takes an XQuery string value:
extern galax_err galax_textNode(atomicString str, text *);
The constructor functions for sequences are language specific. In O’Caml, the sequence constructor is simply the O’Caml list constructor. In C, the sequence constructor is defined in galapi/itemlist.h as:
extern itemlist itemlist_cons(item i, itemlist cdr);
The APIs are written in an "object-oriented" style, meaning that any use of a type in a function signature denotes any value of that type or a value derived from that type. For example, the function Dm_functions.string_of_atomicvalue takes any atomic value (i.e., xs_string, xs_boolean, xs_int, xs_float, etc.) and returns an O’Caml string value:
val string_of_atomicValue : atomicValue -> string
Similarly, the function galax_parent in the C API takes any node value (i.e., an element, attribute, text, comment, or processing instruction node) and returns a list of nodes:
extern galax_err galax_parent(node n, node_list *);
The accessor functions take XQuery values and return constituent parts of the value. For example, the children accessor takes an element node and returns the sequence of children nodes contained in that element:
val children : node -> node list (* O’Caml *) extern galax_err galax_children(node n, node_list *); /* C */
The XQuery data model accessors are described in detail in http://www.w3c.org/TR/query-datamodel.
Galax provides the load_document function for loading documents.
The load_document function takes the name of an XML file in the local file system and returns a sequence of nodes that are the top-level nodes in the document (this may include zero or more comments and processing instructions and zero or one element node.)
val load_document : Processing_context.processing_context -> Galax_io.input_spec -> node list (* O’Caml *)
extern galax_err galax_load_document(char* filename, node_list *); extern galax_err galax_load_document_from_string(char* string, node_list *);
The general model for evaluating an XQuery expression or statement proceeds as follows (each function is described in detail below):
let proc_ctxt = default_processing_context() in
let mod_ctxt = load_standard_library(proc_ctxt) in
let library_input = File_Input "some-xquery-library.xq" in let mod_ctxt = import_library_module pc mod_ctxt library_input in
let (mod_ctxt, stmts) = import_main_module mod_ctxt (File_Input "some-main-module.xq") in
let ext_ctxt = build_external_context proc_ctxt opt_context_item var_value_list in let mod_ctxt = add_external_context mod_ctxt ext_ctxt in
let mod_ctxt = eval_global_variables mod_ctxt
** NB: This step is necessary if the module contains *any* global variables, whether defined in the XQuery module or defined externally by the application. **
let result = eval_statement proc_ctxt mod_ctxt stmt in
let result = eval_statement_from_io proc_ctxt mod_ctxt (Buffer_Input some-XQuery-statement) in
let result = eval_query_function proc_ctxt mod_ctxt "some-function" argument-values in
Every query is evaluated in a module context, which includes:
The functions for creating a module context include:
val default_processing_context : unit -> processing_context
The default processing context, which just contains flags for controlling debugging, printing, and the processing phases. You can change the default processing context yourself if you want to print out debugging info.
val load_standard_library : processing_context -> module_context
Load the standard Galax library, which contains the built-in types, namespaces, and functions.
val import_library_module : processing_context -> module_context -> input_spec -> module_context
If you need to import other library modules, this function returns the module_context argument extended with the module in the second argument.
val import_main_module : processing_context -> module_context -> input_spec -> module_context * (Xquery_ast.cstatement list)
If you want to import a main module defined in a file, this function returns the module_context argument extended with the main module in the second argument and a list of statements to evaluate.
The functions for creating an external context (context item and global variable values):
val build_external_context : processing_context -> (item option) -> (atomicDayTimeDuration option) -> (string * item list) list -> external_context
The external context includes an optional value for the context item (known as "."), the (optional) local timezone, and a list of variable name, item-list value pairs.
val add_external_context : module_context -> external_context -> module_context
This function extends the given module context with the external context.
val eval_global_variables : processing_context -> xquery_module -> xquery_module
This function evaluates the expressions for all (possibly mutually dependent) global variables. It must be called before calling the eval_* functions otherwise you will get an "Undefined variable" error at evaluation time.
Analogous functions are defined in the C and Java APIs.
The APIs support three functions for evaluating a query: eval_statement_from_io, eval_statement, and eval_query_function.
Note: If the module context contains (possibly mutually dependent) global variables, the function eval_global_variables must be called before calling the eval_* functions otherwise you will get an "Undefined variable" error at evaluation time.
val eval_statement_from_io : processing_context -> xquery_module -> Galax_io.input_spec -> item list
Given the module context, evaluates the XQuery statement in the third argument. If the statement is an XQuery expression, returns Some (item list); otherwise if the statement is an XQuery update, returns None (because update statements have side effects on the data model store, but do not return values).
val eval_statement : processing_context -> xquery_module -> xquery_statement -> item list
Given the module context, evaluates the XQuery statement
val eval_query_function : processing_context -> xquery_module -> string -> item list list -> item list
Given the module context, evaluates the function with name in the string argument applied to the list of item-list arguments. Note: Each actual function argument is bound to one item list.
Analogous functions are defined in the C and Java APIs.
Once an application program has a handle on the result of evaluating a query, it can either use the accessor functions in the API or it can serialize the result value into an XML document. There are three serialization functions: serialize_to_string, serialize_to_output_channel and serialize_to_file.
val serialize : processing_context -> Galax_io.output_spec -> item list -> unit
Serialize an XML value to the given galax output.
val serialize_to_string : processing_context -> item list -> string
Serializes an XML value to a string.
Analogous functions are defined in the C and Java APIs.
The Galax query engine is implemented in O’Caml. This means that values in the native language (C or Java) are converted into values in the XQuery data model (which represented are by O’Caml objects) before sending them to the Galax engine. Similarly, the values returned from the Galax engine are also O’Caml values – the native language values are "opaque handles" to the O’Caml values.
All O’Caml values live in the O’Caml memory heap and are therefore managed by the O’Caml garbage collector. The C API guarantees that any items returned from Galax to a C application will not be de-allocated by the O’Caml garbage collector, unless the C appliation explicitly frees those items, indicating that they are no longer accessible in the C appliation. The C API provides two functions in galapi/itemlist.h for freeing XQuery item values:
extern void item_free(item i);
Frees one XQuery item value.
extern void itemlist_free(itemlist il);
Frees every XQuery item value in the given item list.
The Galax query engine may raise an exception in O’Caml, which must be conveyed to the C application. Every function in the C API returns an integer error value :
The global variable galax_error_string contains the string value of the exception raised in Galax. In future APIs, we will provide a better mapping between error codes and Galax exceptions
The Galax query engine is implemented in O’Caml. This means that values in the native language (C or Java) are converted into values in the XQuery data model (which represented are by O’Caml objects) before sending them to the Galax engine.
The Java API uses JNI to call the C API, which in turn calls the O’Caml API (it’s not as horrible as it sounds).
There is one class for each of the built-in XML Schema types supported by Galax and one class for each kind of node:
Atomic | Node | Item |
xsAnyURI | Attribute | |
xsBoolean | Comment | |
xsDecimal | Element | |
xsDouble | ProcessingInstruction | |
xsFloat | Text | |
xsInt | ||
xsInteger | ||
xsQName | ||
xsString | ||
xsUntyped |
There is one class for each kind of sequence:
There is one class for each kind of context used by Galax:
Finally, the procedures for loading documents, constructing new contexts and running queries are in the Galax class.
All Galax Java API functions can raise the exception class GalapiException, which must be handled by the Java application.
All Java-C-O’Caml memory management is handled automatically in the Java API.
Currently, Galax is not re-entrant, which means multi-threaded applications cannot create multiple, independent instances of the Galax query engine to evaluate queries.
The C API library libgalaxopt.a,so does not link properly under MinGW. A user reported that if you have the source distribution, you can link directly with the object files in galapi/c_api/*.o and adding the library -lasmrun on the command line works.