The OWLlink interface provides an implementation-neutral mechanism for accessing OWL reasoner functionality. This document defines the OWLlink HTTP/S-Expression Binding as a syntactic variant of the [OWLlink HTTP/Functional Binding]. Its syntax is close to that of functional programming languages such as Common Lisp, which are still very popular implementation languages for OWL 2 reasoners and related tools. The S-Expression Binding can also be considered as a modern variant of the (nowadays slightly outdated) classic [KRSS Specification].
The OWLlink Working Group seeks public feedback on this Working Group Recommendation. Please send your comments to public-comments@owllink.org or post to the public discussion forum at http://www.owllink.org/forum/.
Contents |
This document presents an S-Expression syntax for OWLlink and thus a concrete syntax for OWLlink which is convenient for Lisp-based OWLlink implementations, e.g. [Common Lisp], acknowledging the fact that functional programming languages such as Common Lisp are still very popular implementation languages for OWL 2 reasoners and related tools. The OWLlink HTTP/S-Expression binding, or OWLlink S-Expression for short, can be seen as a syntactic variant of the [OWLlink HTTP/Functional Binding]. Moreover, the S-Expression binding could be considered as a modern variant of the (nowadays slightly outdated) classic [KRSS Specification]. S-Expressions can be directly consumed and produced by Lisp-like languages; thus, no further machinery is required to process these messages.
The OWLlink S-Expression binding, likewise to the OWLlink Functional binding, employs [HTTP/1.1] as the underlying transport protocol. As such, standard notions and features from the HTTP protocol apply (e.g., sessions, content encoding and compression, etc.), and are used in the HTTP 1.1 sense in this document.
The abstract set and syntax of OWLlink messages is specified in the [OWLlink Structural Specification] in terms of UML. The most important design criteria for the concrete S-Expression syntax specified in this document is Lisp-readabilty. This means that messages must be parsable by the Common Lisp function read without requiring additional frameworks or additional machinery such as XML parsers etc.
To exemplify this, consider the following OWLlink message in the OWLlink HTTP/XML binding, which adds an OWL 2 ClassAssertion axiom to a freshly created knowledge base http://www.owllink.org/KB_1, and asks for the instances of the Father class:
This message takes the following form in the OWLlink S-Expression binding:
Like in the [OWLlink HTTP/Functional Binding], the NamespacePrefix message is used in order to emulate XML namespaces.
Since the OWL 2 functional-syntax for full URIs is unreadable by Lisp, the S-Expression binding uses simple symbols for the representation of URIs. In addition, an implementation should also accept strings for IRIs, for fullIRIs as well as for abbreviated IRIs, but only if they are used as attribute values and not at functor position (i.e., do not appear as the first element in a list or S-Expression).
According the Common Lisp syntax rules, all symbols which contain special, non-alphanumerical characters or whitespaces, e.g. the colon, whitespaces, period or hash quote etc., have to be enclosed in bars (character "|"). OWLlink messages are read in a case-sensitive mode. That is, (eq (readtable-case *readtable*) :preserve) is assumed when OWLlink S-Expression messages are consumed. This implies that no surrounding bars must be used for symbols such as GetInstances.
Another syntax problem regarding Lisp-readability is caused by the OWL2 functional syntax for owl.typedLiteral elements. Therefore, the S-Expression syntax for the typed literal "John Doe"^^xsd:string is (OWLLiteral "John Doe" "xsd:string").
Whenever the OWLlink specification accepts an (UML) argument of type string, either a Common Lisp string or a Common Lisp symbol may be used to ensure good human readabilty. Moreover, boolean arguments may be supplied as t and nil, as it is standard in Common Lisp.
As for the OWLlink Functional syntax, the standard namespace prefixes are assumed to be predefined (rdf, rdfs, xsd, owl, ol).
To specify arguments, a standard Common Lisp argument-passing style using a list of so-called keyword value pairs. Hence, OWLlink messages can be directly processed by Common Lisp macros (see Section 4 for implementation hints), which is a big benefit since no additional message parsers are required. The empty argument lists of OWL 2 elements like ClassAssertion is omitted. However, the omission of empty argument lists for OWLlink messages is prohibited to ensure backwards compatibilty of existing OWLlink messages in case additional arguments are added to future versions of these messages (otherwise, old messages would have to be rewritten to be acceptable by the extended OWLlink parser).
As for OWLlink Functional, implementors can reuse their existing OWL 2 functional-style parsers to parse OWLlink S-Expression terms by implementing some simple syntax transformations which are specified in Section 2.
Consider the valid OWLlink XML/HTTP response to the request given above:
In OWLlink S-Expression, this message takes the following form:
The same syntax rules and conventions as for the request messages also apply for the response messages. The S-Expression response messages can easily be further processed by standard Common Lisp macros (see below), given the Common Lisp reader is set up properly (see Section 4).
Whereas the syntax of the OWLlink Functional is readable, it is verbose and has the drawback that it cannot directly be processed by some functional programming languages such a Common Lisp. OWLlink S-Expression is designed in such a way that parsing and processing of the messages becomes straight forward in standard Lisp dialects such as Common Lisp, without requiring additional heavy-weight machinery or frameworks such as XML parsers, resulting also in a less verbose syntax.
To ensure the consumption of OWLlink messages in the S-Expression syntax by the Lisp function read, certain derivations from the standard OWL 2 functional-style syntax have to be accepted. For example, owl.fullIRIs must be specified as Common Lisp strings or as Common Lisp symbols enclosed in bars, e.g. <http://www.w3.org/2002/07/owl#ClassAssertion> is not readable by read and thus, if no abbreviated variant is used, either "http://www.w3.org/2002/07/owl#ClassAssertion" or |http://www.w3.org/2002/07/owl#ClassAssertion| have to be used instead. Whereas both strings and symbols are acceptable for such IRIs at argument or keyword value position in an S-Expression message, only the symbol representation is possible if IRIs are used at functor position, in order to ensure that such message can directly be used as function or macro calls. A standard Common Lisp argument-passing style is adopted. As a result of these design decissions, OWLlink message handlers ("parsers") can directly be implemented through simple Common Lisp macros (see Section 4 for implementation hints).
As in Section '2.2 XML Schema' [OWLlink HTTP/XML Binding], the concrete S-Expression syntax is given by specifying two syntax translation functions: T and AT. If i is a direct OWLlink instance (message) or OWL 2 instance (message) of type (UML class) c in the object graph, and i has attribute values v_1, ..., v_n for the attributes a_1, ..., a_n of types t_1, ..., t_n (n may be zero), and also has associations ac_1, ..., ac_m to further instances (messages) i_1, ..., i_m (m may be zero) of types c_1, ..., c_m (the ranges of the associations), and if i is itself possibly the source individual of some association ac (ac is nil in case i is a root individual of the object graph), then the concrete syntax of i is given by T(i,c,ac), where T is the translation function specified below. Note that, if i is a root node and thus c is either RequestMessage or a ResponseMessage, then the OWLlink functional-style concrete syntax is given by T(i,c,nil). In general, T(i,c,ac) is specified as follows (note that terminal content is specified in double quotes in this binding).
":IRI" i'
and i' is either a Common Lisp string or symbol. A symbol has to use the surrounding bars syntax (character "|") if the symbol contains non-alphanumeric characters or whitespaces. For mixed-case symbols, no enclosing bars are required since it is assumed that (eq (readtable-case *read-table*) :preserve) holds during reading of the OWLlink S-Expression message. More details on symbol and string syntax can be found in the [CLtL2].
":"ac i'
and i' is rendered as in the previous case. Unlike in the OWL 2 functional-style syntax, IRIs are not enclosed in sharp parentheses (characters "<", ">").
S(i')
where i' is specified in the [OWL 2 Specification] and S(i') is the result of applying the following transformation function S to i', converting the functional message into an S-Expression in the obvious way:
"(OWLLiteral" owl.lexicalForm owl.Datatype ")"is used, where both owl.lexicalForm and owl.Datatype are Common Lisp strings.
f "(" i'_1 ... i'_n ")"
where i'_1 ... i'_n are i_1 ... i_n in OWL 2 functional-style syntax, then S(i') is given as
"(" f' S(i'_1) ... S(i'_n) ")"
where f' is either f or |prefix.f| with prefix either some declared NamespacePrefix for <http://www.w3.org/2002/07/owl#>, or owl. Moreover, the fully qualified syntax |"http://www.w3.org/2002/07/owl#"f| may be used for f'.
"(" c' "(" TA(v_1,a_1) ... TA(v_n,a_n) ")" T(i_1,c_1,ac_1) ... T(i_m,c_m,ac_m) ")"
where either c'=|nsprefix.postfix| if some namespace prefix nsprefix is defined for the namespace namespace such that c is the concatenation of namespace and postfix, or c' is |c| if no such namespace prefix nsprefix is declared, or the implementation does not support namespace prefixes. Moreover, if nsprefix is one of ol, rdf, rdfs, xsd, owl, then postfix may be used for c'. The same comments from item 5, Section '2 Functional Binding' [OWLlink HTTP/Functional Binding] apply regarding usage and declaration of namespace prefixes and scope of these declarations apply here. Only the syntax differs, since Common Lisp symbols containing periods have to be enclosed in bars (character "|"), and sharp parantheses may not be used.
The same comments regarding the order of the associated / referenced instances i_1 ... t_m apply here. This order is specified in Section '2.2 XML Schema' [OWLlink HTTP/XML Binding] and adopted here.
Again, TA is the attribute translation function. If v is an attribute value (e.g., the string "true") for attribute a (e.g., result) of type t (e.g., string), then TA(v,a) is specified as follows:
":"ac v'
and v' is thus either a Common Lisp string, integer, or boolean. The strings "true" and "false" may be used for the Common Lisp booleans t and nil as well. In all caes, the empty attribute list () is equivalent to nil.
The NamespacePrefix message takes the following form in the OWLlink S-Expression binding.
(NamespacePrefix () nsprefix fullIRI)
nsprefix is either a Common Lisp string or a symbol (which has to be enclosed in bars, character "|" in case it contains whitespaces or non-alphanumeric characters. Prefixes do not necessarily, but may end with colons. fullIRI is either a Common Lisp string or a symbol. The same conventions for specifying full IRIs as strings or symbols as already discussed above apply, as well as the comments regarding scope and standard namespace prefixes.
A set of rendering options may appear in the header of a RequestMessage, similar to the NamespacePrefix message. The syntax is the following:
(RenderingOption () renderingOption boolean)
where renderingOption is one of
and the boolean is specified either as a Common Lisp boolean (t, nil) or Common Lisp string ("true", "false").
These scope of these rendering options is the current OWLlink request-response pair and effects response generation. The effect of these switches is described as follows:
(f () ...)are thus reduced to
(f ...)before being returned to the client.
(BooleanResponse (:result boolean)are reduced to t or nil (depending on boolean), and messages of the kind
(StringResponse (:result string))are condensed to
stringbefore being returned to the client.
(structuringElement () ...)are reduced to
(...)where structuringElement is one of the following elements:
(atom ())are simplified to simple symbols:
atom
Since the S-Expression response is still verbose, it is possible to further strip down the verbosity by specifying a set of rendering options. For example, by putting
(RenderingOption () removeEmptyArgumentLists t) (RenderingOption () flattenStructuringElements t) (RenderingOption () simplifyAtomicMessages t)
in the header of the S-Expression request message, the following much less verbose and more Lisp-like result will be returned instead:
Note that rendering options are only available in OWLlink S-Expression, not in OWLlink Functional.
This Section present the example request and response messages from Section '4 Examples' [OWLlink HTTP/XML Binding] in S-Expression Syntax.
GetDescription request.
GetDescription response.
CreateKB request.
CreateKB response.
GetSettings request.
GetSettings response.
Set request.
Set response.
Prefix request.
Prefix response. Please note that the fourth GetSubclass request raises an error, since it refers to the unqualified class A which relies on the XML base xml:base="http://www.owllink.org/examples/myOntology#" in the corresponding HTTP/XML example. Since there is no such feature in the OWLlink S-Expression binding, A cannot be resolved to http://www.owllink.org/examples/myOntology#A.
LoadOntologies request.
LoadOntologies response.
Pooling request.
Pooling response.
Taxonomy request.
Taxonomy response.
This Section presents a small dummy Common Lisp implementation that is capable to parse and "process" a small OWLlink S-Expression example message. The example message to be processed is the following:
(NamespacePrefix () ret |http://www.owllink.org/ext/retraction|) (RequestMessage () (Tell (:kb "http://www.owllink.org/KB") ; note: URI as strings (Prefix (:name "test" :fullIRI |http://www.test.org/|)) (SubClassOf |test:A| |http://www.owllink.org.test/B|) (owl.SubClassOf "test:C" "http://www.owllink.org.test/D")) (ret.Retract (:kb |http://www.owllink.org/KB|) ;; note: URI as symbols (SubClassOf |test:A| |http://www.owllink.org.test/B|)))
The Common Lisp program given below produces the following output if applied to the above message, thus demonstrating that such messages can be processed with little effort in Lisp-like languages without requiring further heavy weight machinery (e.g., XML parsers):
(|http://www.owllink.org/owllink|::add-implies '|http://www.test.org/A| '|http://www.owllink.org.test/B| :kb '|http://www.owllink.org/KB|) (|http://www.owllink.org/owllink|::add-implies '|http://www.test.org/C| '|http://www.owllink.org.test/D| :kb '|http://www.owllink.org/KB|) (|http://www.owllink.org/owllink|::forget-implies '|http://www.test.org/A| '|http://www.owllink.org.test/B| :kb '|http://www.owllink.org/KB|)Here is the program, including some helpful comments. The programm assumes that the example message is stored under the filename "owllink-sexpr-test.lisp":
;;; ;;; Set up some Common Lisp packages ;;; This package contains the main OWLlink implementation: ;;; Namespaces correspond to Common Lisp packages ;;; in this implementation ;;; (defpackage |http://www.owllink.org/owllink| (:use :cl) (:nicknames |ol|) (:export "RequestMessage" "Tell" "Prefix" "NamespacePrefix" "name" "kb" "fullIRI" "owl.SubClassOf")) ;;; ;;; All elements from OWL reside in this package: ;;; (defpackage |http://www.w3.org/2002/07/owl| (:use :cl) (:nicknames |owl|) (:export "SubClassOf")) ;;; ;;; Each OWLlink extension ;;; resides in its own package: ;;; (defpackage |http://www.owllink.org/ext/retraction| (:use :cl |ol|) (:nicknames |ret|) (:export "Retract")) ;;; ;;; ;;; (in-package "ol") (defvar *retraction* nil) (defvar *kb* nil) (defvar *kb-prefixes* nil) (defun ensure-symbol (a) (if (symbolp a) a (intern (ensure-string a)))) (defun ensure-string (a) (if (stringp a) a (format nil "~A" a))) ;;; ;;; Helper functions for dealing with namespace prefixes: ;;; (defun add-kb-prefix (|name| |fullIRI|) (let ((prefixes-for-kb (assoc *kb* *kb-prefixes*))) (if prefixes-for-kb (push (list (ensure-symbol |name|) |fullIRI|) (second prefixes-for-kb)) (push (list *kb* (list (list (ensure-symbol |name|) |fullIRI|))) *kb-prefixes*))) nil) (defun expand-prefix (prefix) (second (assoc (ensure-symbol prefix) (second (assoc *kb* *kb-prefixes*))))) (defun expand-name (a) (let* ((name (ensure-string a)) (pos (position #\: name)) (prefix (and pos (subseq name 0 pos))) (name (if pos (subseq name (1+ pos)) name)) (prefix (expand-prefix prefix))) (ensure-symbol (if prefix (format nil "~A~A" prefix name) a)))) (defun expand-expression (expr) (typecase expr ((or symbol string) (expand-name expr)) (cons (mapcar #'expand-expression expr)) (otherwise expr))) ;;; ;;; The implementation of the reasoner's native ;;; API functions; for demonstration purpose, ;;; only a simple output is generated ;;; (defun implies (a b) (if *retraction* (pprint `(forget-implies ',a ',b :kb ',*kb*)) (pprint `(add-implies ',a ',b :kb ',*kb*)))) ;;; ;;; Implementation of the OWLlink message handlers ;;; Each OWLlink message handler / parser is defined ;;; as a Common Lisp macro which delegates the work ;;; to the appropriate reasoner API functions, e.g. ;;; implies, racer-call, ... ;;; (defmacro |RequestMessage| (() &body body) `(progn ,@body)) (defmacro |Tell| ((&key |kb|) &body body) `(let ((*kb* ',(ensure-symbol |kb|))) ,@body)) (defmacro |CreateKB| ((&key |kb|) &body body) `(let ((*kb* ',(ensure-symbol |kb|))) ,@body)) (defmacro |Prefix| ((&key |name| |fullIRI|)) (add-kb-prefix |name| |fullIRI|)) ;;; ;;; Implementation of message handlers / parsers for ;;; OWL 2 axioms. As mentioned, OWL 2 elements reside ;;; in the OWL package. However, all OWL 2 elements ;;; are also available directly in the OL package ;;; (with the exception of owl:Literal) ;;; (defmacro |owl|:|SubClassOf| (first second) `(implies ',(expand-expression first) ',(expand-expression second))) ;;; namespace convenience: (defmacro |SubClassOf| (first second) `(|owl|:|SubClassOf| ,first ,second)) (defmacro |owl.SubClassOf| (first second) `(|owl|:|SubClassOf| ,first ,second)) ;;; ;;; Implementation of the message handlers / parser ;;; for OWLlink extensions: ;;; (defmacro |ret|:|Retract| ((&key |kb|) &body body) `(let ((*kb* ',(ensure-symbol |kb|)) (*retraction* t)) ,@body)) ;;; ;;; Implementation of the NameSpace prefix mechanism. ;;; Since namespaces correspond to Common Lisp ;;; packages here, a namespace prefix declaration ;;; (NamespacePrefix nil <prefix> <ns>) ;;; simply ensure that all external symbols <sym> from ;;; the package <ns> can be accessed from the the ;;; current package *package* as <prefix>.<sym> ;;; (defun add-package-nickname (name nickname) (let ((p (find-package name))) (loop for s1 being the external-symbols in p do (let ((s2 (intern (format nil "~A.~A" nickname s1)))) (if (macro-function s1) (setf (macro-function s2) (macro-function s1)) (setf (macro-function s2) (macro-function s1))))))) (defmacro |NamespacePrefix| (() a b) (add-package-nickname b a)) ;;; ;;; Set up the reader for processing an ;;; OWLlink S-Expression message. ;;; Due to the NamespacePrefix mechanism, each ;;; Request ist evaluted by binding *package* to ;;; a temporary package. This is not necessarily ;;; efficent. ;;; (defvar *owllink-readtable* (copy-readtable *readtable*)) (setf (readtable-case *owllink-readtable*) :preserve) (unwind-protect (let ((package (make-package (gensym) :use '("ol" "owl")))) (let ((*package* package) (*readtable* *owllink-readtable*)) (load "owllink-sexpr-test.lisp")) (delete-package package)))