Table of contents

Introduction

This document is an introduction to Elda, an implementation of the Linked Data API (LDA). The LDA allows you to have a configurable, REST-style interface to a store containing RDF data. This makes it easier for developers used to using common web technologies such as JavaScript and JSON to access your data, and display it in a web browser.

Elda is a Java implementation of the LDA specification, and was developed by Epimorphics Ltd. Elda is licensed under an open-source Apache License.

A quick introduction to running Elda

Before we go on to explain more of what Elda is doing and how you can customise it, let's get an instance of Elda running and see what it can do.

The easiest route to starting Elda is to use the pre-packaged Java .jar file that you can download from http://repository.epimorphics.com/com/epimorphics/lda/elda-standalone/1.2.35/elda-standalone-1.2.35.jar . You can start the file from the command line.

java -jar elda-standalone-$VERSION.jar

where $VERSION denotes the version number of the Elda you downloaded, such as 1.2.35. If your system permits, double-clicking on the file in your preferred file browser may also work.

At this point, you may see a large number of log messages as Elda starts, and then you should be able to view the starting page in a web browser: http://localhost:8080/standalone/hello/games. This should display a page similar to:

Screenshot showing demo dataset in Elda

What just happened?

Contained within the standalone Elda version is a small RDF dataset about board games. The example configuration provides an API for viewing the contents of this dataset through simple web URLs. http://localhost:8080/standalone/hello/games lists the first page of board games that are in the example data: the different games appear as entries in the Search Results section on the left.

By default, the list is presented in HTML format, which is nice for people to read, but not so good for programs to process. The format names on the top-right of the window are clickable to select a different format, e.g. by clicking the ttl link, the BoardGame resources will be shown as RDF Turtle.

The right-hand column of the page has links to the individal items on the left, links to allow sorting on the different properties the items may have, and links for adjusting the view by adding or removing properties from it; these are more useful for bigger examples with more items and properties to experiment with.

How did it happen?

When Elda is presented with a URL, it uses it to select an endpoint. From the details of the URL path (/games in this case) and its query parameters (none in this case), it constructs a SPARQL query which selects one or more items (here, games) from the RDF dataset. It then constructs a view of (some of the) properties of those items, and then renders that view into one of the possible formats, sending that rendering back to whatever sent the query.

This example displays all available properties.

Decisions about which datasets to display, which end-points (i.e., URL patterns) display which resources, how resources are displayed, and other design choices are all encoded in the LDA configuration file. The LDA specification describes in detail what goes in a configuration file. The configuration file itself uses RDF to encode these configuration choices, and is typically written in the Turtle syntax, as it is relatively readable and compact. Elda comes with various pre-built examples which may help you to get started with building your own specs. Ultimately, it is the configuration file which specifies how Elda URLs are turned into queries against the underlying store, and how the results of those queries are presented back to your users.

The cribsheet gives a terse overview of the meaning of the LDA query parameters and configuration properties.

Summary of LDA capabilities

Tutorial

We will now work through some of Elda's capabilities in slightly more detail. See the reference page for more comprehensive and detailed descriptions.

Prerequisites

Elda is written in Java (using the Jena RDF toolkit), so you will need Java installed on your system.

The default demonstration setup for Elda has examples that use the data.gov.uk data accessible from the SPARQL endpoint http://education.data.gov.uk/sparql/education/query. To run those examples, you will need to have open web access.

Downloading and starting Elda

There are two ways to get Elda: either by downloading the pre-compiled runnable demo .jar file, or by checking out the source code from its GitHub project and then compiling the Java source.

The runnable .jar can be downloaded from http://repository.epimorphics.com/com/epimorphics/lda/elda-standalone and following through to a recent version, or the version current for this page: elda-standalone-1.2.35.jar .

If you want to explore the Elda code and have git installed, you can copy the Elda repository:

git clone https://github.com/epimorphics/elda.git

To compile the code, you will also need Apache Maven:

mvn clean package

After compiling, the runnable .jar file will be in ./elda-standalone/target/elda-standalone.war. Alternatively, you can start the Jetty web server that is supplied with Elda by running the following command from the elda-standalone sub-directory:

java -jar start.jar

If you can't use port 8080

Your computer may already be using port 8080 for some local service. In that case, you can start Elda from the command line (this wont' work when double-clicking in a file manager) with:

java -jar standalone.jar -Djetty.port=NNNN
or, if you're starting from the unzipped Elda directory,
java -Djetty.port=NNNN -jar start.jar

where NNNN is the port of your choice. Note: the -D comes after standalone.jar, but before start.jar.

To change the port number without having to supply a -Djetty.port command line option every time, in the Elda directory edit the configuration file etc/jetty.xml and change the line:

<Set name="port"><SystemProperty name="jetty.port" default="8080"/></Set>

to:

<Set name="port"><SystemProperty name="jetty.port" default="NNNN"/></Set>

where NNNN is the port number of your choice.

Built-in example datasets and configurations

Elda comes pre-packaged with some example configurations and an example dataset. The sample URLs in the table below should all work if you have Elda running on your local computer, on port 8080:

description config file sample URLs
one-template games example, local SPARQL endpoint. hello-world.ttl
two-template games example, local SPARQL endpoint. hello-again-world.ttl
one-template education example, external SPARQL endpoint. tiny-education.ttl
multi-template education example, external SPARQL endpoint. mini-education.ttl
full education example, external SPARQL endpoint. full-education.ttl
...
old education example [for comparison], external SPARQ endpoint. old-education.ttl

Games example -- web page

Let's look a little at the two-template games example, standalone/again.

(Refer to the cribsheet for a summary of the action of Elda's query parameters.)

The page http://localhost:8080/standalone/again/games shows us the properties (as in the example data file) of several boardgames. This HTML view allows you to explore the dataset. For example, A Brief History of the World has publication date 2009. Clicking the magnifying-glass icon on that line restricts the results to only those with that publication date -- as it happens, no others. And we see (from the URL bar) that the URL of this page has had a publicationDate=2009 query parameter added.

Going back and clicking the less-than sign shows instead will show games whose publication date is the same as, or less recent than, A Brief History of the World. Similarly, going back and clicking the greater-than sign will show games no older than A Brief History of the World. In both cases, the URL changes to show the applied filter, which also appears in the Filter box in the column on the right.

Similarly you can play with the value of players, eg clicking on the magnifying class for players 4 will restrict the display to only games that have a 4-player option. And, of course, you can apply two (or more) filters at once.

In the right-hand column, the Sortby box contains the names of the properties that are displayed. Clicking on an arrow will change the order of the items by sorting according to the value of the predicate: the default is to sort by the label of the item, but you could choose publication date or designed by, or both together. players, being multi-valued, isn't really a good sorting candidate.

Games example -- configuration

We'll talk briefly through the LDA specification used for the games example.

#
# A hello-world config.
#

# Assorted prefix declarations. Some of them are for the structuring
# of the API config, others are for the vocabulary definitions.
#

@prefix api:    <http://purl.org/linked-data/api/vocab#> .
@prefix dct:    <http://purl.org/dc/terms/> .

@prefix rdf:    <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs:   <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd:    <http://www.w3.org/2001/XMLSchema#> .

# The elda namespace/prefix is for Elda extensions to the LDA specification.
@prefix elda:   <http://www.epimorphics.com/vocabularies/lda#> .

# Prefix for example-local entities.
@prefix hello:  <http://localhost:8080/elda/vocabulary/>.

The prefixes declared here make the configuration more concise and are used in the result model from the LDA query.

# ---------------------------------------------------------------------
# API config

hello:hello-world-again a api:API
; rdfs:label "Hello World example #2 -- games"@en

hello:hello-world-again is declared as an API. The label is used as a title in /api-config.

# Name the SPARQL endpoint which supplies the data we present
; api:sparqlEndpoint <local:data/example-data.ttl>

The SPARQL endpoint for this API is a local file. (This is an Elda extension to the LDA for testing and demonstration purposes.)

; api:defaultViewer api:labelledDescribeViewer

The default view for this API is the built-in labelledDescribeViewer, which fetches all the properties of the item using a SPARQL DESCRIBE and also fetches the labels of all the resource values this finds.

; api:viewer [a api:Viewer; api:name "none"; api:properties ""]

This defines a new view called none which shows no properties at all. This can be useful as a starting-point when building a view on the URL using the query parameter _properties=.

; api:variable
  [ api:name "_resourceRoot"
  ; api:value "http://localhost:8080/standalone/lda-assets/"
  ]

The special variable _resourceRoot is used by Elda as the base URI for assets needed for the HTML rendering of results.

; api:endpoint
  hello:publishers, hello:games

These are two endpoints for this API, hello:games and hello:publishers.

; api:formatter
  [ a api:XsltFormatter
  ; api:name "html"
  ; api:mimeType "text/html; charset=utf-8"
  ; api:stylesheet "lda-assets/xslt/result-osm-trimmed.xsl"
  ]
  .

Elda's default HTML formatter is crude, so we define a new formatter for the name html which is an XSLT formatter producing UTF-8 endcoded text/html and using the stylesheet result-osm-trimmed.xsl.

# Endpoint definitions

hello:publishers a api:ListEndpoint
  ; rdfs:label "Publishers"
  ; api:uriTemplate "/publishers"
  ; api:selector [api:filter "type=Publisher"; api:sort "label"]
  ; api:defaultViewer api:labelledDescribeViewer
  .

This is the publishers endpoint. It will show only items of type hello:Publisher, sort them by their label (which will be the publisher name), and view them with the labelledDescribe viewer.

hello:games a api:ListEndpoint
  ; rdfs:label "Games"
  ; api:uriTemplate "/games"
  ; api:selector [api:filter "type=BoardGame"; api:sort "label"]
  ; api:defaultViewer api:labelledDescribeViewer
  .

Similarly, this is the games endpoint, selecting only items of type hello:BoardGame and sorting them by their label.

The rest of the configuration defines property and class shortnames and other important attributes. The resouces (classes and proeprties both) that are of interest are those of type rdf:Property, owl:ObjectProperty, owl:DatatypeProperty, rdfs:Class, and owl:Class.

hello:BoardGame a rdfs:Class
; rdfs:label "Board Game"
; api:label "BoardGame"
.

The class hello:BoardGame has shortname BoardGame, as defined by its api:label; this is what allows it to appear in the endpoint filter type=BoardGame.

hello:players a rdf:Property
; api:label "players"
; rdfs:range xsd:int
.

hello:players has shortname players, which is what allows you to use eg players as the name of a query parameter. Defining its range to be xsd:int means (eg) that the 2 in the query parameter players=2 is interpreted as an integer and not a string.

hello:Publisher a rdfs:Class
  ; api:label "Publisher"
  .

Similarly to BoardGame.

dct:publisher a rdf:Property
  ; api:label "publishes"
  .

Declares that the shortname of dct:publisher is publishes.

rdfs:label a rdf:Property
  ; api:multiValued true
  ; api:label "label"
  .

Declares that rdfs:label has shortname label and that it is always to be presented in the JSON rendering as having an array of label values, even if there's only one.

rdf:type a rdf:Property
  ; api:multiValued true
  ; rdfs:range rdfs:Class
  ; api:label "type"
  .

Declares that rdf:type has shortname type, should have its JSON-rendered values appear as an array, and has a range of rdfs:Class, which means that for a query parameter type=SPOO, SPOO is interpreted as being the shortname of some resource rather than a literal string.

hello:designed-by a rdf:Property
  ; api:label "designedBy"
  .

Declares that hello:designed-by has shortname designedBy. (Note that the HTML renderer shows property shortnamesin the display translated by turning camelCase like designedBy into space-separated words like designed by.)

hello:designer-of a rdf:Property
  ; api:label "designerOf"
  .

The shortname of hello:designer-of is designerOf.

hello:pubDate a rdf:Property
  ; api:label "publicationDate"
  ; rdfs:range xsd:integer
  .

And finally, the shortname of hello:pubDate is publicationDate and its value is interpreted as an integer.

That concludes our example LDA specification. For more details on LDA configurations, see the Linked Data API (LDA) and the Elda reference material. Also see the other API configurations mentioned above.

Using other LDA specifications

From the command line

To use different LDA specifications, use the system property elda.spec. Like the port number, it can be set as part of launching the elda jar or when launching the jetty start jar:

java -jar standalone.jar -Delda.spec=SPECS

or (in the Elda directory):

java -Delda.spec=SPECS -jar start.jar

where SPECS is one or more LDA specification files separated by commas.

If you use elda.spec, then Elda ignores the default specification (the education LDA) wired into it.

By editing web.xml

To change the specification used without having to use a -Delda.spec command line option every time, edit the Elda webapps/elda/WEB-INF/web.xml. Find the servlet configuration

<servlet>
  <servlet-name>loader-init</servlet-name>
  <servlet-class>com.epimorphics.lda.routing.Loader</servlet-class>
  <init-param>
    <param-name>com.epimorphics.api.initialSpecFile</param-name>
    <param-value>assorted specs here</param-value>
  </init-param>
  <load-on-startup>1</load-on-startup>
</servlet>

Replace the assorted specs here with the name of the LDA specification files you wish to load, separated by commas. Spaces and newlines are ignored. (For more explanation of the structure of the web.xml file, see the reference documentation).

Fancy HTML formatting using XSLT stylesheets

The default formatter supplied by Elda is a very simple HTML formatter showing the properties and their values of the selected items. Elda also ships with a renderer that uses XSLT (and Javascript at the client end) to produce pages with additional controls and a richer appearance. To use this as your html renderer, add:

; api:formatter
  [a api:XsltFormatter
  ; api:name 'html'
  ; api:stylesheet 'xslt/result-osm.xsl'
  ; api:mimeType 'text/html'
]

to your API root in your configuration file and arrange that the webapps/elda directory contents are served as static files.

Alternative data sources

Querying a local file

If the remote SPARQL endpoint is slow, not yet fully configured, or plain unimplemented, you might want to set up a local endpoint using a tool like Fuseki. But it's also possible for Elda to query a local RDF file.

Edit your spec file, which will look something like the education spec suplied with Elda:

spec:api
  a api:API ;
  rdfs:label "Edubase API"@en;
  api:maxPageSize 50;
  api:defaultPageSize 10 ;
  api:sparqlEndpoint <http://education.data.gov.uk/sparql/education/query> ;
  api:endpoint
   spec:schools
   , spec:schoolsPrimary
   , spec:schoolsSecondary
   , spec:schoolsPrimaryDistrict
   , spec:schoolsSecondaryDistrict
 .

Replace the endpoint URI with local:content-name, where content-name is the name of the RDF source you wish to query. When Elda issues queries to a local: endpoint, it loads (and remembers) the contents and queries those directly.

Usually the content-name is a file name. It is resolved against the webapps context path (ie the directory from which it serves files). If there is no such file, then the content-name is treated as a URL and its contents fetched. If that fails, then the content is searched for along the webapps classpath. In all of these cases, the fetched content is loaded into memory as an RDF model and all queries to the endpoint are answered by this model.

(The name-lookup functionality is supplied by the underlying Jena FileManager class; for more details, see the Jena documentation currently at openjena.org.)

Using a local TDB datasource [obsolescent]

As an alternative to setting up a local SPARQL endpoint, or using a local: file, you can instead use a local Jena TDB database. To do so you will need to modify the web.xml webapp configuration file and supply an additional init-param for the loader-init servlet. You can do this in two ways:

<init-param>
  <param-name>com.epimorphics.api.TDB-base-directory</param-name>
  <param-value>tdb-directory</param-value>
</init-param>

Replace tdb-directory with the path to your chosen TDB directory. Note that the path is relative to the webapps directory – your best choice is to use an absolute path.

Warning. If the directory does not contain any TDB files, TDB will create a new empty dataset in it. This is usually not what you want, since all queries will return no answers, so Elda will report an error during setup.

The alternative form:

<init-param>
  <param-name>com.epimorphics.api.dataStoreDirectory</param-name>
  <param-value>datastore-directory</param-value>
</init-param>

specifies datastore-directory as a directory containing a TDB directory named tdb. The same warnings as above apply. (This form exists because Elda can do limited LARQ indexing and in that case the datastore directory will have a larq subdirectory for the LARQ indexes.)

Having specified a TDB directory, you can now edit your spec's sparqlEndpoint declaration, which in the education example looks like:

spec:api
  a api:API ;
  rdfs:label "Edubase API"@en;
  api:maxPageSize 50;
  api:defaultPageSize 10 ;
  api:sparqlEndpoint <http://services.data.gov.uk/education/sparql> ;
  api:endpoint
   spec:schools
   , spec:schoolsPrimary
   , spec:schoolsSecondary
   , spec:schoolsPrimaryDistrict
   , spec:schoolsSecondaryDistrict
 .

Replace the services URI with tdb:model-name, where model-name is the name of your endpoint model inside the TDB store.

Notes

Feedback

Elda aims to provide a complete implementation of the Linked Data API. Problems with Elda should be reported to the linked data API discussion group (note: you will need a google account to use this group).

Current issues can be seen on the Elda issues list .