About this Manual

This manual is for Web developers who want to develop linked data applications using Callimachus. Those new to Callimachus should start by completing the Callimachus Developers Tutorial.

Callimachus is a highly scalable platform for creating and running data-driven websites. 3 Round Stones offers commercial support and private virtual cloud hosting for enterprises running Callimachus.

If you have not installed Callimachus yet, please follow the installation instructions in Getting Started with Callimachus.

Chapter 1. Callimachus Templates

Callimachus templates determine how RDF resources are created, viewed and edited and are based on HTML 5 plus RDFa. Templates are always associated with a Callimachus class.

Templates allow developers to use the Callimachus template language to manage data in web pages, scripts to make them interactive, styles to make them attractive, and named queries to do things such as summarize large amounts of data as google charts.

This provides a breakdown of the initial code for the three Callimachus template types.

NB: To improve efficiency during the code/test cycle for XHMTL pages, make sure to ahdere to the following practices: 1) Make sure JavaScript and CSS code are not embedded in XHTML files (JS and CSS should be in their own files). 2) Save the generated styles.css output into a new file and change the layout to use the pre-generated styles.css (instead of the dynamic one).

1.1. Resource Create Template

1.1.1. Description

A create template is an HTML 5 form that determines how RDF resources are created. Each create template is associated with a Callimachus class, and developers may script create templates by applying these patterns.

1.1.2. Initial create template code

Here is the default code generated for a new create template.

 1:<?xml version="1.0" encoding="UTF-8" ?>
 2:<html xmlns="http://www.w3.org/1999/xhtml"
 3:    xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
 4:    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 5:    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
 6:    xmlns:dcterms="http://purl.org/dc/terms/">
 7:<head>
 8:    <title>New Resource</title>
 9:</head>
10:<body>
11:    <div class="container">
12:        <hgroup class="page-header">
13:            <h1>New Resource</h1>
14:        </hgroup>
15:        <form role="form" method="POST" action="" enctype="text/turtle" resource="" typeof="" class="row"
16:                onsubmit="calli.submitTurtle(event,calli.slugify($('#label').val()))">
17:            <fieldset class="col-sm-4">
18:                <div class="form-group">
19:                    <label for="label">Label</label>
20:                    <input type="text" class="form-control" id="label" value="{rdfs:label}" required="required" autofocus="autofocus"
                           onchange="calli.updateProperty(event, 'rdfs:label')" />
21:                </div>
22:                <div class="form-group">
23:                    <label for="comment">Comment</label>
24:                    <textarea id="comment" class="form-control"
                           onchange="calli.updateProperty(event, 'rdfs:comment')">{rdfs:comment}</textarea>
25:                </div>
26:                <div class="form-group">
27:                    <button type="submit" class="btn btn-success">Create</button>
28:                </div>
29:            </fieldset>
30:        </form>
31:    </div>
32:</body>
33:</html>

1.1.3. Code Analysis

Lines Element Purpose
1 xml Specifies the character encoding to be UTF-8.
2-6 html element Declares the namespaces used to identify resources in this page.
8,13 title, h1 Contains placeholders for the name of the type of resources being created.
15 form HTML form that will update the RDF database when the user presses the submit button.
17-29 input field classes Placeholders for input fields.
27 button Create button submits the data.

1.2. Resource Edit Template

1.2.1. Description

An edit template is an HTML form and determines how resources from a Callimachus class are modified by the user. Each edit template is associated with a Callimachus class, and developers may script Edit templates by using these patterns and functions.

1.2.2. Initial edit template code

Here is the default code generated when a new edit template is created.

 1:<?xml version="1.0" encoding="UTF-8" ?>
 2:<html xmlns="http://www.w3.org/1999/xhtml"
 3:    xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
 4:    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 5:    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
 6:    xmlns:dcterms="http://purl.org/dc/terms/">
 7:<head>
 8:    <title resource="?this">{rdfs:label}</title>
 9:</head>
10:<body resource="?this" onload="comparison=calli.copyResourceData('#form')">
11:    <div class="container">
12:        <hgroup class="page-header">
13:            <h1 property="rdfs:label" />
14:        </hgroup>
15:        <form id="form" role="form" method="POST" action="" enctype="application/sparql-update" resource="?this" class="row"
                   onsubmit="calli.submitUpdate(comparison,event)">
16:            <fieldset class="col-sm-4">
17:                <div class="form-group">
18:                    <label for="label">Label</label>
19:                    <input type="text" class="form-control" id="label" value="{rdfs:label}" required="required"
                           onchange="calli.updateProperty(event, 'rdfs:label')" />
20:                </div>
21:                <div class="form-group">
22:                    <label for="comment">Comment</label>
23:                    <textarea id="comment" class="form-control"
                           onchange="calli.updateProperty(event, 'rdfs:comment')">{rdfs:comment}</textarea>
24:                </div>
25:                <div class="form-group">
26:                    <button type="submit" class="btn btn-primary">Save</button>
27:                    <button type="button" onclick="window.location.replace('?view')" class="btn btn-default">Cancel</button>
28:                    <button type="button" onclick="calli.deleteResource(event)" class="btn btn-danger">Delete</button>
29:                </div>
30:            </fieldset>
31:        </form>
32:    </div>
33:</body>
34:</html>

1.2.3. Code analysis

Lines Element Purpose
1 xml Specifies the character encoding to be UTF-8.
2-6 html Declares the namespaces used to identify resources in this page.
8 title Assigns the page title the label of the current resource.
10 body Sets the RDF subject for elements inside the body element.
13 h1 Displays the label of the current resource.
15 form Form used to update the RDF data for the current resource.
16-30 input fields Sample input fields.
26-28 buttons Buttons used to submit, cancel changes or delete the current resource.

1.3. Resource View Template

1.3.1. Description

A view template determines how resources from a Callimachus class are rendered for display. Each view template is associated with a Callimachus class, and developers may script view templates by applying these patterns.

1.3.2. Initial view template code

 1:<?xml version="1.0" encoding="UTF-8" ?>
 2:<html xmlns="http://www.w3.org/1999/xhtml"
 3:    xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
 4:    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 5:    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
 6:    xmlns:dcterms="http://purl.org/dc/terms/">
 7:<head>
 8:    <title resource="?this">{rdfs:label}</title>
 9:    <link rel="edit-form" href="?edit" />
10:    <link rel="comments" href="?discussion" />
11:    <link rel="version-history" href="?history" />
12:</head>
13:<body resource="?this">
14:    <div class="container">
15:        <div class="page-header">
16:            <h1 property="rdfs:label" />
17:        </div>
18:        <pre property="rdfs:comment" />
19:    </div>
20:</body>
21:</html>

1.3.3. Code Analysis

Lines Element Purpose
1 xml Specifies the character encoding to be UTF-8.
3-6 html Declares the namespaces used to identify resources in this page.
8 title Displays the name of the current resource.
9-11 link(s) Links for editing, describing and viewing the version history of the current resource.
13 body Sets the subject of the RDFa attributes contained in the body of the page.
16 h1 Displays the name of the resource being edited.
18 pre The content of the comment field, which may include wiki markup.

1.4. Named Query Template

1.4.1. Description

A named query template determines how query results from a Named Query are displayed. Each template is associated with a Named Query using the SPARQL comment # @view. When this comment is present in the query, the queries' view tab will return the markup in the template. The template can then use JavaScript to load the query results (shown below) or if the query has exactly one variable in the SELECT clause, the template can walk the graph from the results of that variable binding as described in View Templates for Named Queries.

1.4.2. Named Query code

# @view pie-chart.xhtml
PREFIX skos:<http://www.w3.org/2004/02/skos/core#>
PREFIX vcard:<http://www.w3.org/2006/vcard/ns#>
PREFIX directory:<http://dir.w3.org/rdf/2012/directory/>
SELECT ?label (count(distinct ?proj) as ?value) {
    ?proj directory:isOrganizationType [ skos:prefLabel ?label ]
} GROUP BY ?label ORDER BY desc(?value)

1.4.3. View template code


<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Pie Chart</title>
    <script src="https://www.google.com/jsapi" type="text/javascript"> </script>
    <script type="text/javascript">
        google.load("visualization", "1", {callback: function(){
            var chart = new google.visualization.ChartWrapper({
                dataSourceUrl:"?results",
                options:{"hasLabelsColumn":true,is3D:false,height:300},
                chartType:"PieChart"
            });
            chart.setContainerId("pie-chart");
            chart.draw();
        }});
    </script>
</head>
<body>
    <div class="container">
        <h1>Pie Chart</h1>
        <div id="pie-chart" class="chart" style="height:300px;width:400px"></div>
    </div>
</body>
</html>

Chapter 2. Callimachus Template Language

The Callimachus template language enables programmers to retrieve and manipulate RDF data stored in Callimachus.

2.1. Evaluation Context

Every element in a Callimachus template must have either a new subject or an inherited subject.

2.1.1. New Subject

As processing progresses, any @about or @resource attributes will change the current subject.

Below the body changes the current subject to the variable ?this.

<body resource="?this">
  <!-- Expressions and RDFa attribute in body will use the subject ?this. -->
</body>

If @about and @resource is not present, then @src and @href can also set the new subject of an element.

2.1.2. Inherited Subject

The usual way an inherited subject gets set is when a parent element has the attribute @resource.

<body resource="?this">
  <ul>
    <li rel="foaf:knows" resource="?friend">
      <!-- Within this element the current subject is ?friend. -->
    </li>
  </ul>
</body>

The attribute @href and @src can also change the inherited subject.

<body resource="?this">
  <ul>
    <li rel="foaf:knows" resource="?friend">
      <a rel="foaf:img" href="?img">
        <!-- Within this element the current subject is ?img. -->
      </a>
    </li>
  </ul>
</body>

2.2. Variables

Variables are referenced using a '?' followed by a name, such as ?this or ?myObject. The variable ?this is bound to the resource being rendered for view and edit templates.

Variables can be declared using RDFa attributes, such as @about and @resource. Once variables are declared, they can be used

  • within the current element

  • in nested elements

  • in RDFa attributes, or

  • in Callimachus expressions.

2.2.1. Using variables

Variables can be used in the RDFa attributes  @about, @content, and @resource to declare a new variable, or to reference a variable declared in a parent element.

Variables can also be used in the  @href and @src attributes if they are used on an element that also contains a @rel, @rev, or @property attribute.

2.3. Expressions

Callimachus expressions can be placed in attributes or between elements (i.e. text nodes). Expression types may be variable, property paths or literal, as described below.

2.3.1. Variable Expressions

A variable wrapped in curly brackets will either be replaced with the bound variable value or removed. In the example below, the bound value to the variable ?this is substituted for {?this}.

Properties that are not present in the RDF store will result in an empty string in the resulting HTML page.  Thus, use of the curly bracket syntax may result in empty tags or attributes.  For example, this is always expected to succeed since the ?this variable should always exist:

<body resource="?this">
  <p>The URI of this resource is {?this}.</p>
</body>

However, the use of a property in tag contents or some tag attributes (such @src) might result in an empty tag when the property is not present in the RDF store.  So:


<h1>{rdfs:label}</h1>

could become:


<h1></h1>

in the generated HTML if the property rdfs:label does not exist in the RDF store.  The possibility of empty tags could become significant, as with image tags when a property is used in the src attribute because some browsers (e.g. Firefox version 29) will display an empty image tag as a broken image.  Therefore, one might prefer to replace the use of curly brackets:


<img src="{foaf:depiction}" />  # An anti-pattern.  Do not use!

with:


<img rel="foaf:depiction" src="?depiction" />

to avoid the creation of an empty tag.

2.3.2. Property Path Expressions

A CURIE SPARQL property path wrapped in curly brackets will be replaced with the property path object value from the RDF store for the current subject. In the example below the expression has the subject of ?this and a predicate of rdfs:label. The object of matching triples from the RDF store will be substituted for the expression {rdfs:label|foaf:name}.

<head>
  <title resource="?this">{rdfs:label|foaf:name}</title>
</head>

More information about the property path syntax can be found in the SPARQL 1.1 Query Language Recommendation.

2.3.3. Literal Expressions

Quoted strings wrapped in curly brackets will be replaced with the literal string within.

This code:

<p>The expression {'{rdfs:label}'} is often used to refer to resources.</p>

Would produce:

<p>The expression {rdfs:label} is often used to refer to resources.</p>

2.4. Loops

Callimachus can only loop over properties and relationships present in the RDF store.

Any element with the @property attribute will be repeated (or not shown at all) for every matching property value in the RDF store.

<body resource="?this">
  <h2>List of values for the current resource</h2>
  <ul>
    <li property="rdf:value" content="?value">
      <!-- this li element may be repeated -->
    </li>
  </ul>
</body>

Any element with @rel or @rev attribute and a @resource attribute will be repeated (or not shown at all) for every matching relationship partner in the RDF store.

<body resource="?this">
  <h2>List of friends for the current resource</h2>
  <ul>
    <li rel="foaf:knows" resource="?friend">
      <!-- this li element may be repeated -->
    </li>
  </ul>
</body>

Chapter 3. Patterns for Scripting Edit and Create Templates

This describes software patterns you can use when developing your Edit and Create templates.

3.1. Input Patterns

3.1.1. Overview

In this part we will explore patterns for handling the following kinds of user input:

3.1.2. Single Text Input

Intent

To allow the user to input at most one value for a property.

Motivation

Restricting the number of property values the form can be more effective, reduce complexity and reduce user distractions.

Applicability

Use for functional property values.

Implementation

Assign the value a property expression, and include a datatype attribute if needed. The onchange attribute will ensure the RDFa attributes are setup correctly before the form is parsed. The CURIE in the expression must match the CURIE passed to the calli.updateProperty function.

Sample Code

<?xml version="1.0" encoding="UTF-8" ?>
<html xmlns="http://www.w3.org/1999/xhtml"
   xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
   xmlns:foaf="http://xmlns.com/foaf/0.1/"
   xmlns:dcterms="http://purl.org/dc/terms/"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema#">
  <head><title resource="?this">{foaf:name}</title></head>
  <body resource="?this" onload="comparison=calli.copyResourceData('#form')">
    <div class="container"
      <form id="form" method="POST" action="" enctype="application/sparql-update" resource="?this" typeof="foaf:Person" class="row"
            onsubmit="calli.submitUpdate(comparison,event)">
         <fieldset class="col-sm-4">
            <div class="form-group">
               <label for="name">Name</label>
               <input type="text" id="name" value="{foaf:name}" class="form-control" required="required"
                   onchange="calli.updateProperty(event,'foaf:name')" />
            </div>
            <div class="form-group">
               <label for="date">Date</label>
               <input id="date" type="date" datatype="xsd:date" value="{dcterms:date}" class="form-control"
                   onchange="calli.updateProperty(event,'dcterms:date')" />
            </div>
            <div class="form-group">
               <label for="comment" class="control-label">Comment</label>
               <textarea id="comment" class="form-control"
                   onchange="calli.updateProperty(event,'rdfs:comment')">{rdfs:comment}</textarea>
            </div>
            <div class="form-group">
               <button id="save" type="submit" class="btn btn-primary">Save</button>
               <button id="cancel" type="button" onclick="location.replace('?view')" class="btn btn-default">Cancel</button>
               <button id="delete" type="button" onclick="calli.deleteResource(event)" class="btn btn-danger">Delete</button>
            </div>
         </fieldset>
      </form>
    </div>
  </body>
</html>

3.1.3. Multiple Text Input

Intent

Allow the user to input zero or more values for a property.

Motivation

Callimachus provides JavaScript functions to add multiple property values.

Applicability

Use for non-functional property values, such as keywords or alternate labels.

Implementation

Use the calli.addResource(event) function to add more input boxes with @property.

Sample Code

<?xml version="1.0" encoding="UTF-8" ?>
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
  xmlns:foaf="http://xmlns.com/foaf/0.1/"
  xmlns:dcterms="http://purl.org/dc/terms/"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
  xmlns:skos="http://www.w3.org/2004/02/skos/core#">
<head><title resource="?this">{skos:prefLabel}</title></head>
<body resource="?this" onload="comparison=calli.copyResourceData('#form')">
  <div class="container">
     <form id="form" method="POST" action="" enctype="application/sparql-update" resource="?this" typeof="skos:Concept" class="row"
          onsubmit="calli.submitUpdate(comparison,event)">
       <fieldset class="col-sm-4">
          <div class="form-group">
             <label for="label">Label</label>
             <input type="text" id="label" value="{skos:prefLabel}" class="form-control" required="required"
                 onchange="calli.updateProperty(event, 'rdfs:label')" />
          </div>

          <div class="form-group">
             <label for="altLabel">Alternate label</label>
             <div>
                <input type="text" id="altLabel" property="skos:altLabel" content="?alt" value="{?alt}" class="form-control"
                    onchange="calli.updateProperty(event, 'skos:altLabel')" />
                <a href="javascript:void(0)" title="More" onclick="calli.addResource(event)" class="glyphicon glyphicon-plus" />
             </div>
          </div>
          <div class="form-group">
             <button id="save" type="submit" class="btn btn-primary">Save</button>
             <button id="cancel" type="button" onclick="location.replace('?view')" class="btn btn-default">Cancel</button>
             <button id="delete" type="button" onclick="calli.deleteResource(event)" class="btn btn-danger">Delete</button>
          </div>
       </fieldset>
    </form>
  </body>
</html>

3.2. Manipulation Patterns

3.2.1. Overview

In this part we will explore the following two patterns for creating and editing resources:

3.2.2. Class Instance Create

Intent

To create a new resource associated with Callimachus templates, through a Callimachus class.

Motivation

In addition to exploring and viewing existing resources, the application may allow a user to add additional resources. For example, in a workflow-based application the user may need to be able to create new tasks.

Applicability

Use this where the class of resource is known. The class definition provides a starting point for deciding which properties should be included in the creation form. However, the actual choice of properties is determined by the developer.

Implementation

The create template enables the creation of a new instance of a creatable class. The properties in the form are not determined by the class definition so the developer is free to leave out or add new properties as appropriate (e.g. the use of an rdfs:label may not be mandated by the class definition).

Security

By default, the create operation is restricted to authorized users. To enable this for users of the admin group we add the admin group as a calli:author for the class. Add other user groups as appropriate.

Sample Code

Defines a new Callimachus class specific for resources created locally. Make this a subclass of the more general foaf:Person. The resulting resource will have both the Callimachus class type and any types in the typeof attribute of the form. Within the Class, assign a new create template.

The RDFa create template allows the user to initialise the new resource. The resource is assigned a URL based on the input label. The label is first converted to a lower-case uri-safe format.


<?xml version="1.0" encoding="UTF-8" ?>
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
    xmlns:foaf="http://xmlns.com/foaf/0.1/">
<head>
   <title>New Person</title>
</head>
<body>
   <div class="container">
      <form id="form" method="POST" action="" enctype="text/turtle" typeof="foaf:Person" class="row"
             onsubmit="calli.submitTurtle(event,call.slugify($('#name').val()))">
          <fieldset class="col-sm-4">
              <div class="form-group">
                   <label for="name">Name</label>
                   <input type="text" id="name" value="{foaf:name}" required="required" class="form-control"
                       onchange="calli.updateProperty(event, 'foaf:name')" />
              </div>
              <div class="form-group">
                   <label for="comment">Comment</label>
                   <textarea id="comment" class="form-control"
                        onchange="calli.updateProperty(event, 'rdfs:comment')">{rdfs:comment}</textarea>
              </div>
              <div class="form-group">
                   <button id="create" type="submit" class="btn btn-success">Create</button>
              </div>
          </fieldset>
      </form>
   </div>
</body>
</html>

3.2.3. Class Instance Edit

Intent

To update the properties of an existing resource.

Motivation

Based on the known class of a resource we can create an edit page that enables the user to edit those properties and submit these changes.

Applicability

Use this pattern where the values of an RDF resource can be directly updated by the user.

Implementation

The editing view may be accessed by appending ?edit to the URL of the resource (as long as it is an instance of an editable class). In addition, the 'Edit' tab can be used from the view page.

Sample Code

Define an edit template for a Callimachus Class. The template uses the predefined validation rule required="required" that should be used on mandatory inputs.

The RDFa template person-edit.xhtml displays the current values for the form entries and submits the the list of RDF updates on form submission.


<?xml version="1.0" encoding="UTF-8" ?>
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
    xmlns:foaf="http://xmlns.com/foaf/0.1/">
<head><title resource="?this">{foaf:name}</title></head>
<body resource="?this" onload="comparison=calli.copyResourceData('#form')">
   <div class="container">
      <hgroup class="page-header">
         <h1 property="foaf:name" />
      </hgroup>
      <form id="form" method="POST" action="" enctype="application/sparql-update" resource="?this" typeof="foaf:Person" class="row"
             onsubmit="calli.submitUpdate(comparison,event)">
         <fieldset class="col-sm-4">
             <div class="form-group">
                 <label for="name">Name</label>
                 <input type="text" id="name" value="{foaf:name}" class="form-control" required="required"
                     onchange="calli.updateProperty(event, 'foaf:name')" />
             </div>
             <div class="form-group">
                  <label for="comment">Comment</label>
                  <textarea id="comment" class="form-control"
                      onchange="calli.updateProperty(event, 'rdfs:comment')">{rdfs:comment}</textarea>
             </div>
             <div class="form-group">
                  <button id="save" type="submit" class="btn btn-primary">Save</button>
                  <button id="cancel" type="button" onclick="location.replace('?view')" class="btn btn-default">Cancel</button>
             </div>
         </fieldset>
      </form>
   </div>
</body>
</html>

The following sample extends person-edit.xhtml adding the ability to delete the resource. The javascript adds a click handler to the delete button that calls calli.deleteResource(event) on confirmation.


<?xml version="1.0" encoding="UTF-8" ?>
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
   xmlns:foaf="http://xmlns.com/foaf/0.1/">
<head><title resource="?this">{foaf:name}</title></head>
<body resource="?this" onload="comparison=calli.copyResourceData('#form')">
   <div class="container">
      <hgroup class="page-header">
         <h1 property="foaf:name" />
      </hgroup>
      <form id="form" method="POST" action="" enctype="application/sparql-update" resource="?this" typeof="foaf:Person" class="row"
             onsubmit="calli.submitUpdate(comparison,event)">
         <fieldset class="col-sm-4">
             <div class="form-group">
                 <label for="name">Name</label>
                 <input type="text" id="name" value="{foaf:name}" class="form-control" required="required"
                     onchange="calli.updateProperty(event, 'foaf:name')" />
             </div>
             <div class="form-group">
                  <label for="comment">Comment</label>
                  <textarea id="comment" class="form-control"
                      onchange="calli.updateProperty(event, 'rdfs:comment')">{rdfs:comment}</textarea>
             </div>
             <div class="form-group">
                  <button id="save" type="submit" class="btn btn-primary">Save</button>
                  <button id="cancel" type="button" onclick="location.replace('?view')" class="btn btn-default">Cancel</button>
                  <button id="delete" type="button" onclick="calli.deleteResource(event)" class="btn btn-danger">Delete</button>
             </div>
         </fieldset>
      </form>
   </div>
</body>
</html>

3.3. Selection Patterns

3.3.1. Overview

In this chapter we will explore four patterns for making data selection easier:

3.3.2. Large Hierarchical Selection

Intent

To choose from a large set of finite possible concepts.

Motivation

When categorizing resources the number of categorizes is often too large for a flat list and requires the ability to browse through possible concepts.

Applicability

Use for object relationships that have a large set of finite possible objects.

Implementation

Create a single top concept with skos:narrower and skos:related of the hierarchical concepts that are valid objects for this relationship. The user will be able to navigate among the concepts using broader and narrower relationships. When the user navigates to the concept they want they can click the select button.

Sample Code

<div id="medium" class="form-group" ondrop="calli.insertResource(event)">
 <label>Medium <a href="/scheme/medimus/top" title="Browse Mediums"
     onclick="calli.selectResource(event)" class="glyphicon glyphicon-folder-open" /></label>
  <div rel="dcterms:medium">
   <span resource="?medium" typeof="skos:Concept" class="label label-info">
     <span property="skos:prefLabel" />
     <a href="{?medium}" title="Remove relationship" onclick="calli.removeResource(event)" class="glyphicon glyphicon-remove" />
   </span>
 </div>
</div>

3.3.3. Limited Selection

Intent

To provide the user with a small set of possible relations to choose from.

Motivation

Some relationships are limited to small set of target objects, that are curated separately. For this it is important to provide the user with a list of possible selections inline.

Applicability

Use when the number of possible target objects in a relationship is limited, doesn't change often, and can be shown to the user all together.

Implementation

Create a folder containing the concepts that should be presented to the user. Use the calli:hasComponent relationship from the folder to the concepts in an RDF Named Query to select the possible set.

Within an edit template page, add XInclude directive of the ?radio pragma as shown below.

Sample Code

# mediums-list.rq
PREFIX skos:<http://www.w3.org/2004/02/skos/core#>
PREFIX calli:<http://callimachusproject.org/rdf/2009/framework#>

SELECT ?concept ?label {
    </scheme/mediums/> calli:hasComponent ?concept .
    ?concept skos:prefLabel ?label
} ORDER BY ?label

Horizontal radio buttons are best used when the relationship is functional (only one object) and the concepts can be listed in a single line.


<div xmlns:dcterms="http://purl.org/dc/terms/" class="form-group">
  <label>Medium</label>
  <xi:include href="mediums-list.rq?radio&amp;rel=dcterms:medium&amp;name=medium&amp;id=medium" />
  <div rel="dcterms:medium" resource="?medium" />
  <script type="text/javascript">
    $('div[rel="dcterms:medium"]').filter(calli.checkEachResourceIn('#medium')).remove();
  </script>
</div>

Horizontal checkboxes are best used when the relationship is non-functional (can have multiple objects) and the concepts can be listed in a single line.


<div xmlns:dcterms="http://purl.org/dc/terms/" class="form-group">
  <label>Medium</label>
  <xi:include href="mediums-list.rq?checkbox-inline&amp;rel=dcterms:medium&amp;name=medium&amp;id=medium" />
  <div rel="dcterms:medium" resource="?medium" />
  <script type="text/javascript">
    $('div[rel="dcterms:medium"]').filter(calli.checkEachResourceIn('#medium')).remove();
  </script>
</div>

Vertical checkboxes is best used when the relationship is non-functional (can have multiple objects) and all concepts should visible to the user at once.


<div xmlns:dcterms="http://purl.org/dc/terms/" class="form-group">
  <label>Medium</label>
  <xi:include href="mediums-list.rq?checkbox&amp;rel=dcterms:medium&amp;name=medium&amp;id=medium" />
  <div rel="dcterms:medium" resource="?medium" />
  <script type="text/javascript">
    $('div[rel="dcterms:medium"]').filter(calli.checkEachResourceIn('#medium')).remove();
  </script>
</div>

3.3.4. Range Relationships

Intent

Allow the user to lookup or create resources by type.

Motivation

Many relationships between resources are open ended, requiring only particular resource types. The user may link to a large possible set of objects or create a new one.

Applicability

Use for object relationships that have a open ended set of possible objects.

Implementation

Use the selectize.js library, integrated into Callimachus, to create an auto-complete input. The @rel/@resource will be used to populate existing entries in edit forms, while the calli.updateResource call will establish the relationship for new entries. Create an RDF Named Query to search for existing resource. Use the function calli.createResource to create new resources in a modal dialogue.

Sample Code

<div class="form-group">
  <label>Knows</label>
  <select id="knows" class="form-control" multiple="multiple"
      onchange="calli.updateResource(event,'foaf:knows')">
    <option selected="selected" rel="foaf:knows" resource="?knows" value="{?knows}">{foaf:name}</option>
  </select>
</div>

# person-search.rq
PREFIX foaf:<http://xmlns.com/foaf/0.1/>

SELECT ?resource ?label {
    ?resource a foaf:Person; foaf:name ?label
    FILTER regex(?label, "$q")
} ORDER BY ?label LIMIT 100

$('#knows').selectize({
    load: function(query, callback) {
        if (!query) return callback();
        var url = 'person-search.rq?results&tqx=out:sparql-json&q=' + encodeURIComponent(query));
        calli.getJSON(url).then(function(json){
            return json.results.bindings.map(function(bindings){
                return {
                    value: bindings.resource.value,
                    text: bindings.label.value
                };
            });
        }).then(callback, function(error){
            callback();
            return calli.error(error);
        });
    },
    create: function(label, callback) {
        calli.headText(calli.slugify(label)).then(function(){
            return calli.slugify(label); // already exists
        }, function(xhr) {
            if (xhr.status != 404) return calli.reject(xhr);
            return calli.createResource('#knows', './?create=Person');
        }).then(function(resource){
            return resource && {
                value: resource,
                text: resource.replace(/.*\//,'')
            };
        }).then(callback, function(error){
            callback();
            return calli.error(error);
        });
    }
});

You may need to change the path of person-search.rq and the Person class to match your folder structure.

3.3.5. Scroll Through Selection

Intent

To provide the user with a limited set of possible relations to choose from.

Motivation

Some relationships are limited to a set of target objects, that are curated separately. For this it is important to provide the user with a list of possible selections to choose from.

Applicability

Use when the number of possible target objects in a relationship is limited and small enough that the user can scroll quickly through all of them.

Implementation

Create a folder containing the enumerated concepts that should be presented to the user. Use the calli:hasComponent relationship from the folder to the concepts to link all possible relationships.

Within a edit template page, add one of the following markup patterns.

Sample Code

# mediums-list.rq
PREFIX skos:<http://www.w3.org/2004/02/skos/core#>
PREFIX calli:<http://callimachusproject.org/rdf/2009/framework#>

SELECT ?concept ?label {
    </scheme/mediums/> calli:hasComponent ?concept .
    ?concept skos:prefLabel ?label
} ORDER BY ?label

Drop down list is best used when the relationship is functional (only one object) and the list of concepts should be hidden by default.


<div xmlns:dcterms="http://purl.org/dc/terms/" class="form-group">
  <label for="medium">Medium</label>
  <xi:include href="mediums-list.rq?select&amp;rel=dcterms:medium&amp;id=medium" />
  <div rel="dcterms:medium" resource="?medium" />
  <script type="text/javascript">
    $('div[rel="dcterms:medium"]').filter(calli.selectEachResourceIn('#medium')).remove();
</div>

Select box is best used when the relationship is non-functional (can have multiple objects) and the user should be able to scroll through the list of concepts.


<div xmlns:dcterms="http://purl.org/dc/terms/" class="form-group">
  <label for="medium">Medium</label>
  <xi:include href="mediums-list.rq?select&amp;rel=dcterms:medium&amp;id=medium&amp;multiple=multiple" />
  <div rel="dcterms:medium" resource="?medium" />
  <script type="text/javascript">
    $('div[rel="dcterms:medium"]').filter(calli.selectEachResourceIn('#medium')).remove();
</div>


Chapter 4. Patterns for Scripting View Templates

This describes software patterns you can use when scripting view templates.

4.1. Display Patterns

4.1.1. Overview

Here we will explore four patterns that can help visualize data using View templates:

4.1.2. Class Instance View

Intent

This is the simplest kind of view where we wish to display the properties of a resource, an instance of known class. The resource is represented in an RDF structure.

Motivation

To present a customised view of a resource based on a known class. The view template of the class includes properties that we would expect to see in the view page of the resource.

Applicability

Consider using this pattern where the resource is represented as RDF metadata with literal and object properties. The structure may be browsed using the Callimachus triple browser, but it is more convenient to present the user with a customised view based on the class.

Implementation

Create a Callimachus Class that is either linked from the resource through an rdf:type relationship or create the Class as an equivalent of a owl:Class linked from the resource through an rdf:type relationship.

The class instance is the task resource denoted by ?this in both the title and the body with the template. For this example, we assume that the resource has both literal (rdfs:comment) and object properties; object properties may be displayed inline, nested within the current page, or they may translate into links to other view pages. Examples of each are shown below. Additionally, Callimachus provide formatting functions, such as the pre-formatted comment field may contain Creole wiki markup.

Sample Code

The RDFa template my-class.xhtml contains the following XHTML code. We assume the primary class instance has rdfs:label, rdfs:comment, and dcterms:created; it has two object properties dcterms:hasPart and dcterms:relation; the object of each has an rdfs:label.

The function calli.parseCreole is used to formatted the wiki text and calli.parseDateTime is used to parse the datetime into a Date object for formatting.

<html xmlns="http://www.w3.org/1999/xhtml"
   xmlns:xi="http://www.w3.org/2001/XInclude"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
   xmlns:dcterms="http://purl.org/dc/terms/"
   xmlns:dbpedia-owl="http://dbpedia.org/ontology/">
<head>
   <title resource="?this">{rdfs:label}</title>
</head>
<body resource="?this">
   <div class="container">
     <h1 property="rdfs:label" />

     <pre property="rdfs:comment" />
     <script type="text/javascript">
       $('p[property="rdfs:comment"]').replaceWith(calli.parseCreole);
    </script>

    <p>Created on <time id="created" datetime="{dcterms:created}" />.</p>
    <script type="text/javascript">
      $('#created').text(calli.parseDateTime("{dcterms:created}").toLocaleString());
    </script>

    <ul>
       <!-- inline object relationship -->
       <li rel="dcterms:hasPart" resource="?part">
          <span property="rdfs:label" />
       </li>
    </ul>

     <!-- out-of-line, hyper-linked relationship -->
     <div rel="dcterms:relation" resource="?resource2">
        <a href="?resource2" property="rdfs:label" />
     </div>

     <!-- out-of-line, reverse hyper-linked relationship -->
     <div rev="dcterms:relation" resource="?resource3">
        <a href="?resource3" property="rdfs:label" />
     </div>

     <!-- use of a property in an image tag -->
     <div rel="dbpedia-owl:thumbnail" resource="?thumbnail">
       <img src="?thumbnail" style="border:1px solid black;" align="left" hspace="10" vspace="10" />
     </div>
   </div>
</body>
</html>

4.1.3. Class Membership View

Intent

To list members of a class, rather than a specific instance.

Motivation

In many applications we need to view a set of resources in order to select the specific resource we are interested in.

Applicability

Use this pattern where members of a class are to be displayed. Where membership is conditional it is possible to test for the existence of a property/value, but not for more complex filters.

Implementation

Rather than using a class view template to display a single resource, you must use a query view template to display a set of resources.

Sample Code
# my-class-membership.rq
#
# @view my-class-membership.xhtml
#
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX eg: <http://example.com#>
SELECT ?member {
    ?member a eg:MyClass
}

The Named Query references a view template: my-class-membership.xhtml. The div element has no enclosing context so establishes a new subject of the indicated type. Consequently, the div is repeated for every member of MyClass. The link to my-class-membership.rq?results (the above named query) may be included in a menu or anywhere else a link may appear.

The file my-class-membership.xhtml contains a simple RDFa template that renders all members of MyClass and provides a link to each member.

<html xmlns="http://www.w3.org/1999/xhtml"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
   xmlns:eg="http://example.com#">
<head><title>Class Membership</title></head>
<body>
   <div class="container">
        <div resource="?member">
          <a href="?member" property="rdfs:label"></a>
        </div>
   </div>
</body>
</html>

4.2. Formatting Patterns

This describes four ways of formatting data in View templates:

4.2.1. Property List

Intent

Display multivalued property values in a meaningful way.

Motivation

Non-functional datatype property have unordered set of values that need to be shown in a organized view.

Applicability

This pattern applies when a property may have zero or more values and is non-functional.

Implementation

Properties can be shown in a view template vertically, in a list, or horizontally.

Sample Code

To list property values vertically use a div.


<?xml version="1.0" encoding="UTF-8" ?>
<html xmlns="http://www.w3.org/1999/xhtml"
   xmlns:xi="http://www.w3.org/2001/XInclude"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
   xmlns:skos="http://www.w3.org/2004/02/skos/core#">
<head>
   <title resource="?this">{rdfs:label}</title>
</head>
<body resource="?this">
   <div class="container">
     <h1 property="rdfs:label" />

     <div property="skos:altLabel" />
   </div>
</body>
</html>

To list property values in an unordered list use ul/li tags.


<?xml version="1.0" encoding="UTF-8" ?>
<html xmlns="http://www.w3.org/1999/xhtml"
   xmlns:xi="http://www.w3.org/2001/XInclude"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
   xmlns:skos="http://www.w3.org/2004/02/skos/core#">
<head>
   <title resource="?this">{rdfs:label}</title>
</head>
<body resource="?this">
   <div class="container">
     <h1 property="rdfs:label" />

     <ul>
       <li property="skos:altLabel" />
     </ul>
   </div>
</body>
</html>

To list all property values horizontally use span tags.


<?xml version="1.0" encoding="UTF-8" ?>
<html xmlns="http://www.w3.org/1999/xhtml"
   xmlns:xi="http://www.w3.org/2001/XInclude"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
   xmlns:skos="http://www.w3.org/2004/02/skos/core#">
<head>
   <title resource="?this">{rdfs:label}</title>
</head>
<body resource="?this">
   <div class="container">
     <h1 property="rdfs:label" />

     <span property="skos:altLabel" />
   </div>
</body>
</html>

4.2.2. Relationship List

Intent

Display multivalued object relationships in a meaningful way.

Motivation

Non-functional object relationships have unordered set of objects that need to be shown in a organized view.

Applicability

When a relationship may have zero or more values and is non-functional.

Implementation

Object links can be shown in a view template vertically, in a list, or horizontally. A link with an href attribute can be used to link the object in an HTML view page.

Sample Code

Relationships can also be listed vertically using divs.


<?xml version="1.0" encoding="UTF-8" ?>
<html xmlns="http://www.w3.org/1999/xhtml"
   xmlns:xi="http://www.w3.org/2001/XInclude"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
   xmlns:skos="http://www.w3.org/2004/02/skos/core#">
<head>
   <title resource="?this">{rdfs:label}</title>
</head>
<body resource="?this">
   <div class="container">
      <h1 property="rdfs:label" />

      <div rel="skos:topConcept" resource="?concept">
         <a href="?concept" property="skos:prefLabel" />
      </div>
   </div>
</body>
</html>

To list relationship objects in an unordered list use ul/li tags.


<?xml version="1.0" encoding="UTF-8" ?>
<html xmlns="http://www.w3.org/1999/xhtml"
   xmlns:xi="http://www.w3.org/2001/XInclude"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
   xmlns:skos="http://www.w3.org/2004/02/skos/core#">
<head>
   <title resource="?this">{rdfs:label}</title>
</head>
<body resource="?this">
   <div class="container">
     <h1 property="rdfs:label" />

     <ul>
       <li rel="skos:topConcept" resource="?concept">
         <a href="?concept" property="skos:prefLabel" />
       </li>
     </ul>
   </div>
</body>
</html>

Relationships can be listed horizontally (like properties above) using a span tag.


<?xml version="1.0" encoding="UTF-8" ?>
<html xmlns="http://www.w3.org/1999/xhtml"
   xmlns:xi="http://www.w3.org/2001/XInclude"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
   xmlns:skos="http://www.w3.org/2004/02/skos/core#">
<head>
    <title resource="?this">{rdfs:label}</title>
</head>
<body resource="?this">
   <div class="container">
       <h1 property="rdfs:label" />

       <span rel="skos:topConcept" resource="?concept">
           <a href="?concept" property="skos:altLabel" />
       </span>
   </div>
</body>
</html>

4.2.3. Sorted View

Intent

To display resources sorted by one or more properties

Motivation

Many resources need to be presented in a specific order:- Alphabetic order; date order; or in order of priority.

Applicability

Use this pattern where resources contain one or more properties that may be used to determine the order of presentation.

Implementation

This implementation uses the skos:member property to define the relationship between the subject, ?this, and it's ?members. The members are sorted in ascending order of their labels. The calli.compareElementsBy is used to sort the rows by their label in the a element.

Sample Code

<?xml version="1.0" encoding="UTF-8" ?>
<html xmlns="http://www.w3.org/1999/xhtml"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" xmlns:skos="http://www.w3.org/2004/02/skos/core#">
<head><title>Sorted View</title></head>
<body resource="?this">
   <div class="container">
      <table id="table" class="table">
         <tbody>
            <tr rel="skos:member" resource="?member">
               <td><a href="?member" property="rdfs:label" /></td>
            </tr>
         </tbody>
      </table>
      <script type="text/javascript">
          $('#table tbody tr').sort(calli.compareElementsBy('a')).appendTo('#table tbody');
      </script>
   </div>
</body>
</html>

4.2.4. Wiki Text

Intent

To display text property values using simple markup.

Motivation

Provide simple markup for text that can be easily read without prior knowledge of the markup syntax.

Applicability

Used for properties that may benefit from markup, but the markup will only be used in some of the property values.

Implementation

Display the property value in a pre tag with a CSS class of wiki. Callimachus will format the element using the Creole syntax on page load.

Sample Code

<?xml version="1.0" encoding="UTF-8" ?>
<html xmlns="http://www.w3.org/1999/xhtml"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#">
<head>
   <title resource="?this">{rdfs:label}</title>
</head>
<body resource="?this">
   <div class="container">
     <h1 property="rdfs:label" />

     <pre property="rdfs:comment" />

     <script type="text/javascript">
       $('pre[property="rdfs:comment"]').replaceWith(calli.parseCreole);
     </script>

   </div>
</body>
</html>

4.3. Navigation Patterns

4.3.1. Overview

Here we explore patterns that can help users navigate your Callimachus application.

4.3.2. Context Sensitive Menu

Intent

To provide a menu item that is tied to a specific web-page.

Motivation

Many web-based application need to provide links that are determined by the currently displayed page. This might be to upload or download specific information; to copy the current resource, etc.

Applicability

Use this pattern to define a menu that is defined in the context of a given page.

Implementation

Contextual menus are defined within the web-page itself in a sidebar. This can appear in the upper right-hand corner of the page.

Sample Code

Application metadata that defines this template must be defined as with other patterns. The template below defines a list of menu items of class "aside".


<?xml version="1.0" encoding="UTF-8" ?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
   <title>Title Here</title>
</head>
<body resource="?this">
   <div class="container">
      <div class="row">
         <div class="col-sm-8">
            <h1>Title Here</h1>
            <p>Rest of the page here</p>
         </div>
         <div class="col-sm-4">
            <aside class="well">
               <p><a href="?whatlinkshere">What links here</a></p>
               <p><a href="./?view">View container folder</a></p>
               <p><a href="?edit">Edit this resource</a></p>
            </aside>
         </div>
      </div>
   </body>
</html>


Chapter 5. Finding, Importing and Displaying Linked Data

This chapter provides a hands-on example showing how to find, import and display linked data in Callimachus. For the example, we are going to find and display linked data about the father of digital music synthesis - Wolfgang Palm.

5.1. Finding linked data

5.1.1. Sources of linked data

Image: Linked Open Data Project

The Linked Open Data Project provides tens of billions of RDF statements that are ready to use, with DBpedia at the center of the linked data cloud.

Other major sources include

5.1.2. Using DBpedia to get linked data

Follow these steps to get linked data from DBpedia. 

Step Action Example
1 Find the information you are looking for in Wikipedia. http://wikipedia.org/wiki/Wolfgang_Palm
2 Change the Wikipedia URL into a DBpedia URL as shown. http://dbpedia.org/resource/Wolfgang_Palm
3 Download the RDF/XML file (i.e. "Save link as"). http://dbpedia.org/data/Wolfgang_Palm.rdf

5.2. Importing linked data

Follow these steps to import linked data into Callimachus.

Step Action Example
1 Edit the URI(s) of the resources you want to host to be relative URIs. Change "http://dbpedia.org/resource/Wolfgang_Palm" to "Wolfgang_Palm"
2 Using the main menu navigate to the Home Folder and create a new folder for your data. Create a folder with the label "resource"
3 Open the new folder and using the upload file icon, next to the create menu. The modified Wolfgang_Palm.rdf is the linked data file you want to upload.
4 Upload the file. Result: A new graph document will be created in your folder. It will appear as "wolfgang_palm" in the folder listing, the .rdf file extension is not displayed in the folder view.

5.3. Displaying linked data

Follow these steps to display the linked data in Callimachus.

Step Action Example
1

Determine the type of the resource that you want to model.

Note: Use a class from a well-known vocabulary so the data will be easier to reuse. 

Wolfgang_Palm a rdf:type foaf:Person , yago:Person100007846 , yago:GermanMusicians .

2 Download the vocabulary as an RDF file. Save link as:  FOAF Vocabulary Specification
3 Upload the vocabulary RDF file into a Callimachus folder.

4 From the graph view select Explore OWL classes in this graph from the main menu.
5 Using the equivalent (assign templates) option, select the desired class to create a new Callimachus class In this case we are selecting for foaf:Person. When you create an eqivalent this class it will automatically fill in the Callimachus class name with the word Person.
6 Create a default view template and save the class. Result: You will now be able to view any RDF data that uses the foaf:Person class. Click on Class Resources from the main menu of the class to view data about Wolfgang Palm.

Chapter 6. Using Named Queries

In Callimachus Named Queries are SPARQL queries that are created using the Named Query create interface. In this chapter you will learn how to use named queries.

6.1. Named query syntax

Callimachus Named Queries use a superset of the SPARQL 1.1 query syntax SELECT form.

As in SPARQL, any prefixes used in the Named Query must be declared using a PREFIX clause. When evaluating, the base IRI of the query is the URI of the Named Query.

6.1.1. Sample named query

PREFIX foaf:    <http://xmlns.com/foaf/0.1/>
SELECT ?nameX ?nameY ?nickY
WHERE
  { ?x foaf:knows ?y ;
       foaf:name ?nameX .
    ?y foaf:name ?nameY .
    OPTIONAL { ?y foaf:nick ?nickY }
  }
OFFSET ${ ($pageNumber - 1) * $pageSize } LIMIT ${ $pageSize }

6.2. Parameters for named queries

Callimachus supports four ways of passing parameters to named queries: as wild parameters, relative pararmeters, lexical parameters, or expression parameters.

6.2.1. Wild parameters

Wild parameters use the SPARQL variable syntax with a prefix of '$', as shown in Example 1.

PREFIX foaf:    <http://xmlns.com/foaf/0.1/>
PREFIX dcterms: <http://purl.org/dc/terms/>
SELECT ?title {
  $doc a foaf:Document; dcterms:title ?title
}

Example 1: Named query that uses wild parameters

The value of the query parameters are any RDF term using the SPARQL term syntax. URIs are absolute or relative to the Named Query and wrapped in '<' and '>'. Literals maybe numeric or strings in double quotes and may include a language or datatype.

In Example 1, requests with the suffix ?results will return the title of all documents in the RDF store. This compares to requests with the suffix ?results&doc=%3Cdoc1%3E. These requests return document titles within the same namespace as the Named Query and a local part of "doc1".

Note: The %3C and %3E are percent encodings of '<' and '>'.

6.2.2. Relative parameters

Relative parameters must be bound and can only be a relative or absolute URI (i.e. not a literal value), as shown in Example 2.

PREFIX foaf:    <http://xmlns.com/foaf/0.1/>
PREFIX dcterms: <http://purl.org/dc/terms/>
SELECT ?title {
  <$doc> a foaf:Document; dcterms:title ?title
}

Example 2. Named query that uses relative parameters

In Example 2, requests with the suffix ?results will not return any results. However requests with the suffix ?results&doc=doc1 will retrieve the title of the <doc1> resource. The value of the query parameters are any relative or absolute URI (without angle brackets).

6.2.3. Lexical parameters

Lexical parameters must be bound and only be bound to literals, as shown in Example 3.

PREFIX foaf:    <http://xmlns.com/foaf/0.1/>
PREFIX dcterms: <http://purl.org/dc/terms/>
SELECT ?doc {
  ?doc a foaf:Document; dcterms:title "$title"@en
}

Example 3. Named query that uses lexical parameters

The datatype and language (if present) must be present in the Named Query itself and cannot be provided using lexical query parameters. As with relative parameters, a request using the suffix ?results will not return any results. However a request with the suffix ?results&title=Linking+Enterprise+Data will result in the document URI with an English title of "Linking enterprise Data"@en (if present in the RDF store). The value of the query parameters are any lexical value.

6.2.4. Expression parameters

Expression parameters are used to calculate the OFFSET and LIMIT for results, as shown in Example 4.

PREFIX foaf:    <http://xmlns.com/foaf/0.1/>
PREFIX dcterms: <http://purl.org/dc/terms/>
SELECT ?title {
  ?doc a foaf:Document; dcterms:title ?title
} OFFSET ${ ($pageNumber - 1) * $pageSize } LIMIT ${ $pageSize }

Example 4. Named query that uses expression parameters

Unlike other parameters, expression parameters must only have exactly one value per request. Expression parameters may contain any SPARQL expression of other (non-expression) parameters within a '${' and '}'. In this example, a request with the suffix ?results&pageNumber=1&pageSize=30 will result in a SPARQL with an OFFSET 0 and LIMIT 30.

Expression parameters have no name and do not appear in the query parameter. However, the parameters within an expression must be present in the query parameter.

6.3. Results from named queries

The results from named queries can be accessed using JavaScript in the following three ways.

6.3.1. Retrieving the results formatted as SPARQL results XML

To retrieve the results, send a GET request to the Named Query URI with the suffix ?results. This will return the tuple binding results in an XML document.

6.3.2. Retrieving the results formatted in HTML, CSV, TSV, or JSON

To retrieve the result in HTML, CSV, TSV, or JSON use the suffix: ?results&tqx=out:html , ?results&tqx=out:csv , ?results&tqx=out:tsv-excel, or ?results&tqx=out:table respectively.

All result formats comply with the GoogleChartToolsDatasourceProtocol.

6.3.3. Accessing the results from a Web browser

To access the result from a Web browser, use the google Query library to parse the result, as shown below.

  <script src="https://www.google.com/jsapi" type="text/javascript"> </script>
  <script type="text/javascript">
    // <![CDATA[
    google.load("visualization", "1.0", {callback:function() {
      new google.visualization.Query("organizations-by-country.rq?results").send(function(result){
        var select = $('#my-select');
        var data = result.getDataTable();
        var rows = data.getNumberOfRows();
        for (var i=0; i<rows; i++) {
          var option = $('<option/>');
          option.text(data.getValue(i, 0));
          select.append(option);
        }
      });
    }});
    // ]]>
  </script>

Take notice that this code relies on jQuery placing the results into an HTML element with an ID of "my-select". This ID can be whatever you want, but it must be present in the HTML for the jQuery to succeed. In this case, the HTML element that is necessary is:

<div id="my-select"> 
  ... 
</div>

6.4. View Templates for Named Queries

Callimachus supports the ability to assign a view template to a specific name query. It is quite a simple process and only requires two separate files: a query and a template. It does not matter which is created first but the two are dependent on each other, and thus both must exist to function correctly.

6.4.1. The Query

Queries that use view templates are not structured differently than queries that do not. The only difference is in a comment at the top of the query. In order to add a view template to a query, we add a comment with @view to include the relative filepath and name of the template we wish to apply.

#
# @Cache-Control: max-age=3600
# @view concept-search.xhtml
#
PREFIX skos:<http://www.w3.org/2004/02/skos/core#>

SELECT ?concept {
  ?concept a skos:Concept; skos:prefLabel ?label
  FILTER regex(?label, "$q", "i")
} ORDER BY ?concept LIMIT 10

Example 1: Named query that uses a view template

Be aware that once you have added a view template to a named query, when you hit the View tab it will no longer appear as a table of query results. It will now be rendered through the template. You can still edit the query itself by simply clicking the Edit tab.

6.4.2. The Template

The template behaves as any other Callimachus template does, relying on RDFa markup to "traverse" the graph and display the apporpriate data. For more information about templates see the full documentation. As you can see below by adding just a few attributes to existing html tags we are able to display the results of the query as if the query was  occuring within that page.

<?xml version="1.0" encoding="UTF-8" ?>
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
    xmlns:skos="http://www.w3.org/2004/02/skos/core#">
<head>
    <title>Concept Search Results</title>
    <link rel="edit-form" href="?edit" />
    <link rel="comments" href="?discussion" />
    <link rel="describedby" href="?describe" />
    <link rel="version-history" href="?history" />
</head>
<body>
    <h1>Concept Search Results</h1>
    <ul>
        <li resource="?concept">
            <a href="{?concept}">{skos:prefLabel}</a>
            <pre property="skos:definition" />
        </li>
    </ul>
</body>
</html>

Example 2. View template for named query

Above we have added a few crucial pieces of information to the existing HTML tags. Since this template is now associated with a named query (completed in the step above) the template is able to reference the variable in the SELECT clause of the query. As you can see, the resource attribute of the <li> is now connected to ?concept, the variable that was returned in the results of the named query. From here we are able to pick and choose the data we want to display and how to display it. An HTTP request to "concept-search.rq?view&q=sun" will include any concept with the regex "sun" in the pref label.

6.5. Chart Wizard

6.5.1. Overview

Callimachus' Chart Wizard exists to make visualizations of your data easy to explore, develop, and include in other documents. No JavaScript to write or frameworks to learn - the Chart Wizard provides a friendly user interface that allows you to create and customize a wide variety of charts and visualizations for any properly structured queries contained within Callimachus.

6.5.2. Interface

Visualizations are based on data and data is surfaced and organized via queries. For that reason, the Chart Editor is only available when you are on the ?view template for an existing query. Once there, the Chart Editor is opened by clicking the Main Menu (top right) in the top right of the screen and selecting "Edit visualization". 

At this point the Wizard is opened in a dialog box in front of whatever Named Query you were previously viewing. The dialog box is intentionally minimal to allow you to test multiple visualizations and see the results in real-time in the query view page. This allows for rapid iteration and testing of potential visualizations without having to compile or embed unsuccessful attempts. 

The Wizard is composed of two sections: the Visualization Selector and the Chart Options pane. 

Visualization Selector

When you select "Edit visualization" from the main menu the dialog box will appear. From here try selecting different visualizations and take notice of how the query view page (behind the dialog box) which was once a simple table, changes to reflect the selections made in the chart wizard.

Callimachus' chart wizard also offers the ability to create Google Charts via an integration of the Google Charts Editor. To see what options are available via Google Charts select "More... (Google Charts)" from the bottom of the menu to open the editor. Documentation on the Google Charts Editor is below.

Chart Options pane

Many of the Visualizations can be further customized once they are selected. For some visualizations, X and Y axes or label and value settings will need to be specified. Once the mandatory configuration is completed, many optional configurations exist. Attributes such as color, gradient scaling, and legends can be added with ease. Just as with changing visualization types, any changes to the attributes are reflected in the actual query view behind the chart wizard. Try out some of the different options and see what works best before saving the final product.

Here you can see we have taken a basic line chart and assigned the following configurations:

  • Assigned the key column to represent the results of the ?label variable returned in the query
  • Assigned the value column to represent the results of the ?count variable returned in the query
  • Set the chart to display the labels from the key column
  • Set the chart to display a legend of all key column values
Google Charts Editor
Start tab

This tab is simple yet powerful. Callimachus' Chart Wizard will actually introspect the structure of the Named Query's results and suggest charts that may make the most sense for the underlying data. Also, if applicable, this tab allows users to set the first column of results as labels for any resulting charts.

Charts tab

The Charts tab houses the full collection of available charts and visualizations (full list below). Simply click a chart option to populate the preview area to the right. If a chart would not render properly based on the underyling data the option is greyed out and the preview area offers some guidance on how the data must be structured in order for that chart to be used.

Customize tab

The Customize tab gives you the ability to fine-tune your chart to whatever level of granularity you desire. Each specific chart has it's own respective set of configuration options available under the "Customize" tab in the Chart Wizard. Some are more configurable than others but in general you will be able to edit aspects such as color, font, title, legend, and more. Just as in the Charts tab, any changes made here are immediately reflected in the preview pane to the right.

6.5.3. Chart Types

  • Table
    • Bootstrap
    • Datatable
    • Google Charts
  • Bar 
    • Dimple
    • Google Charts -> Basic
    • Google Charts -> Stacked
  • Line
    • Dimple
    • Google Charts -> Basic
    • Google Charts -> Smooth
    • Google Charts -> Combo
    • Google Charts -> Radar
  • Area
    • Dimple
    • Google Charts -> Basic
    • Google Charts -> Stacked
    • Google Charts -> Stepped
  • Pie
    • NVD3
    • Google Charts -> Basic
    • Google Charts -> Three dimensional
    • Google Charts -> Donut
  • Map
    • Google Charts -> Region
    • Google Charts -> Marker
  • Column
    • Google Charts -> Basic
    • Google Charts -> Stacked
  • Scatter 
    • Google Charts -> Basic
    • Google Charts -> Bubble
  • Trend
    • Google Charts -> Spark
    • Google Charts -> Time
    • Google Charts -> Motion
    • Google Charts -> Candlestick
  • Other
    • Google Charts -> Gauge
    • Google Charts -> Org Chart
    • Google Charts -> Tree map
    • Google Charts -> Table

6.5.4. Integration into Applications

There are two ways in which these charts can be integrated into Callimachus pages and applications. The first is via the @view template notation on Named Query templates and the second is through embedded iFrames.

Named Query View Template

If you click "Save settings..." at the bottom of the Chart Editor and save the chart, that chart's new URL is set as the @view template for the Named Query the chart is based on. If you create another visualization for that same Named Query, the @view template will be updated to the most recent visualization.

Note: Previously created visualizations have not been deleted, they are just not assigned as the @view template for the Named Query. The visualization itself still exists.

If you want to keep the visualization but do not want it applied as the @view template for the Named Query, simply edit the Named Query and remove the URL following @view at the top of the page.

iFrame

Another way to integrate the visualizations into different pages and applications is via iFrames. This allows for ultimate flexibility since iFrames can be independetly styled and layed out on the page. Use the URL of the visualization as the @src attribute for the iFrame and you're done!

<iframe src="/my-first-chart.xhtml?view" />

6.5.5. Sample Query

Want to try out the Chart Editor quickly? Upload this sample query which lends itself well to a large number of the chart options. 

#
# @Cache-Control: 
# @infer true
# @view
#
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>

SELECT ?label (COUNT(?type) AS ?count) {

    ?resource a ?type .

    ?type rdfs:label ?label .
} GROUP BY ?label ORDER BY DESC(?count) LIMIT 30

Chapter 7. Using XProc

7.1. Callimachus Pipeline

7.1.1. Overview

Callimachus supports XProc pipeline documents as first-class Pipeline objects. It uses the Calabash XProc implementation for this purpose. Pipeline objects can be created in a folder (selecting the 'Pipeline' item from the create menu) and given content that conforms with the XProc: An XML Pipeline Language specification.

Then, POST and GET requests can be dispatched to them as web resource in order to invoke the pipeline and return the XML document from the result primary output port as the body of the response. The query component of the request URI can be used to pass values in as options into the pipeline.

The input document for the source port (declared as a document input of the pipeline) can be specified for the instantiation of the pipeline.

7.1.2. HTTP Methods

XProc pipelines can be invoked by POST and GET requests using their URL as the request URL along with request in the query component. We will refer to this as the result URL. For example:

..pipeline..URL..?results

Additional key / value pairs can be used in the query component to pass options into the XProc pipeline. This is discussed in the next section.

Sending an HTTP GET request to the result URL will trigger an instantiation of the pipeline without providing an input document in the source port. The pipeline would have to take care of that by either embedding the input document into the pipeline or requesting it using the p:load step, for example:

<?xml version="1.0" encoding="UTF-8" ?>
<p:pipeline xmlns:p="http://www.w3.org/ns/xproc" version="1.0" name="pipeline">

    <p:load href="my-query.rq?results" />

    <p:xslt> 
        <p:input port="stylesheet">
            <p:document href="my-transform.xsl" />      
        </p:input>
    </p:xslt>

</p:pipeline>

Note the URL used by the p:load step can identify a Callimachus web resource (an XML document), facilitating the use of Callimachus web resources as XProc pipelines and inputs to such pipelines.

Sending an HTTP POST request to the result URL will trigger an instantiation of the pipeline, passing the request body as an input document for the source port.

7.1.3. Pipeline Options

Any query parameters appended to the result URL, as additional query components, will be passed into the pipeline as options name/value string pairs, if the pipeline declares the options.

So a POST request to:

..pipeline..URL..?results&foo=bar

To the following pipeline:

<?xml version="1.0" encoding="UTF-8" ?>
<p:pipeline xmlns:p="http://www.w3.org/ns/xproc" version="1.0" name="pipeline">

    <p:option name="foo" required="true" />

    <p:load>
        <p:with-option name="href" select="concat('my-query.rq?results&amp;foo=', encode-for-uri($foo))"/>
    </p:load>

    <p:xslt> 
        <p:input port="stylesheet">
            <p:document href="my-transform.xsl" />      
        </p:input>
    </p:xslt>

</p:pipeline>

Will pass the foo option as a query parameter to the named query my-query.rq and use the result as the source for the xsl transformation.

I.e., the options are passed into the pipeline document as in-scope bindings options.

7.2. Overview

Callimachus 0.18 introduced an XProc implementation. XProc is an XML pipeline language and can be used to script the transformation of content such as SPARQL query results or XML data gathered from the Web. XProc is a W3C Recommendation.This page provides examples of XProc pipelines to perform common tasks.

The XProc Web site provides links to other materials, including a tutorial and examples. The XProc specification provides the complete details of the XProc syntax and should be consulted before using XProc for complex tasks. The purpose of this page is to ease your transition into XProc usage by providing a short tutorial.

Callimachus uses XProc as an extension mechanism. As of Callimachus 0.18, one can create PURLs that resolve to XProc pipelines. XProc replaces the Action with no side effects pattern that used an executable Turtle file to orchestrate the transformation of SPARQL query results to other formats via XSLT.

An XProc pipeline works similarly to other pipeline implementations: A series of "steps" are defined and the order of processing is step-by-step. Consider a Unix pipeline as an analogy:

$ cat README.txt | grep Callimachus > callimachus-refs.txt

That Unix pipeline consists of two steps (the 'cat' command and the 'grep' command. The first step echoes the contents of the file README.txt, which is passed to the 'grep' command. The 'grep' command outputs only those lines containing the word 'Callimachus'. Finally, the results are put onto the process' STDOUT and thus to a file. An XProc pipeline works in a similar manner. A number of steps are defined, the output of each becomes the input to the next. The equivalent of STDIN in XProc is called source and has zero or more XML documents. The equivalent of STDOUT in XProc is called result and has zero or more XML documents.

7.3. "Hello, World" in XProc 

XProc pipelines may be created in Callimachus just like any other type of resource. Navigate to any Callimachus folder where you have write access and select Pipeline from the menu.

You will be redirected to an editor with the default pipeline definition pre-populated in it:

To create your pipeline, simply type (or copy) your XProc definition into the editor. A simple XProc pipeline that outputs "Hello, World" looks like this:

<?xml version="1.0" encoding="UTF-8" ?> 
  
<p:pipeline version="1.0" 
      xmlns:p="http://www.w3.org/ns/xproc" 
      xmlns:c="http://www.w3.org/ns/xproc-step" 
      xmlns:l="http://xproc.org/library"> 
  
<p:serialization port="result" media-type="text/plain" method="text" /> 
  
<p:identity> 
  <p:input port="source"> 
    <p:inline> 
      <c:data content-type="text/plain">Hello, World</c:data> 
    </p:inline> 
  </p:input> 
</p:identity> 

</p:pipeline>

The output of this pipeline may be retrieved by resolving its URL with the suffix "?results" appended.

If you saved the above pipeline at the URL http://example.com/test/hello-world.xpl then you can get the pipeline itself at that URL, a human-readable HTML page containing the pipeline at http://example.com/test/hello-world.xpl?view and the results of the pipeline at http://example.com/test/hello-world.xpl?results, like this:

$ curl http://example.com/test/hello-world.xpl 
<?xml version="1.0" encoding="UTF-8" ?> 
<p:pipeline version="1.0" 
      xmlns:p="http://www.w3.org/ns/xproc" 
      xmlns:c="http://www.w3.org/ns/xproc-step" 
      xmlns:l="http://xproc.org/library"> 

<p:serialization port="result" media-type="text/plain" method="text" /> 

<p:identity> 
  <p:input port="source"> 
    <p:inline> 
      <c:data content-type="text/plain">Hello, World</c:data> 
    </p:inline> 
  </p:input> 
</p:identity> 

$ curl http://example.com/test/hello-world.xpl?results 

                     Hello, World

You might be thinking, "Wow! That's typical XML! Very verbose to do so little." We hope to convince you that XProx is an excellent way for us to extend Callimachus into new areas, such as gathering, transforming and rendering data from anywhere on the Web.

In the "Hello, World" example, the serialization tag sets the MIME type of the result. If this tag is not present, XProc defaults to a MIME type of "application/xml" and a method of "xml".

The p:identity tag is used to echo any defined input to the output. In this case, we specified a literal string and asked that it be put to the output.

We could do something similar by getting a resource from the Web and putting it to the output. It would be more interesting to get two resources from the Web and combine them. The following section gets two Atom feeds from blogs, combines them and creates a new Atom feed of the results.

7.4. Create an RSS feed from two named Atom feeds

This example uses XSLT to convert each input feed from Atom format to RSS format, gets their entries and places the entries into an RSS template. XProc p:document tags are used to read Atom feeds from blog sites and then they are converted using xslt to RSS using p:xslt steps. Lastly, an p:insert tag is used to insert the items from the produced channels into the empty rss channel.

<?xml version="1.0" encoding="UTF-8" ?> 
<p:pipeline version="1.0" 
      xmlns:p="http://www.w3.org/ns/xproc" 
      xmlns:c="http://www.w3.org/ns/xproc-step" 
      xmlns:l="http://xproc.org/library"> 

<p:serialization port="result" media-type="application/rss+xml" method="xml" /> 

<p:xslt name="prototypo-rss"> 
  <p:input port="source"> 
    <p:document href="http://prototypo.blogspot.com/feeds/posts/default" /> 
  </p:input> 
  <p:input port="stylesheet"> 
    <p:document href="http://atom.geekhood.net/atom2rss.xsl" /> 
  </p:input> 
</p:xslt> 

<p:xslt name="jamesrdf-rss"> 
  <p:input port="source"> 
    <p:document href="http://jamesrdf.blogspot.com/feeds/posts/default" /> 
  </p:input> 
  <p:input port="stylesheet"> 
    <p:document href="http://atom.geekhood.net/atom2rss.xsl" /> 
  </p:input> 
</p:xslt> 

<p:insert match="/rss/channel" position="last-child"> 
  <p:input port="source"> 
    <p:inline> 
      <rss version="2.0"> 
        <channel> 
          <title>RSS Title</title> 
          <description>This is an example of an RSS feed</description> 
          <link>http://www.someexamplerssdomain.com/main.html</link> 
          <lastBuildDate>Mon, 06 Sep 2010 00:01:00 +0000 </lastBuildDate> 
          <pubDate>Mon, 06 Sep 2009 16:45:00 +0000 </pubDate> 
          <ttl>1800</ttl> 
        </channel> 
      </rss> 
    </p:inline> 
  </p:input> 
  <p:input port="insertion" select="/rss/channel/item"> 
    <p:pipe step="prototypo-rss" port="result" /> 
    <p:pipe step="jamesrdf-rss" port="result" /> 
  </p:input> 
</p:insert>

</p:pipeline>

7.5. Rendering RDF from Pipeline into HTML using Callimachus Templates

<?xml version="1.0" encoding="UTF-8" ?> 
<p:pipeline version="1.0" 
      xmlns:p="http://www.w3.org/ns/xproc" 
      xmlns:c="http://www.w3.org/ns/xproc-step" 
      xmlns:l="http://xproc.org/library" 
      xmlns:calli="http://callimachusproject.org/rdf/2009/framework#"> 

<p:serialization port="result" media-type="text/html" method="html" doctype-system="about:legacy-compat" /> 

<p:import href="/callimachus/library.xpl" /> 

<calli:render-html> 
  <p:input port="source"> 
    <p:document href="http://localhost:8080/moon?describe" /> 
    <p:document href="http://localhost:8080/sun?describe" /> 
  </p:input> 
  <p:input port="query"> 
    <p:inline> 
      <c:data content-type="application/sparql-query">
        <![CDATA[
          SELECT ?this { BIND (<$target> AS ?this) }
        ]]>
      </c:data> 
    </p:inline> 
  </p:input> 
  <p:with-param name="target" select="'moon'" /> 
  <p:input port="template"> 
    <p:document href="/callimachus/templates/concept-view.xhtml" /> 
  </p:input> 
</calli:render-html> 

</p:pipeline>

7.6. Rendering SPARQL Endpoint into HTML using Callimachus Templates


<?xml version="1.0" encoding="UTF-8" ?> 
<p:pipeline version="1.0" 
      xmlns:p="http://www.w3.org/ns/xproc" 
      xmlns:c="http://www.w3.org/ns/xproc-step" 
      xmlns:l="http://xproc.org/library" 
      xmlns:calli="http://callimachusproject.org/rdf/2009/framework#"> 
 
<p:serialization port="result" media-type="text/html" method="html" doctype-system="about:legacy-compat"/> 
 
<p:option name="id" required="true"/>
 
<p:import href="/callimachus/library.xpl"/> 
 
<calli:render-html endpoint="/data/endpoint">
  <p:input port="query"> 
    <p:inline> 
      <c:data content-type="application/sparql-query">
        <![CDATA[
          SELECT ?this { BIND (<$target> AS ?this) }
        ]]>
      </c:data> 
    </p:inline> 
  </p:input> 
  <p:with-param name="target" select="$id"/>
  <p:input port="template">
    <p:document href="endpoint-view.xhtml"/> 
  </p:input> 
</calli:render-html> 
 
</p:pipeline>

7.7. Displaying Named Query Results on OpenStreetMap via Pipeline

This example will demonstrate a few core pieces of functionality strung together to create an interesting and useful application. It will walk through the following steps:

  1. Creating a named query
  2. Using that named query as the input source of an XML Processing (XProc) pipeline
  3. Assigning a Perisistent URL (PURL) to the results of that XProc pipeline [Optional]
  4. Generating an OpenStreetMap display from a call to that PURL

Specifically, this example will generate a map of all the Nuclear Maps in the United States, plot those points on a map, and allow the user to click on any of those facilities and learn more about a facility.

7.7.1. 1. Create a named query

This query must return data in a way that is compliant with use by OpenStreetMap. Here is what the query looks like in Callimachus:

As you can see above, the query specificly selects the URL (?link), name (?title), description (?description, which is always the same), and latitute (?lat) and longitude (?long) of the facility. This query generates a SPARQL Protocol and RDF Query Language (SPARQL) XML result set which must now be transformed into Geographically Encoded Objects for Rich Site Summary (GeoRSS) via an XProc pipeline.

7.7.2. 2. Use that named query as the input source of an XProc pipeline

To generate GeoRSS from SPARQL XML results, use an XProc pipeline with the appropriate EXtensible Stylesheet Language (XSL) stylesheet.

<?xml version="1.0" encoding="UTF-8" ?> 
<p:pipeline version="1.0" 
      xmlns:p="http://www.w3.org/ns/xproc" 
      xmlns:c="http://www.w3.org/ns/xproc-step" 
      xmlns:l="http://xproc.org/library"> 

<p:serialization port="result" media-type="application/rss+xml" method="xml" /> 

<p:load href="nukemap.rq?results" /> 

<p:xslt name="nukemap"> 
  <p:input port="stylesheet"> 
    <p:document href="sparql-georss.xsl" /> 
  </p:input> 
</p:xslt>

</p:pipeline>

There a small number of tags here each with their own distinct purpose. The serialization tag (<p:serialization>) uses the port attribute (port="result") to declare that the results of the pipeline will be a form of RSS+XML (media-type="application/rss+xml"). The load tag (<p:load>) executes the named query created in step 1 and returns the results to the pipeline.

XSL Transformation is a language for transforming one form of an XML document into another form of XML. In this case we'll be going from SPARQL XML to GeoRSS.  The XSLT tag (<p:xslt>) declares the start of the XSLT and names it "nukemap". Inside that transformation, the input tag (<p:input>) uses the port attribute (port="stylesheet") to specify the stylesheet that will be applied to the results of the named query. The document tag (<p:document>) specifies the URL of the stylesheet to be used (href="sparql-georss.xsl") which in this case is located in the same directory as the pipeline.

7.7.3. 3. Assign a PURL to the results of that XProc pipeline [Optional]

To enable the ability to set caching control, as well as move or edit the XProc pipeline without having to change the link, it would be wise to assign a PURL to the results of the pipeline. However, if you are simplying putting together a prototype, or do not anticipate relocating your resource, a PURL is entirely optional. The map can call the URL of the XProc pipeline without the intermediary PURL. However, if you were to create a PURL it would look like this:

The PURL is given a name (nukemap) and a type of 200 which means that the results of this PURL will be copied from their location. Content location specifies where the PURL should look for content, which in this case we want to be the results of our XProc pipeline (nukemap.xpl?results). Lastly, we can set cache control on the PURL. This is a way of improving efficiency by not having to constantly fetch new results if a number of requests are made in quick succession. In this case we are specifying that if multiple requests are made over the course of 3,600 seconds, rather than following the PURL and getting new results each time, simply grab results from cache. 

7.7.4. 4. Generate OpenStreetMap display from a PURL

The last step of this example is to tie it all together. At this point there is now a single PURL (nukemap) that can be accessed which will return the results of the named query in GeoRSS format. Now that PURL needs to be worked into the OpenStreetMap code as the input for generating the map itself. If you are unfamiliar with OpenStreetMaps (OSM) at a high level, it would be beneficial to read some of their basic documentation and examples before diving into this code.

<?xml-stylesheet type="text/xsl" href="/callimachus/template.xsl"?> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head> 
  <title>U.S. Nuclear Plants</title> 
  <script src="//www.openlayers.org/api/OpenLayers.js"></script> 
  <script> 
  // <![CDATA[ 
    jQuery(function() { 
      var map = new OpenLayers.Map("mapdiv"); 
      map.addLayer(new OpenLayers.Layer.OSM()); 
      
      map.addLayer(new OpenLayers.Layer.GeoRSS("My Points", "nukemap", { 
        tileOptions: { crossOriginKeyword: null } 
      })); 

      map.setCenter(new OpenLayers.LonLat("-98.0", "38.0").transform( 
          new OpenLayers.Projection("EPSG:4326"), // transform from WGS 1984 
          map.getProjectionObject() // to Spherical Mercator Projection 
        ), 4 // Zoom level 
      ); 
    }); 
  // ]]> 
  </script> 

  <style> 
    .leaflet-map-pane img, /* OpenStreetMap */ 
    .olMapViewport img { /* general OpenLayers maps */ 
      max-width: none; 
     } 
  </style> 

</head> 
<body> 
  <h1>U.S. Nuclear Plants</h1> 
  <table width="100%"> 
    <tbody> 
      <tr> 
        <td style="width:100%">
          <div id="mapdiv" style="height:800px"></div>
        </td> 
      </tr> 
    </tbody> 
  </table> 
</body> 
</html>

There is really one important line that makes this code different from a standard implementation of OSM and that line is:

map.addLayer(new OpenLayers.Layer.GeoRSS("My Points", "nukemap", { tileOptions: { crossOriginKeyword: null } }));

which is where we call the nukemap PURL as the source of our GeoRSS. With the infrastructure in place it is a simple adjustment to standard code that allows for a simple collection of data files to become an interesting visualization of nuclear plants in the United States.

NB: Twitter Bootstrap (which Callimachus' default theme is based on) has a default setting that intereferes with OpenStreetMap. Luckily this can be easily overcome with a bit of CSS at the top of the page. The code is below.

<style> 
  .leaflet-map-pane img, /* OpenStreetMap */ 
  .olMapViewport img { /* general OpenLayers maps */ 
    max-width: none; 
  } 
</style>

7.8. Passing Parameters into a Pipeline for Use in a Named Query

Passing parameters into an XProc Pipeline is structurally very similar to passing them into Named Queries. The URI is still query.rq?results&variableName=variable.  However, once the paramater has been successfully passed into the pipeline the pipeline must interpret it correctly depending on where it will be used. It starts the same way, with the <p:option> tag. The name attribute assigns the paramter a name while the required attribute states whether or not the parameter is necessary for the pipeline to execute.

From there, if the intent is to use the parameter in a named query, the query string must be built up inside the <p:load> tag in order for it to be passed correctly to the named query. In this example the <p:with-option> tag two attributes: the name attribute which defines it as a link (href) and the select attribute which defines where to look for that link. Inisde the select attribute is where the query string must be constructed using the concat function. The string is simply the file name for the query (nuclear-chemical-amount.rq), the suffix that returns results in SPARQL/XML (?results) and the URI-encoded variable name and string (&amp;substance='encode-for-uri($substance)). $substance here refers to the option that was defined in the previous step.

After this step, the SPARQL/XML that is returned can be passed to any other necessary steps just as it could be in a pipeline that does not use parameters.

<?xml version="1.0" encoding="UTF-8" ?>
<p:pipeline version="1.0" 
      xmlns:p="http://www.w3.org/ns/xproc" 
      xmlns:c="http://www.w3.org/ns/xproc-step" 
      xmlns:l="http://xproc.org/library"> 

<p:serialization port="result" media-type="application/json" method="text" /> 

<p:option name="substance" required="true" /> 

<p:load> 
    <p:with-option 
        name="href" 
        select="concat( 
            'nuclear-chemical-amount.rq?results&amp;substance=', 
            encode-for-uri($substance) 
        )" 
    /> 
</p:load> 

<p:xslt name="piechart">
    <p:input port="stylesheet">
        <p:document href="../coordinate-points-d3-json-sparql.xsl" /> 
    </p:input> 
    <p:with-param name="x-coordinate-variable" select="'name'" /> 
    <p:with-param name="y-coordinate-variable" select="'total'" /> 
</p:xslt> 

</p:pipeline>

7.9. Aggregating RDF through a pipeline

If you are trying to expose some raw RDF and a describe query is not the right solution for you, for example because you want to intelligently aggregate data from multiple sources, then the following pattern is useful. It also demonstrates how to generate a CONSTRUCT sparql query and call it from within XProc.

The intent of the example below is to fetch the RDF for a specific facility. It then aggregates any referenced data from the same data source (filtering out what is not required). Finally, it aggregates data from another data source.

Note the with-option line: <p:with-option name="replace" select="concat('replace(., &quot;%ID%&quot;, &quot;', $id, '&quot;)')" />. This is hard to read but it takes the pipeline parameter $id and contructs a replace function call to modify the SPARQL query. For example, if the id was 1234, the generated function would be

replace(., '%ID%', '1234')

Having built the SPAQRL query it is then executed by a POST to the relevant endpoint and the results are returned as XML.

<?xml version="1.0" encoding="UTF-8"?>
<p:pipeline version="1.0"
    xmlns:p="http://www.w3.org/ns/xproc"
    xmlns:c="http://www.w3.org/ns/xproc-step"
    xmlns:l="http://xproc.org/library"
    xmlns:frs="http://opendata.epa.gov/frs/schema#"
    xmlns:rcra="http://opendata.epa.gov/rcra/schema/"
>

<p:serialization port="result" media-type="application/rdf+xml" method="xml"/> 

<p:option name="id" required="true" />

<p:string-replace match="/c:request/c:body/text()">
    <p:with-option name="replace" select="concat('replace(., &quot;%ID%&quot;, &quot;', $id, '&quot;)')" />
    <p:input port="source">
        <p:inline>
            <c:request method="post" href="/usepa/data/frs">
                <c:body content-type="application/sparql-query">
                <![CDATA[
                PREFIX places: <http://purl.org/ontology/places#>
                PREFIX rcra: <http://opendata.epa.gov/rcra/schema/>
                CONSTRUCT { ?s ?p ?o }
                WHERE {{
                    BIND(<http://opendata.epa.gov/facilities/%ID%> AS ?s) ?s ?p ?o
                } UNION {
                    BIND(<http://opendata.epa.gov/facilities/%ID%> AS ?facility) ?facility ?fp ?s .
                    ?s ?p ?o .
                    FILTER (?p NOT IN(places:contains))
                } UNION {
                    SERVICE </usepa/data/rcra> {
                        SELECT DISTINCT * {{
                            BIND(<http://opendata.epa.gov/facilities/%ID%> AS ?facility)
                            ?s owl:sameAs $facility .
                            ?s ?p ?o.
                        } UNION {
                            BIND(<http://opendata.epa.gov/facilities/%ID%> AS ?facility)
                            ?handler owl:sameAs $facility .
                            ?handler ?handlerPred1 ?s .
                            FILTER (?handlerPred1 NOT IN(rcra:hasActivity))
                            ?s ?p ?o .
                        } UNION {
                            BIND(<http://opendata.epa.gov/facilities/%ID%> AS ?facility)
                            ?handler owl:sameAs $facility .
                            ?handler ?handlerPred2 ?s .
                            FILTER (?handlerPred2 IN(rcra:hasActivity))
                            ?s ?p ?o .
                            FILTER (?p IN(rcra:receivedReportOn, rcra:reportType, rcra:reportedInCycle))
                        }}
                    }
                }}
                ]]>
              </c:body>
            </c:request>
        </p:inline>
    </p:input>
</p:string-replace>

<p:http-request/>

</p:pipeline>


Chapter 8. Some Best Practices to Follow

Here are four best practices to follow when developing Callimachus applications.

8.1. Handling multiple languages

8.1.1. Overview

Linked data applications are particularly well-suited for multilingual data portals. Below are three multilingual templates from the Callimachus Meeting Notes Tutorial which have been modified to show a best practice for managing multilingual data.

8.1.2. journal-create

Description

When a new Journal is created the jQuery function highlighted below sets the lang attribute of the comment field to the language of the user’s browser.

Source Code
<?xml version="1.0" encoding="UTF-8" ?>
<html version="XHTML+RDFa 1.0" xmlns="http://www.w3.org/1999/xhtml"
    xmlns:xi="http://www.w3.org/2001/XInclude"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
    xmlns:dcterms="http://purl.org/dc/terms/">
<head>
    <title>New Journal</title>
    <style type="text/css">
        .fr :lang(en) { display: none; }
        .en :lang(fr) { display: none; }
    </style>
    <script type="text/javascript">
    (function($){
        var language = window.navigator.language || window.navigator.userLanguage;
        var lang = language.toLowerCase().replace(/-.*/,'');
        document.documentElement.className += ' ' + lang;
        jQuery(function($) {
            $('#comment').attr('lang', lang); 
        });
    })(jQuery);
    </script>
</head>
<body>
    <div class="container">
        <div class="page-header">
            <h1>New Journal</h1>
        </div>
        <form role="form" method="POST" action="" enctype="text/turtle" resource="" typeof="" class="row"
                onsubmit="calli.submitTurtle(event,calli.slugify($('#label').val()))">
            <fieldset class="col-sm-4">
                <div class="form-group">
                    <label for="label" lang="en">Label</label>
                    <label for="label" lang="fr">Étiquette</label>
                    <input type="text" id="label" value="{rdfs:label}" class="form-control" required="required" autofocus="autofocus"
                        onchange="calli.updateProperty(event, 'rdfs:label')" />
                </div>
                <div class="form-group">
                    <label for="comment" lang="en">Comment</label>
                    <label for="comment" lang="fr">Commentaire</label>
                    <textarea id="comment" class="form-control"
                        onchange="calli.updateProperty(event, 'rdfs:comment')">{rdfs:comment}</textarea>
                </div>
                <div class="form-group">
                    <button type="submit" class="btn btn-success" lang="en">Create</button>
                    <button type="submit" class="btn btn-success" lang="fr">Créer</button>
                </div>
            </fieldset>
        </form>
    </div>
</body>
</html>

8.1.3. journal-edit

Description

The jQuery function loops through each value of the language attribute and hides comments which are not in the default language for the browser. If there is no comments field it adds one.

Source Code
<?xml version="1.0" encoding="UTF-8" ?>
<html version="XHTML+RDFa 1.0" xmlns="http://www.w3.org/1999/xhtml"
    xmlns:xi="http://www.w3.org/2001/XInclude"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
    xmlns:dcterms="http://purl.org/dc/terms/">
<head>
    <title resource="?this">{rdfs:label}</title>
    <style type="text/css">
        .fr :lang(en) { display: none; }
        .en :lang(fr) { display: none; }
    </style>
    <script type="text/javascript">
    (function($){
        var language = window.navigator.language || window.navigator.userLanguage;
        var lang = language.toLowerCase().replace(/-.*/,'');
        document.documentElement.className += ' ' + lang;
        jQuery(function($) {
            if (!$('#comments .comment:visible').length) {
                calli.addResource({}, '#comments');
            }
        });
       window.changeLangIfModified = function(input) {
           if(input.value != $(input).text()){
               $(input).attr('lang', lang);
               $(input).text(input.value);
           }
       };
    })(jQuery);
    </script>
</head>
<body resource="?this" onload="comparison=calli.copyResourceData('#form')">
    <div class="container">
        <div class="page-header">
            <h1 property="rdfs:label" />
        </div>
        <form id="form" role="form" method="POST" action="" enctype="application/sparql-update" resource="?this" class="row"
                onsubmit="calli.submitUpdate(comparison,event)">
            <fieldset class="col-sm-4">
                <div class="form-group">
                    <label for="label" lang="en">Label</label>
                    <label for="label" lang="fr">Étiquette</label>
                    <input type="text" id="label" value="{rdfs:label}" class="form-control" required="required"
                        onchange="calli.updateProperty(event, 'rdfs:label')" />
                </div>
                <div class="form-group">
                    <label for="comment" lang="en">Comment</label>
                    <label for="comment" lang="fr">Commentaire</label>
                    <textarea id="comment" class="form-control"
                        onchange="calli.updateProperty(event, 'rdfs:comment')">{rdfs:comment}</textarea>
                </div>
                <div class="form-group">
                    <button type="submit" class="btn btn-primary" lang="en">Save</button>
                    <button type="submit" class="btn btn-primary" lang="fr">Enregistrer</button>
                    <button type="button" onclick="window.location.replace('?view')" class="btn btn-default" lang="en">Cancel</button>
                    <button type="button" onclick="window.location.replace('?view')" class="btn btn-default" lang="fr">Annuler</button>
                    <button type="button" onclick="calli.deleteResource(event)" class="btn btn-danger" lang="en">Delete</button>
                    <button type="button" onclick="calli.deleteResource(event)" class="btn btn-danger" lang="fr">Supprimer</button>
                </div>
            </fieldset>
        </form>
    </div>
</body>
</html>

8.1.4. journal-view

Description

The jQuery function loops through each value of the language attribute and hides comments which are not in the default language for the browser.

Source Code
<?xml version="1.0" encoding="UTF-8" ?>
<html version="XHTML+RDFa 1.0" xmlns="http://www.w3.org/1999/xhtml"
    xmlns:xi="http://www.w3.org/2001/XInclude"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
    xmlns:dcterms="http://purl.org/dc/terms/">
<head>
    <title resource="?this">{rdfs:label}</title>
    <style type="text/css">
        .fr :lang(en) { display: none; }
        .en :lang(fr) { display: none; }
    </style>
    <script type="text/javascript">
    (function($){
        var language = window.navigator.language || window.navigator.userLanguage;
        var lang = language.toLowerCase().replace(/-.*/,'');
        document.documentElement.className += ' ' + lang;
    })(jQuery);
    </script>
</head>
<body resource="?this">
    <div class="container">
        <div class="page-header">
            <h1 property="rdfs:label" />
        </div>
        <div class="row">
            <div class="col-sm-8">
                <p property="rdfs:comment" />
                <ul>
                    <li rev="dcterms:isPartOf" resource="?note">
                        <a href="?note">
                            <time datetime="{dcterms:date}" />
                        </a>
                    </li>
                </ul>
                <script type="text/javascript">
                    $('li time[datetime]').text(function(){
                        return calli.parseDateTime(this).toLocaleString();
                    });
                </script>
            </div>
            <div class="col-sm-4">
                <aside class="well well-sm">
                    <p class="lead">
                        <a resource="Note" href="Note"
                            onclick="href='?create='+encodeURIComponent(getAttribute('resource'))" lang="en">Create a new note</a>
                        <a resource="Note" href="Note?create"
                            onclick="href='?create='+encodeURIComponent(getAttribute('resource'))" lang="fr">Créer une nouvelle Note</a>
                    </p>
                </aside>
            </div>
        </div>
    </div>
</body>
</html>

8.2. Naming Callimachus resources

8.2.1. Naming Conventions

Developers should follow these conventions when naming Callimachus resources.

Identifier

Convention

Case

Example

Namespace prefix

two to six letters

lower

sig

Class

noun

PascalCase

AppDomain

Message class

verb

PascalCase

GetAppResult

Datatype property

role noun

camelCase

typeName

Time property

verb

camelCase

completedOn

Object property

verb

camelCase

hasParent

Message property

noun

camelCase

inputStream

Query parameter

noun

lower case

authordetails

File or directory

- separates

lower case

event-create.xhtml

Singleton resource

_ separates

lower case

main_resource

Other resource

+ separates

lower case

my+resource

Namespace for things

/ ends and separates

lower case

/tools/

Sub-resource

# separates parent resource

lower case

my+resource#rel0

Nested resource

/ separates parent resource

lower case

parent/child

8.2.2. Naming guidelines

  1. Use alphanumeric characters for identifiers (unless convention otherwise indicates).

  2. Keep identifiers simple and descriptive.

  3. Avoid acronyms and abbreviations.

  4. Choose easily readable identifier names.

  5. Favor readability over brevity.

  6. Do not use Hungarian notation, where the variable type can be seen from its name.

  7. Avoid using identifiers that conflict with keywords of widely used programming languages.

  8. Use slash URI identifiers for things and hash URI identifiers for classes and properties.

8.3. Guidelines for page layout

8.3.1. Purpose

Apply these guidelines when designing your forms and pages in Callimachus.

UI Element Function
Page links area All links that are specific to the content in the page should appear on the right side of the screen in the sidebar.
Definitions area Definitions of terms used in the page or instructions on how to fill in forms should be given on the right in the sidebar, below the page links area.These instructions should be visually distinct from the page links area.
Page heading All pages should include a page heading.
Form fields Form fields should have their labels above the field.
Buttons The primary form buttons should be shown before the secondary buttons, and should also be visually different.

The sidebar should be a <div id="sidebar">...</div> with exactly one attribute: id="sidebar". No other attributes should be present. The sidebar may contain <aside></aside> elements, which may contains <h3></h3> and <p></p> or other block elements. The sidebar should be placed after the page heading. The page heading should either be a single <h1> element or an <hgroup> element with nested heading elements.

Form fields and buttons should use bootstrap's CSS convesions.

8.4. Using timestamps to control state transitions

8.4.1. Intent

To define a view of a single workflow task in a long-running process. The application data is represented as RDF data and the resource is an instance of a class that is required to be presented to the user. A typical state-change is represented as the monotonically increasing assertion of time-stamps. This helps to avoid the possibility of inconsistent states and removes the need for an RDF deletion.

8.4.2. Motivation

Applications often need to transition through a series of states, performing one significant task after another, and indicating to the user which tasks have been completed and what task is next. For example, an application may transition through state A, B, C and D. In a non-monotonic programming environment such as Java, one might use a state variable to indicate the current state, and (non-monotonically) modify this variable as the state changes:

currentState = S1;   // Initial state
  [ Perform some task T1 ]
currentState = S2;
  [ Perform another task T2 ]
currentState = S3;
  [ Perform yet another task T3 ]
currentState = S4;

However, if the state is being stored in RDF, changing the state this way is not so convenient, because it means that a /:currentState/ property must be continually deleted and re-asserted:

INSERT DATA { :app :currentState :S1 }   # Initial state
## Perform some task T1 ##
DELETE WHERE { :app :currentState ?s }
INSERT DATA { :app :currentState :S2 }
## Perform another task T2 ##
DELETE WHERE { :app :currentState ?s }
INSERT DATA { :app :currentState :S3 }
## Perform another task T3 ##
DELETE WHERE { :app :currentState ?s }
INSERT DATA { :app :currentState :S4 }

Such timestamps can also be useful for display to the user or for logging progress.

This style of programming also meshes nicely with the way state transitions are handled in the REST programming style. Several years ago Paul Prescod posted a nice explanation of this to a mailing list. (If anyone can provide a link, please do so.) In lieu of that, he has a pretty good description here: http://www.prescod.net/rest/state_transition.html .

8.4.3. Applicability

Consider using this pattern where the state of a resource must change over time and the resource is to be represented as RDF metadata.

8.4.4. Implementation

The view is constructed as a Callimachus XHTML template with RDFa properties. The subject of these properties, in both the head and body, is the task resource denoted by '?this'. Stateful properties are not displayed directly but are consumed by javascript and used to update the displayed status. The date-time of completion is shown using the standard datetime-locale layout. The status may change while the view page is open, so the javascript in the head reloads the page after a suitable interval.

8.4.5. Sample Code

The application metadata defines the relationship between the class of resource and the RDFa template:

@prefix eg: <http://example.com#>.
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.
@prefix calli: <http://callimachusproject.org/rdf/2009/framework#>.

eg:MyStatefulClass rdfs:subClassOf calli:Viewable ; calli:view <my-stateful-class.xhtml> .

The RDFa XHTML template my-stateful-class.xhtml contains:

 <?xml version="1.0" encoding="UTF-8" ?>
 <html xmlns="http://www.w3.org/1999/xhtml"
   xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
   xmlns:eg="http://example.com#">
   <head>
      <title resource="?this">{rdfs:label}</title>
      <script>setTimeout(function() {document.location.reload(false)}, 300000)</script>
   </head>
   <body resource="?this">
     <h1 property="rdfs:label" />
     <div id="status">
       <span property="eg:startedT1At" content="?t1">
          Step 1 since <time class="abbreviated">{?t1}</time>
       </span>
       <span property="eg:startedT2At" content="?t2">
          Step 2 since <time class="abbreviated">{?t2}</time>
       </span>
       <span property="eg:startedT3At" content="?t3">
          Step 3 since <time class="abbreviated">{?t3}</time>
       </span>
       <span property="eg:finishedAt" content="?t4">
          Finished since <time class="abbreviated">{?t4}</time>
       </span>
     </div>

     <script type="text/javascript"><![CDATA[
        // only show the last status
        $("#status>span:not(:last)").remove();
     ]]></script>

   </body>
 </html>

Part IX. Callimachus Reference

Chapter 9. Supported File Types

Callimachus resources are used to build Callimachus applications. A Callimachus resource is created by using the create menu from a folder.

Access to a resource may be controlled by using the Permissions menu item.

9.1. Serviceable Resources

The following tables documents the various actions common to many different files and resources types, these are initiated by appending the query string to the resource URL.

Resolving the URL of a file without attaching a pragma, or with an unsupported pragma, will result in the raw file being returned or, if the resource is not a file, a reasonable default action will occur (e.g. a PURL will resolve to its target, a folder will redirect to its index target, or redirect to the resource's view page).

Pragma Scope Description
?annotations Callimachus Enterprise resources Shows any OpenAnnotation annotations related to the resource.  Allows the creation of a new comment.
?classifiedby Callimachus Enterprise resources Shows the OpenAnnotation tags and categories for the resources and allows creation of new ones.
?describe All resources Shows the RDF describing the resource, in either Turtle, RDF+XML, JSON-LD, or HTML.
?discussion All resources Shows a discussion page similar to Wikipedia's Talk page about the resource.
?edit Resources with edit templates Returns a page based on the edit template of the resource that allows editing of the resource.
?history All resources Summarizes the history of changes to the resource.
?introspect All resources Shows the operations, properties and methods supported for the resource.
?permissions All resources Displays the permissions associated with the resource and allows changes to be made.
?relatedchanges All resources Displays changes related to the resource.
?results Named SPARQL queries Returns the results of the named query. Parameters to the query may be provided as additional options on the query string.
?view Resources with view templates Displays an XHTML page based on the view template of the resource.
?whatlinkshere All resources Shows the resources that link to the resource.

The following table summarizes some common requests (without any query string) that can be made to files hosted in Callimachus.

HTTP Method Description
GET Retrieve the raw file
PUT Replace the raw file
DELETE Remove the file and its metadata

9.2. Articles

A Callimachus article is a text file that is structured using the DocBook XML markup language, a popular and open standard for marking up technical documentation. Articles may be included in one or more Callimachus books.

Articles are used to create documentation in Callimachus.

Pragma Description
?docbook Responds with a docbook representation of article with all URLs in their absolute form

Callimachus uses the CKEditor to edit books and articles. To learn more about how to use the functions of the CKEditor that Callimachus exposes, please take a look at CKEditor's documentation.

9.3. Concepts

Callimachus concepts are used to categorize objects or events.  A concept consists of one primary label which is used to construct its URI, as well as any number of alternate labels. These alternate labels are used to assist in concept lookup.

Concepts are primary used to to clarify the usage and meaning of something. In an application they are used to populate controls such as dropdowns, checkboxes or radio buttons.

Note: A concept is a common attribute for one or more objects, not a set of objects, which would instead be modeled as a class. The distinction is subtle and is primarily based on the focus/emphasis of the data model used.

To create a concept, select Concept using the create menu from the folder you wish to store the concept in. You will be presented with a form.

In many data model the set of US state names or a list of the Canadian provinces are examples of concepts, as they are often simply geo properties of objects and often not the focus of the data model itself.

9.4. Folders

A Callimachus folder is a way to group files/resources. A folder may contain any of the following

  • File resources,
  • Folder resources, or
  • RDF resources

To create a folder, select Folder using the create menu from the folder you wish to create the new folder in.

Pragma Description
?contents Atom feed of the folder's contents
?changes Atom feed of the changes to files or resources within the folder
?archive Download a CAR file of the containing files and resources, or 404 if the folder is empty
PUT ?archive Replaces the files and resources within the folder with the archive in the request body
DELETE ?archive Removes all files and resources within the folder
?create=... Responds with the create form of the given class
9.4.1. Deleting the contents of a folder

To delete the contents of a folder

  • Click on the Edit tab
  • Use the Delete button to delete the folder and its contents
9.4.2. Granting folder permissions

To grant permissions to a folder, navigate to the desired folder and select Permissions from the main menu.

Lookup and add User Group(s) to the appropriate Role to assign permissions.

Role Permissions
Reader Redirected to the folder's index target (configured in the edit tab)
Subscriber View file listing, see the history, and discuss the folder
Contributor Create new resources in this folder
Editor Make changes using the edit tab and create new resources in this folder
Administator View, create and modify using any available operation
9.4.3. Exporting and importing the contents of a folder

Callimachus compresses and stores the contents of folders in CAR files. To export or import the contents of a folder, navigate to the folder and open the main menu.

If you click the Export folder contents entry, you will be prompted for a location on your computer to save the CAR file. If you click Import folder contents you will be prompted to specifiy the CAR file you wish to import. CAR files can either be imported and create/replace a subfolder or replace the current folder's contents.

9.5. ZIP and CAR Files

Archives are used to store many related files together as a single file. Using an archive the set of files can be managed as a single unit, which can reduce overhead and simplify processes for sets of files that are created and modified in unison.

Pragma Description
?contents Responds with the archive contents listing as an atom feed
?entry=... Responds with the archive entry with the given name

9.6. PURL

A Persistent URL or PURL is a permanent identifier for a web resource. It provides a permanent address for a web resource. PURLs provide a way of letting a service manage the resolution of URLs. As well PURLs provide metadata for resources.

Other persistent identifier schemes include Digital Object Identifiers (DOIs), Life Sciences Identifiers (LSIDs) and INFO URIs. While some other schemes such as DOIs do support curation, DOIs are seen as too commercial. LSIDs are functionally similar to PURLs since they may be mapped to a URL scheme and an administration service. INFO URIs provide neither real-time resolution, nor real-time administration.

PURLs are vulnerable to changes in Domain Name System (DNS) registrations and dependencies on the host computer. As well, a failure to resolve a PURL can lead to an ambiguous state.

A PURL solves the problem of changing URIs in a location-based URI scheme such as HTTP by providing the permanent identification of a web resource. Unlike a regular URL that simply provides an address to a web resource, a PURL redirects the browser to another Web resource.

PURLs ensure that clients can rely on the same Web address to get a web resource, even if the location of that resource changes. They allow the decentralized management and real-time administration of persistent identifiers (i.e. curation). As well, PURL services can solve the Web’s back link problem for content important enough to warrant its use.

PURLs have been used to address persistent identifier needs in the library and Linked Data communities for the past fifteen years. Many Linked Data vocabularies are hosted at purl.org including the Dublin Core element set and FOAF.

A public PURL service has been operated by the Online Computer Library Center since 1995.

9.6.1. Creating a PURL

To create a PURL, select PURL using the create menu from the folder that you wish to store the PURL in. You will be presented with a form.

When you press the Create button the PURL will appear in a Callimachus folder, just like any other Callimachus resource.

Here is a description of the fields used to specify a PURL:

Field Description
Local name The name of your PURL. This name will be appended to the URL of the folder you are in to form the PURL's address.
Comment An optional field provided for your own use.
GET status See PURL GET status.
GET content location The target location pattern for the GET response content from the PURL.
GET cache control How long the results of a PURL should be cached by a proxy or a client.
POST request target The response content location pattern for POST requests
PUT request target The response content location pattern for PUT requests
PATCH request target The response content location pattern for PATCH requests
DELETE request target The response content location pattern for DELETE requests
9.6.2. URL Target Patterns

The content location patterns are URI templates, optionally prefixed by a Regular Expression (on the same line), optionally prefixed by a comma separated list of request methods.

200, 404, and 410 GET location patterns and POST/PUT/PATCH/DELETE target patterns, may also include request headers (on their own line) and optionally a request body (separated by a blank line). These are used by Callimachus to create the out going HTTP request.

[[Method ]RegEx ]URI-Template[
Request-Header]*[

Request-Body]

The regular expression is applied against the entire (absolute) request-uri (include query string) starting at the end of this resource's URI. If the regular expression does not match or the request method does not match one of provided (if any are provided) the URI-template is ignored and error condition is returned to the client. If no regular expression is provided, the rule will only match requests that have the same path as this resource.

The URI-Template (and outgoing request headers and body, if applicable) uses the query parameters and regex group names and numbers as template variables. If multiple values exist for the variable, the values will be comma separated, unless the explode ('*') modifier is used, in which case the separator depends on the type of expansion.

Expansion Form Description Example Expansion
Literal The literal character is copied directly to the result /target-uri /target-uri
Unknown variable Variables that are undefined are ignored by the expansion process O{undef}X OX
Simple Percent encoded values, comma separated {hello} Hello%20World%21
Reserved Value substitution, comma separated {+path}/here /foo/bar/here
Fragment If any value, append crosshatch and values, comma separated {#x,hello,y} #1024,Hello%20World!,768
Label with Dot-Prefix Value substitution, each prefixed by the dot operator www{.dom*} www.example.com
Path Segment Value substitution, each prefixed by the slash operator {/list*} /red/green/blue
Path-Style Parameter Name-Value pairs prefixed by semicolon, separated by "=" {;list*} ;list=red;list=green;list=blue
Form-Style Query Percent encoded name-Value pairs prefixed by "?" or "&", separated by "=" {?x,y} ?x=1024&y=768
Form-Style Continuation Percent encoded name-Value pairs prefixed by "&", separated by "=" {&list*} &list=red&list=green&list=blue

If the target URL has no query string component, the incoming request query string is appended to the target URL.

For example, a call can be made to an existing PURL with parameters like this:

/existing-purl?first=Joe&last=Bloggs

These variables that are passed in, can then be passed on to the content location pattern of the PURL using bracket notation.

existing-pipeline.xpl?results{&first,last} -> /existing-pipeline.xpl?results&first=Joe&last=Bloggs

The variable names inside the curly brackets should match the variable names used in the query string (or regex named group or number) when the PURL is called. This notation will pass along a URL-encoded version of the parameter's value. If you want to pass along an unencoded version use the reserved expansion, indicated with a plus sign before the variable name, as shown in the table above and example below.

/{+last}/{+first}.txt -> /Bloggs/Joe.txt
9.6.3. PURL GET status

PURLs are categorized by the HTTP response code they result in. Callimachus implements the following types of GET responses:

Response code Label Description
200 Copy A PURL resource of this type is a cached copy of its target location. It is most often used in Callimachus to refer to XProc pipelines for the collection, transformation and rendering of remote content.
301 Canonical The resource has been assigned a new permanent URI and any future references to this resource SHOULD use the given location URI. The PURL redirects a client to the target location.
302 Alternate A representation of the resource currently resides at the given location. The PURL redirects a client to the target location.
303 Described by The target location provides information about the requested resource, but the requested resource may not be an "information resource" (that is, it may be a real-world object). This type of PURL is most often used when resolving RDF and Linked Data resources.
307 Resides The resource location has been temporarily changed. Redirection to the target location should be considered temporary and may change.
308 Moved The resource URL has been permanently moved to the target location.
404 Missing The resource is not available. It is "Missing". This situation may or may not be temporary. The content of the target location is used as the response content. The content might not be shown to a user if it is less than 512 bytes in length.
410 Gone The resource is no longer available and no forwarding address is known. This condition is expected to be considered permanent. The content of the target location is used as the response content. The content might not be shown to a user if it is less than 512 bytes in length.
451 Illegal Access to the resource is denied for legal reasons.

Note: The 200 PURL is also known as an "Active PURL" because the PURL takes an active role in creating its response. Other types of PURLs are passive in that they simply redirect to existing content and/or return an appropriate HTTP response code.

9.6.4. PURL example

In this example, we will name our PURL "blogrollup" to match the example XProc pipeline given in the XProc RSS feed example. This example uses a PURL of type 200 in order to resolve against a dynamically generated RSS feed.

Field Value
Local name blogrollup
GET status Copy (200)
GET content location blogrollup.xpl?results
Cache Control max-age=300

The GET content location field is set to the PURL's target location. PURLs of type 404 and 410 also require a GET location for their response content. In this example, we will provide a relative URL to the XProc results,  and append ?results to the XProc URL to get the results of the pipeline instead of the pipeline itself.

The Cache Control field determines how long the results of a PURL should be cached by a proxy or a client. In this example, we have reduced the max-age parameter from 3600 seconds (1 hour) to 300 seconds (5 minutes).

How it works

The XProc pipeline "blogrollup(.xpl)" serves as the target for the PURL "blogrollup". When the PURL "blogrollup" is resolved, the target location blogrollup.xpl?results is invoked, which creates the RSS feed and returns it as the result of the PURL.

Benefit of using this PURL

You could just call the XProc pipeline directly, however the PURL provides a significant benefit: The PURL address can stay persistent, even if the location of the target URL changes. Additionally, either the PURL or the pipeline can take parameters that impacts the output of the pipeline. Equally important is the ability for 200 type PURLs to cache their results.

9.6.5. Support for partial PURLs

Callimachus does not implement "Partial PURLs" as of the 1.4 release. Partial PURLs "allow PURLs to be created which refer to a directory level portion of a URL; any path information appended to a partial redirect PURL may in turn be appended to its target URL. That allows a single PURL to redirect to a hierarchy on a target Web server." They are useful in that they allow PURL targets to refer to database content. Callimachus may implement support for partial PURLs in a later release.

9.7. Images

Callimachus supports SVG, GIF, ICO, PNG, and JPEG image formats. Use the upload button in a the folder view or drag and drop the image onto the folder view listing.

JPEG photo files support server side resizing for network optimization. These pragmas return an image with the same proportions as the original, but the entire image has been resized so that either the width or height is one of the corresponding pixel lengths (the smaller dimension).

Pragma Description
?large A photo with a size of at least 1080 pixels in both dimensions
?medium A photo with a size of at least 480 pixels in both dimensions
?small A photo with a size of at least 240 pixels in both dimensions
?thumbnail A photo with a size of at least 64 pixels in both dimensions

These pragmas, which are only available to JPEG files hosted on Callimachus, can be used with the picture and source tags.

Only Chrome 38 and Firefox 33 support the picture element at this time.

<picture>
    <source media="(min-width: 1080px)" srcset="photo.jpeg?large" />
    <source media="(min-width: 480px)" srcset="photo.jpeg?medium" />
    <img class="img-responsive" src="photo.jpeg?small" />
</picture>

9.8. Books

A Callimachus book is a DocBook document.

Books organize articles into a desired sequence and hierarchy and may be divided into parts and chapters.

To create a book, select Book using the create menu from the folder you wish to store the book in. You will be presented with the following initial DocBook code:


<?xml version="1.0" encoding="UTF-8" ?>
<book xmlns="http://docbook.org/ns/docbook" xmlns:xl="http://www.w3.org/1999/xlink" 
      xmlns:xi="http://www.w3.org/2001/XInclude" version="5.0">

<title>Untitled Book</title>

</book>

Screenshot: Initial code for a book

9.8.1. Including an article

Use the xi:include tag to include an article by specifying its relative path.


<xi:include href="articles/who-is-using-callimachus.docbook" />
Pragma Description
?docbook Transcludes all articles and return the combined docbook file
9.8.2. Editing an included article

To edit an article when viewing a book

  • click on the  symbol which appears immediately after the article's title
  • press the edit tab to edit the article
9.8.3. Linking to a point in a book

When linking to a particular point in a book, insert an archor tag to set the destination for the link. The link target can be a named anchor within the article, a hash identifier elsewhere in the book, or the view page of an included article. Other links will point to the coresponding resources.

9.8.4. Adding a part

Use the following DocBook code to add a part to the book. Insert the code directly after the book's title tag for the first part.


    <part>
        <title>Topic</title>
        <preface>
            <title>Introduction</title>
            <para>
                Text goes here.
            </para>
            <para>Topics</para>
        </preface>
        <xi:include href="articles/new-topic.docbook" />
    </part>
9.8.5. Adding a chapter

Use the following DocBook code to add a chapter to a part. Insert the code directly after the part's <title> tag for the first chapter.


        <chapter>
            <title>Chapter title goes here</title>
            <info>
                <abstract>
                    <para>Overview goes here.</para>
                    <para>Topics</para>
                </abstract>
            </info>
            <xi:include href="articles/new-topic.docbook" />
        </chapter>

9.9. CSS Files

Cascading Style Sheet (CSS) files are used to specify the visual display of content. It is stored with a .css extension in a Callimachus folder.

To create a style, select CSS file using the create menu from the folder you wish to store the style in.

Styles are used to specify the visual presentation of a page. A style sheet may be included in any Callimachus page by naming it within a <link> tag.

Pragma Description
?less Evaluate this script file as a less.js file and inline all included styles
9.9.1. Linking style sheets to pages or templates

Linking the style sheet report.css to a Callimachus page:

<head>
    <title>Customer Report</title>
    <link rel="stylesheet" href="/styles/report.css" type="text/css" />
</head>

The stylesheet report.css centers the main heading:

h1
{
text-align:center;
}

Note: It is reccommended to use external styles sheets and not the <style> element.

9.10. Classes

A class describes a set of resources that share some common characteristics. In Callimachus a class is a set of RDF resources that use the same templates. Callimachus templates dynamically merge RDF data within XHTML5 pages, allowing users to create, view or edit resources from their browsers. Super classes may be used to inherit or override page templates.

To create a class, select Class using the create menu from the folder you wish to store the class in. You will be presented with a form to assign Class templates.

9.10.1. Classes and RDF resource types

When you create a Callimachus class you are also creating a RDF resource type.

9.10.2. Controlling who can create resources

Use the Authors field to specify the User Groups that are allowed to create resources for the class. When a user has permission to create one of these resources, the class label will appear in the create menu. If the class does not include a comment it will appear near the bottom of the create menu.

Icons are used in the create menu and next to the resources in the folder view. To add an icon, click the Icon link to open a file upload dialogue.

Pragma Description
?index Responds with a page listing some of the resources of the class

The index page, available from the main menu in a Class view page, is not a complete list, as only a limited number of resources are shown.

9.10.3. Using external classes

An external OWL class can be associated with a Callimachus class to apply templates to those resources. Once an OWL vocabulary has been uploaded, the owl:Class rdfs:labels can be searched using the equivalent field.

9.11. HTML Files

A Hypertext File is an HTML file served verbatim within Callimachus. This means that the normal JavaScript and CSS that is applied to Callimachus Pages (XHMTL files) is omitted when the page is rendered. Hypertext Files are ideal in Callimachus when you want to serve a page that will appear or function as a visually separate page or application.

In order to view an HTML page ensure that the URL ends in .html, rather than .html?view. If the URL is appended with ?view the page will be rendered within the contents section of the Callimachus layout. 

View within contents section:

http://example.com/resource.html?view

View as stand-alone HTML page:

http://example.com/resource.html

9.12. Relax NG and Schematron

RELAX NG is a schema language for XML and Schematron is a rule-based validation language for making assertions about the presence or absence of patterns in XML trees. Together this provide very strong XML validation.

Pragma Description
POST ?validate Validates the request body against this schema file

9.13. JavaScript Files

A script is a JavaScript file that is stored with a .js extension in a Callimachus folder.

To create a script, select Script using the create menu from the folder you wish to store the script in.

Scripts may be included in any Callimachus page or template by using the <script> tag. Below is a page the linking the script utility.js to a Callimachus page:

 <head>
    <title>Customer Report</title>
    <link rel="edit-form" href="?edit" />
    <link rel="comments" href="?discussion" />
    <link rel="version-history" href="?history" />
    <script type="text/javascript" src="/scripts/utility.js"></script>
...

Note: It is recommended that all <script> elements include a @src attribute for all, but the the most trival scripts.

9.14. Markdown

The Markdown language was created in 2004 by John Gruber with substantial contributions from Aaron Swartz, with the goal of allowing people to

write using an easy-to-read, easy-to-write plain text format, and optionally convert it to structurally valid XHTML (or HTML)

Callimachus supports John Gruber's Markdown syntax.

Pragma Description
?html Responds with just the HTML markup produced by this markdown file

9.15. Text, JSON, and XML

Callimachus supports text, JSON, and XML files.

Use GET, PUT, and DELETE requests to access and modify the raw file directly. Or use the pragmas below to access and modify the file from within a browser editor.

Pragma Description
?view Read only contents of the file within an HTML page
?edit Web editor to make changes to the file from your browser

9.16. XHTML Files

A Callimachus Page is an XHTML5 compliant web page.

Pages are used to store hypertext that may be used stand alone or as a template for an RDF resource.

To create a named page, select Page using the create menu from the folder you wish to store the new page in. You will be presented with the following XHTML 5 code:

<?xml version="1.0" encoding="UTF-8" ?>
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:xi="http://www.w3.org/2001/XInclude"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#">
<head>
    <title>Title Here</title>
    <link rel="edit-form" href="?edit" />
    <link rel="comments" href="?discussion" />
    <link rel="version-history" href="?history" />
</head>
<body>
    <div class="container">
        <h1>Title Here</h1>
        <xi:include href="container.xhtml" xpointer="xpath(//*[@class='container']/node()">
            <xi:fallback>
                <xi:include href="body.xhtml" xpointer="xmlns(xhtml=http://www.w3.org/1999/xhtml)xpath(//xhtml:body/node())" />
            </xi:fallback>
        </xi:include>
    </div>
</body>
</html>

Pages are used to create Callimachus Templates which are in turn associated with Callimachus Classes. They may include other pages (or files) using the xi:include tag. The optional xpointer attribute can be used to select a subsection of the page to include. To include a raw copy of the file (as text in the page), include the attribute parse="text". The xi:fallback tag can be used to containt content that should be used if the included page/file could not be found.

Pragma Description
?html Transcludes any included files and converts the XHTML into the HTML response
?sparql Responds with the sparql-query that would be used to populate templates using this page

9.17. XProc Pipeline

A Callimachus pipeline performs a sequence of operations on specified XML documents, such as transforming them into RDF in order to load data from a remote source. Callimachus supports XProc pipeline documents and uses the Calabash XProc implementation. 

To create a pipeline, select Pipeline using the create menu from the folder you wish to store the pipeline in. You will be presented with the following initial code:

<?xml version="1.0" encoding="UTF-8" ?>
<p:pipeline version="1.0"
        xmlns:p="http://www.w3.org/ns/xproc"
        xmlns:c="http://www.w3.org/ns/xproc-step"
        xmlns:l="http://xproc.org/library">

<p:identity />

</p:pipeline>
9.17.1. Invoking pipelines

Pipelines are invoked by HTTP GET and POST requests, using the URL as the request URL with results in the query component.

Result URL example

http://example.com/my-pipeline.xpl?results

Additional key / value pairs are used in the query component are passed as options into the pipeline.

HTTP GET request

Sending an HTTP GET request to the result URL will trigger an instantiation of the pipeline, without providing an input document for the source port. The pipeline would have to take care of that by either

  • Embedding the input document into the pipeline, or
  • Requesting it using the p:http-request step
Example: Invoking a pipeline using HTTP GET
<?xml version="1.0" encoding="UTF-8" ?>
<p:pipeline 
    xmlns:t="http://xproc.org/ns/testsuite" 
    xmlns:p="http://www.w3.org/ns/xproc"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0" 
    name="pipeline">
    <p:load href="http://example.com/document.xml" />
    <p:xslt>
        <p:input port="stylesheet">
            <p:inline>
                <xsl:stylesheet version="1.0">
                    <xsl:output method="xml" indent="yes" />
                    <xsl:template match="/">
                        <Info elementNo="{count(/Elements/Element)}"/>
                    </xsl:template>
                </xsl:stylesheet>            
            </p:inline>      
        </p:input>
    </p:xslt>  
</p:pipeline>

Assuming an HTTP GET request to http://example.com/document.xml returns: 

<?xml version="1.0" encoding="UTF-8" ?>
<Elements>
  <Element />
  <Element />
</Elements>

then, an HTTP GET request to the pipeline will result in:

<?xml version="1.0" encoding="UTF-8" ?>
<Info elementNo="2"/>

Note: The URL used by the p:load step can identify a Callimachus web resource (an XML document), facilitating the use of Callimachus web resources as XProc pipelines and inputs to such pipelines.

HTTP POST request

Sending an HTTP POST request to the result URL will trigger an instantiation of the pipeline, passing the request body as an input document for the source port.

9.17.2. Pipeline Parameters

Any parameters appended to the result URL, as additional query components, will be passed as options name/(string) value pairs.

So a POST request to:

http://example.com/my-pipeline.xpl?result&foo=bar 

to the following pipeline:

<?xml version="1.0" encoding="UTF-8" ?>
<p:pipeline 
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:p="http://www.w3.org/ns/xproc"
        version="1.0" 
        name="pipeline">
    <p:option name="foo" required="true" />
    <p:xslt>
        <p:with-param name="foo" select="$foo" />
        <p:input port="stylesheet">
            <p:inline>
                <xsl:stylesheet version="1.0">
                    <xsl:output method="xml" indent="yes" />
                    <xsl:param name="foo"/>
                    <xsl:template match="/">
                        <Element foo="{$foo}"/>
                    </xsl:template>
                </xsl:stylesheet>            
            </p:inline>      
        </p:input>
    </p:xslt>    
</p:pipeline>

will result in:

<Element foo="bar"/>

9.18. XQuery Files

XQuery is a query language that offers the ability to quickly and easily retrieve XML resources for rendering and presentation. Callimachus Layouts are XQuery files that provide a template for how content should be displayed.

The most common usage of XQuery files is as the Callimachus Layout. There are a number of very useful functions defined in the Callimachus XQuery Reference, many of which are used in the default layout.

Pragma Description
?results Evaluates this XQuery without an initial document
POST ?results Evaluates this XQuery using the request body as input

XQuery can also be used to format results, such as listings the unique speakers in each act of Shakespeare's play Hamlet, encoded in hamlet.xml.


 <html><head/><body>
 {
   for $act in doc("hamlet.xml")//ACT
   let $speakers := distinct-values($act//SPEAKER)
   return
     <div>
       <h1>{ string($act/TITLE) }</h1>
       <ul>
       {
         for $speaker in $speakers
         return <li>{ $speaker }</li>
       }
       </ul>
     </div>
 }
 </body></html>

9.19. XSLT Files

An XSL Transform is a document utilizing XSLT which gives you the ability to transform XML documents into other formats such as HTML, plain text, or even a different XML structure. Transforms are extremely useful for restructuring data into a new format or serialization.

To create a transform click the "Create" button and select "Transform". Here you are presented with a text editor into which you can type your transform. Click "Create" and your Transform will be saved. You can go back at any point to Edit the Transform by selecting the "Edit" tab.

Pragma Description
?results Evaluates the transforms without an initial template
?results&initial-template=... Transforms the given initial templates, after loading it by URL, using this XSL transform
POST ?results Transforms the request body using this XSL transform

Take a look at the following XML and XSLT documents.


<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="example.xsl"?>
<Article>
  <Title>My Article</Title>
  <Authors>
    <Author>Mr. Foo</Author>
    <Author>Mr. Bar</Author>
  </Authors>
  <Body>This is my article text.</Body>
</Article>

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="text"/>

  <xsl:template match="/">
    Article - <xsl:value-of select="/Article/Title"/>
    Authors: <xsl:apply-templates select="/Article/Authors/Author"/>
  </xsl:template>

  <xsl:template match="Author">
    - <xsl:value-of select="." />
  </xsl:template>

</xsl:stylesheet>

This Transform capatures the title of the article and prints it out prepended with "Article - " by accessing the value located within the <title> tag using select="/Article/Title/". The same mechanism is used to access the authors of the article except since there are multiple values instead of simply obtaining the raw value it is passed along to a template for printing, as can be seen on the line showing <xsl:template match="Author">. Below is the text output from the transform.


Article - My Article
Authors:
- Mr. Foo
- Mr. Bar

This is obviously a very simple example but you can use these principles to start transforming your data however is necessary.

Example source: https://developer.mozilla.org/en-US/docs/XSLT_in_Gecko/Basic_Example

9.20. Domains

Callimachus Domains represent a set of network agents (i.e. all authenticated users). This differs from a User Group in that user groups are defined by named users whereas a Domain can be defined by more generalized attributes such as authenticated or unauthenticated.

Domains provide a way to assign resource permissions to a set of network agents which can simplify resource permissions. This can greatly help generalize resource permissions.

Upon creating a Domain you initially set only the Label and Description. Once the Domain is saved, you can select the "Edit" tab and set a number of new fields:

Field Description
Anonymous access from Reverse domain lookup suffix for agents that can interact with the resources without authentication. This can be used for resources you want to be publicly available.
Authenticated access from Reverse domain lookup suffix for authenticated agents that can interact with the resources. 
Deny access from Reverse domain lookup suffix for agents that cannot interface with the resources. This setting overrides other settings.

Examples of Domains within Callimachus can be found in /auth/groups/ and are:

  • everyone
    • Represents all authenticated users by setting Authenticated access from to . which signifies access is allowed from any network.
  • public
    • Represents all possible users (unauthenticated included) by setting Anonymous access from to .
  • system
    • Represents the local Callimachus system by setting Anonymous access from to localhost

9.21. Groups

A User Group is a collection of Callimachus users.

User Groups make it more convenient to grant users permissions to resources.

9.21.1. Default Groups

Permission groups exist within Callimachus to make the assignment of abilities to users easier. If a user belongs to that permission group, they are able to perform whatever functions are allowed by that group. There are currently eight different groups in Callimachus - each with a different purpose and level of ability. It is important to assign users to these groups carefully, ensuring that each user has only the minimum access necessary to perform their functions effectively.

Label Path Members Default permissions
public /auth/groups/public A virtual group of all agents Read-only access to the home folder
system /auth/groups/system A group of all IP addresses on the local machine Read-only access to the /callimachus/ folder
everyone /auth/groups/everyone A virtual group of all authenticated agents View and discuss resources in the home folder
users /auth/groups/users Empty list of users Document, link, and upload binary resources
staff /auth/groups/staff Empty list of users Design and code websites and develop applications
power /auth/groups/power Empty list of users Access all data in the underlying data store
admin /auth/groups/admin List of users, including the initial user Edit other user accounts and modify the underlying data store
super /auth/groups/super Nobody Modify /callimachus/ resources
9.21.2. Create a User Group

To create a User Group, select Group using the create menu from the folder you wish to create it in, then give the group a name and a description.

Warning: The group name cannot be changed once it has been created.

9.21.3. Adding Users

To allow group members access from any location list the members in the Members field.

9.22. SPARQL query

A named query is a SPARQL SELECT query that may be created and edited directly in Callimachus.

Named queries provide “result sets” or answers to questions asked using the SPARQL Query Language. The result sets can be visualized as pie charts, line charts, annotations on Google maps and so on.

9.22.1. Creating named queries

To create a named query, select Named query using the create menu from the folder you wish to store the named query in. You will be presented with the following initial code:

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

SELECT * {
}

The following pragmas will use additional query parameters when evaluating the query to produce the result.

Pragma Description
?sparql Responds with the actual SPARQL query used, after subsituting parameters with variables
?results Responds with the SPARQL results as XML
?results&tqx=out:html Formats the results into an HTML table
?results&tqx=out:csv Responds with the SPARQL results as CSV using UTF-8
?results&tqx=out:tsv-excel Responds with the SPARQL results as TSV using UTF-16LE
?results&tqx=out:sparql-json Responds with the SPARQL results as JSON
?results&tqx=out:table Responds with a JSON object with columns property of an array of variable names and rows property of an array of arrays of literals
?results&tqx=out:json Responds with the results formatted into Google's Chart protocol
?view Uses the query's view template (if annotated) to build the response markup
9.22.2. Example Named Query

Here is an example of a named query that shows pollution levels over time.

    PREFIX owl: <http://www.w3.org/2002/07/owl#>
    PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
    PREFIX tri: <http://usepa.3roundstones.net/id/us/fed/agency/epa/tri/schema/>
    PREFIX : <#>

    SELECT DISTINCT ?year ?pounds
    WHERE {
    ?tri_facility owl:sameAs <http://usepa.3roundstones.net/facilities/110000484039>
    ; tri:has_report ?report .

    ?report tri:reports_release_of ?chem
    ; tri:reporting_year ?year
    ; tri:released_to ?location .

    ?chem skos:prefLabel “$chemical” .

    ?location tri:amount_in_pounds ?pounds
    ; tri:environmental_medium <http://usepa.3roundstones.net/id/us/fed/agency/epa/tri/environmental_medium/AIR_STACK> .

    } order by ?year

Source: A Real-World Linked Open Data Story

9.23. RDF Turtle Graph

A graph is a set of RDF triples. A Callimachus graph document is an RDF document encoded as a Turtle file.

Graph documents are used to add RDF data to the Callimachus RDF database.

9.23.1. Creating a graph document

To create a graph document, select Graph document using the create menu from the folder you wish to store the graph document in. You will be presented with the following initial Turtle code:

@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rif: <http://www.w3.org/2007/rif#> .
@prefix skos: <http://www.w3.org/2004/02/skos/core#> .
@prefix skosxl: <http://www.w3.org/2008/05/skos-xl#> .
@prefix cc: <http://creativecommons.org/ns#> .
@prefix wdr: <http://www.w3.org/2007/05/powder#> .
@prefix void: <http://rdfs.org/ns/void#> .
@prefix msg: <http://www.openrdf.org/rdf/2011/messaging#> .
@prefix calli: <http://callimachusproject.org/rdf/2009/framework#> .
@prefix : <#> .
9.23.2. Sample Turtle file

Here is a sample turtle file:

@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix dc: <http://purl.org/dc/elements/1.1/> .
@prefix ex: <http://example.org/stuff/1.0/> .

<http://www.w3.org/TR/rdf-syntax-grammar>
  dc:title "RDF/XML Syntax Specification (Revised)" ;
  ex:editor [
    ex:fullname "Dave Beckett";
    ex:homePage <http://purl.org/net/dajobe/>
  ] .
9.23.3. Turtle syntax

Angle brackets are used to identify relative URLs, while colons outside of angle brackets identify a compact URI or a CURIE. The prefix before the colon is mapped to a namespace at the top and prepended to the remaining part after the colon. A comma separates multiple objects; a semicolon separates multiple relationships to to same subject; and a period marks the end of a subject.

For more information about the Turtle syntax see Turtle syntax for RDF.

9.24. RDF Datasources

An RDF Datasource is a SPARQL endpoint service that gives you the ability to define and access additional repositories within a single deployment. For example /sparql is the Datasource that gives you read/write access to the default Sesame repository that Callimachus uses. By creating a a new Datasource you are creating a new, empty Sesame native store within your Callimachus instance.

9.24.1. Creating an RDF Datasource

Steps for creating an RDF Datasource in Callimachus:

Field Description Sample Value
Label Value used for title of Datasource New Datasource
Comment Value used for description of Datasource. Appears in top right corner when viewing the Datasource. A new instance of a Datasource
SPARQL Query Whether or not the Datasource allows Read operations against it. Checked
SPARQL Update Whether or not the Datasource allows Write operations against it.  Checked

After clicking create you will be brought to a page viewing your new Datasource. From here you can perform any number of operations which are described in more detail in Using a Datasource.

9.24.2. Editing an RDF Datasource

Once an RDF Datasource has been created you can go back and edit any of the values you entered by selecting the "Edit" tab when viewing the RDF Datasource. You can change both the Label and the Comment as well as whether or not Read and Write operations can be performed against the Datasource.

Note: If you plan to use this RDF Datasource in Named Queries or Pipelines, be sure to set the the appropriate permissions under the Main menu by selecting "Permissions" and adding the "System" user to the "Editor" group. 

9.24.3. Deleting an RDF Datasource

You can delete an RDF Datasource at any time by navigating to the "Edit" tab of the desired RDF Datasource.

Warning! If you delete an RDF Datasource, any data you have loaded into it will also be deleted.

9.24.4. Using an RDF Datasource

Callimachus RDF Datasources expose all SPARQL 1.1 operations and most SPARQL Protocol and Graph Store HTTP Protocol (using indirect graph identification) requests. The most common operations you probably will find yourself using to get started are LOAD and SELECT. The interface is just a large textarea in which you can type your operations.

RDF Datasource can be accessed programatically via SERVICE clauses in SPARQL queries and XProc Pipelines, for example. Also, if you are working with a small dataset you can perform the following query to ensure the RDF Datasource is working as expected:

SELECT DISTINCT ?type WHERE { 
    ?thing a ?type 
} ORDER BY ?type LIMIT 50
Pragma Description
?uri=... Retrieves the Description of the provided resource
?query=... Evaluates the given SPARQL query
?graph=... Retrieves the given RDF graph

9.25. SQL Datasources

A SQL Datasource is an HTTP endpoint to access SQL data, using a provided JDBC driver. These resources only represent the connection setup and proxy HTTP requests/response to the remote SQL database managed externally.

From a folder view, choose "SQL Datasource" from the create menu. If you don't see it try scrolling down and check that your user is in the admin group and has accepted any outstanding invitations.

Field Description Example
Label The value will be used to compute the local part in the resulting endpoint A label of "TestDB" will have a local part of "testdb"
Comment Free text field used to describe author's intent for creating this
JDBC URL The syntax is specific to the driver being used, but always starts with jdbc: jdbc:mysql://localhost:3306/javatest
Driver class name The value is unique to the driver and provided by the vendor com.mysql.jdbc.Driver
Driver jar file The uploaded driver JAR provided by the vendor, should corespond to the version of the database mysql-connector-java-5.1.29-bin.jar
localhost to modify Indicates that the system can modify the data without further authentication This is useful when access the datasource via pipeline or PURL
Validation qurey A command sent to server prior to every request to ensure communication is open to remote database SELECT 1
Max active Limit the number of active concurrent connections to the remote database 100
Max idle Pool the connections, but don't keep more that this amount inactive. 30
Max wait When the Max active value is reached, wait this many miliseconds for one to become available before giving up 10000
9.25.1. Using SQL Datasource

The endpoint will only process a single command per request. Transactions are not supported. However, replacing the contents of a table is performed within a transaction. Below is a list of request types that are supported by a SQL Datasource /sql.

Description HTTP Method Query parameter Content-Type xor Accept header Example
Query the database using an arbitrary SELECT command GET query "text/csv;header=present", "text/tab-separated-values", or "application/sparql-results+xml"
GET /sql?query=SELECT%20*%20FROM%20%20Book
Accept: text/csv
Query or Modify the database using an arbitrary SQL command POST n/a application/sql
POST /sql
Content-type: application/sql

UPDATE example
 SET field1 = 'updated value'
 WHERE field2 = 'N';
Retrive the contents of a table GET table "text/csv;header=present", "text/tab-separated-values", or "application/sparql-results+xml"
GET /sql?table=example
Accept: text/csv
Replace the contents of a table PUT table "text/csv;header=present", "text/tab-separated-values", or "application/sparql-results+xml"
PUT /sql?table=Book
Content-Type: text/csv;header=present

title,authors
"SQL Examples and Guide",4
"The Joy of SQL",1
"An Introduction to SQL",2
Append the contents to a table POST table "text/csv;header=present", "text/tab-separated-values", or "application/sparql-results+xml"
POST /sql?table=Book
Content-Type: text/csv;header=present

title,authors
"Pitfalls of SQL",1
Drop a table DELETE table n/a
DELETE /sql?table=Book

9.26. Realms

A Realm in Callimachus is a folder hierarchy backed by an RDF store. Realms have their own authentication, credentials and layout options. Every Callimachus instance includes at least one Realm, which is also refered to as the home folder.

Pragma Description
?register Redirects to the authentication manager (if only one), or the manager in the choice parameter, or returns an HTML page listing the available managers
?login Redirects to the authentication manager (if only one), or the manager in the choice parameter, or returns an HTML page listing the available managers
?profile Redirects to the URI of the currently logged in user account
?logout Resets cookies and forces bogus credentials to replace any legitimate ones
?search Responds witha open search description file
?q Searches the labels of all the files and resources in this realm and responds with an HTML page or ATOM feed


Chapter 10. JavaScript Reference

Callimachus makes RDFa-aware DOM manipulation, Ajax, and other common usages easier with the provided functions below.

See Mozilla's JavaScript Reference for a reference to the language itself.

10.1. JavaScript Promises

Callimachus provides a Promise/A+ implementation. Promises are a lot like events, but a promise can only succeed or fail once and if a promise has succeeded or failed and later a success/failure callback is added, the correct callback will be called, even though the event took place earlier

10.1.1. calli.promise
Description

Returns a promise that is fulfilled when the provided resolve or reject function is called. Any errors thrown in the constructor callback will be implicitly passed to reject(error).

Signature

calli.promise(function(resolve,reject))
Parameter Description
resolve(obj) Function to call when a thenable or object fulfils this promise
reject(error) Function to call when this promise is rejected. For consistency and debugging (eg stack traces), obj should be an instanceof Error.
Example

calli.promise(function(callback){
    google.load('visualization', '1.0', {
        packages: ['core'],
        callback: callback
    });
}).then(function(){
    new google.visualization.ChartWrapper(options).draw();
}).then(undefined, calli.error);

10.1.2. calli.resolve
Description

Make a new promise from the parameter.

Signature

calli.resolve(thenable)

calli.resolve(obj)
Parameter Description
thenable A thenable is promise-like in as far as it has a "then" method. Make a new promise from the thenable.
obj Make a promise that fulfils to obj. in this situation.
Example

story.chapterUrls.reduce(function(sequence, chapterUrl) {
  // Add these actions to the end of the sequence
  return sequence.then(function(){
    return calli.getJSON(chapterUrl);
  }).then(function(chapter){
    addHtmlToPage(chapter.html);
  });
}, calli.resolve()); // Start off with a promise that always resolves

10.1.3. calli.reject
Description

Make a promise that rejects to error. For consistency and debugging (e.g. stack traces), error should be an instanceof Error.

Signature

calli.reject(error)
Parameter Description
error For consistency and debugging (e.g. stack traces), error should be an instanceof Error.
Example

calli.getJSON('story.json').then(function(story){
  return handleStory(story);
}, function(error){
  console.log(error);
  return calli.reject(error); // re-throw error
});

10.1.4. calli.all
Description

Make a promise that fulfils when every item in the array fulfils, and rejects if (and when) any item rejects. Each array item is passed to calli.resolve, so the array can be a mixture of promise-like objects and other objects. The fulfilment value is an array (in order) of fulfilment values. The rejection value is the first rejection value.

Signature

calli.all(arrayOfPromises)
Parameter Description
arrayOfPromises Array of promises, thenables, and/or results
Example

calli.all([img1.ready(), img2.ready()]).then(function(arrayOfResults) {
  // all loaded
}, function() {
  // one or more failed
});

10.1.5. calli.load
Description

Returns a promise that is fulfilled when the current page is loaded, including all images, styles, scripts, and iframes.

Signature

calli.load()

calli.load(obj)
Parameter Description
obj Object used to fulfil the promise
Example

calli.load().then(function(){
    $('p').text("The page is now loaded.");
});

10.1.6. calli.ready
Description

Returns a promise that is fulfilled when the current page DOM is loaded.

Signature

calli.ready()

calli.ready(obj)
Parameter Description
obj Object used to fulfil the promise
Example

calli.ready().then(function(){
    $('p').text("The DOM is now loaded and can be manipulated.");
});

10.1.7. calli.sleep
Description

Returns a promise that is fulfilled after the given number of milliseconds.

Signature

calli.sleep(milliseconds)
Parameter Description
milliseconds Number of milliseconds before this promises is fulfilled
Example

calli.sleep(10000).then(function(){
  alert("It has been at least ten seconds");
});

10.1.8. calli.error
Description

Displays the given error to the user and returns a rejected promise.

Signature

calli.error(error)

calli.error(error, details)
Parameter Description
error Error object, XMLHttpRequest, or message string
details string of more information
Example

$("#link").click(function(event) {
    event.preventDefault();
    var url = event.target.href;
    calli.getText(url).then(function(doc) {
        return handleLink(url, doc);
    }, calli.error);
});

10.2. DOM Manipulation

All of the functions in this section manipulate the DOM to facilitate RDFa modification for form submission.

10.2.1. calli.updateProperty
Description

Add a property attribute when the input, textarea, or option has a value and is active (selected or checked if applicable). This method can be used to ensure the value property is consistent with the RDFa attributes.

Signature

calli.updateProperty(event, property)
Parameter Description
event HTML event
property CURIE of the @property value
Example

<div class="form-group">
    <label for="label">Label</label>
    <input type="text" class="form-control" id="label" value="{rdfs:label}" required="required"
        onchange="calli.updateProperty(event, 'rdfs:label')" />
</div>

10.2.2. calli.updateResource
Description

Add a rel attribute when the input, textarea, or option has a value and is active (selected or checked if applicable). This method can be used to ensure the value property is consistent with the RDFa attributes.

Signature

calli.updateResource(event, rel)
Parameter Description
event HTML event
rel CURIE of @rel value
Example

<div class="form-group">
    <label for="support">Support</label>
    <div id="support">
        <div class="checkbox">
            <label>
                <input type="checkbox" name="support" resource="http://www.w3.org/ns/sparql-service-description#SPARQL11Query"
                    onchange="calli.updateResource(event, 'sd:supportedLanguage')" />
                <span>SPARQL Query</span>
            </label>
        </div>
        <div class="checkbox">
            <label>
                <input type="checkbox" name="support" resource="http://www.w3.org/ns/sparql-service-description#SPARQL11Update"
                    onchange="calli.updateResource(event, 'sd:supportedLanguage')" />
                <span>SPARQL Update</span>
            </label>
        </div>
    </div>
    <div class="hidden" rel="sd:supportedLanguage" resource="?support"></div>
    <script type="text/javascript">
        $('[rel="sd:supportedLanguage"].hidden').filter(calli.checkEachResourceIn('#support')).remove();
    </script>
</div>

10.2.3. calli.checkEachResourceIn
Description

Higher order function that returns a function for iterating over resources. This function will find radio and/or check boxes in the given container that match the resource provided, then mark it as checked and return it.

This is particularly useful when copying state from one set of elements to another.

Signature

calli.checkEachResourceIn(container)
Parameter Description
container DOM element or CSS selector of an element
Example

$('[rel="sd:supportedLanguage"].hidden').filter(calli.checkEachResourceIn('#support')).remove();

10.2.4. calli.selectEachResourceIn
Description

Higher order function that returns a function for iterating over resources. This function will find option elements in the given select container that match the resource provided, then mark it as selected and return it.

Signature

calli.selectEachResourceIn(container)
Parameter Description
container DOM element or CSS selector
Example

<div class="form-group">
    <label for="type1">Type</label>
    <xi:include href="types.rq?select&amp;rel=dcterms:type&amp;id=type&amp;multiple" />
    <div class="hidden" rel="dcterms::type" resource="?existingType" />
    <script type="text/javascript">
        $('[rel="dcterms:type"].hidden').filter(calli.selectEachResourceIn('#type')).remove();
    </script>
</div>

10.2.5. calli.addResource
Description

Appends an empty resource from the template to the container. If no container is provided the parent node is used.

Signature

calli.addResource(event)

calli.addResource(event, container)
Parameter Description
event HTML click event
container CSS selector of container element
Example

<div class="form-group">
    <label for="altLabel">Alternate label</label>
    <div>
        <input type="text" id="altLabel" property="skos:altLabel" content="?alt" value="{?alt}" class="form-control"
            onchange="calli.updateProperty(event, 'skos:altLabel')" />
        <a href="javascript:void(0)" title="More" onclick="calli.addResource(event)" class="glyphicon glyphicon-plus" />
    </div>
</div>


<div class="form-group">
    <label for="adr">Address <a href="javascript:void(0)" title="Another Address"
        onclick="calli.addResource(event,'#adr')" class="glyphicon glyphicon-plus" /></label>
    <div id="adr" rel="vcard:adr">
        <div typeof="vcard:Address">
            <input type="text" placeholder="street address" value="{vcard:street-address}" class="form-control"
                onchange="calli.updateProperty(event, 'vcard:street-address')" />
            <input type="text" placeholder="extended address" value="{vcard:extended-address}" class="form-control"
                onchange="calli.updateProperty(event, 'vcard:street-address')" />
            <input type="text" placeholder="po box" value="{vcard:post-office-box}" class="form-control"
                onchange="calli.updateProperty(event, 'vcard:street-address')" />
        </div>
    </div>
</div>

10.2.6. calli.removeResource
Description

Removes the target resources element from the DOM.

Signature

calli.removeResource(event)
Parameter Description
event HTML event
Example

<span about="?medium" typeof="skos:Concept" class="label label-info">
  <span property="skos:prefLabel" />
  <a href="{?medium}" title="Remove" onclick="calli.removeResource(event)" class="glyphicon glyphicon-remove" />
</span>

10.2.7. calli.insertResource
Description

Inserts an RDFa resource from the drop event. The new resource URI is read from the text/uri-list of the dropped data.

Signature
calli.insertResource(event)
Parameter Description
event HTML drop event
Example
<div id="related" dropzone="link string:text/uri-list" class="form-group"
        ondrop="calli.insertResource(event)">
    <label>Related</label>
    <div rel="skos:related">
        <span resource="?related" typeof="skos:Concept" class="label label-info">
            <span property="skos:prefLabel" />
        </span>
    </div>
</div>
// Or, create your own pseudo event
calli.insertResource(jQuery.extend(jQuery.Event('drop'), {
  target:$('#id-of-dropzone')[0],
  dataTransfer:{getData:function(){return url_of_resource}}
}));

10.3. Modal Dialogues

These functions open modal dialogues to the user, prompting them for information.

10.3.1. calli.selectResource
Description

Opens a modal box with an iframe to the given location (or the href property of the target element). When the user clicks on the select button, the dialogue is closed and a drop event is fired on the target element of the resource for the last view page shown.

Signature

calli.selectResource(event)

calli.selectResource(event, src)
Parameter Description
event HTML event
src http: URL to open
Example

<div id="subClassOf" dropzone="link string:text/uri-list" class="form-group col-sm-6"
        ondrop="calli.insertResource(event)">
    <label>Super <a href="/?view" title="Create"
            onclick="calli.selectResource(event)" class="glyphicon glyphicon-folder-open" /></label>
    <div rel="rdfs:subClassOf">
        <span resource="?subClassOf" typeof="owl:Class" class="label label-info">
            <span property="rdfs:label" />
            <a href="{?subClassOf}" title="Remove relationship" onclick="calli.removeResource(event)" class="glyphicon glyphicon-remove" />
        </span>
    </div>
</div>

10.3.2. calli.createResource
Description

Opens a modal box with an iframe to the given location (or the href attribute of the target element). When the user navigates to a view page, the dialogue is closed and a drop event is fired on the target element with the resource URL.

Signature

calli.createResource(event)

calli.createResource(event, src)
Parameter Description
event HTML click event
src URL of the page to display in the dialogue.
Example

<a href="Person?create" title="Create a Person"
      onclick="calli.createResource(event)"
      class="glyphicon glyphicon-list-alt" />

10.3.3. calli.promptForNewResource
Description

Opens a dialogue with an iframe of the namespace and an input box with the localPart. The user in then able to navigate and change each of them. When the user clicks on the save button of the dialogue, the returned promise is fulfilled with an object hash with container and slug as keys. The container is the resource URI of the last view page and the slug is the localPart of the input box when the user clicked on the save button. If the user clicks on the cancel button, the promise is fulfilled with undefined.

Signature
calli.promptForNewResource(container, slug)
Parameter Description
container URI of the folder or container resource
slug URI suffix after the namespace or slash
Example
$('#save').click(function(event){
    var text = $('#text').val();
    var btn = $(event.target);
    btn.button('loading');
    calli.promptForNewResource('./', 'untitled').then(function(hash){
        if (!hash) return undefined;
        var action = hash.container + '?create';
        return calli.postText(action, text, form.attr('enctype'), {Slug: hash.slug});
    }).then(function(redirect){
        btn.button('reset');
        if (redirect) window.location.href = redirect;
    }, function(error){
        btn.button('reset');
        return calli.error(error);
    });
});

10.4. Form Submission

A number of methods are provided to facilitate form submission.

10.4.1. calli.submitForm
Description

Submits the form to a hidden iframe and redirects the page to the URL of the response body. Any errors are displayed to the user.

Signature

calli.submitForm(event)
Parameter Description
event HTML submit event, which is cancelled
Example

<form role="form" method="POST" action="" enctype="multipart/form-data"
        onsubmit="calli.submitForm(event)">
    <div class="form-group">
        <label>File</label>
        <div>
            <input type="file" name="file" class="form-control" />
        </div>
    </div>
    <div class="form-group">
        <button type="submit" class="btn btn-primary">Upload</button>
    </div>
</form>

10.4.2. calli.submitFile
Description

Submits the contents of the first file of the form as an HTTP PUT request using the @enctype of the form as the Content-Type request header. The page is then redirected to the URL of the response body.

Signature

calli.submitFile(event)
Parameter Description
event HTML submit event to be cancelled
Example

<form role="form" method="PUT" action="?" enctype="image/png"
        onsubmit="calli.submitFile(event)">
    <fieldset>
    <div class="form-group">
        <label>Replacement file</label>
        <div>
            <input type="file" class="form-control" accept="image/png" />
        </div>
    </div>
    <button type="submit" class="btn btn-primary">Replace</button>
</form>

10.4.3. calli.copyResourceData
Description

Parses the RDFa of the element and returns a copy of the data in an object.

Signature

calli.copyResourceData(element)
Parameter Description
element DOM element or CSS selector of one
Example

<body resource="?this" onload="comparison=calli.copyResourceData('#form')">
        <form id="form" role="form" method="POST" action="" enctype="application/sparql-update" resource="?this" class="row"
                onsubmit="calli.submitUpdate(comparison,event)">

10.4.4. calli.submitTurtle
Description

Add a resource attribute to the form of the local parameter value. Reads the RDFa data of the target form and serializes it as text/turtle in an HTTP POST request body. The page is then redirected to the response body URL.

Signature
calli.submitTurtle(event)
calli.submitTurtle(event, local)
Parameter Description
event HTML submit event, to be cancelled
local Optional local name of the resource to be assigned to the @resource of the form
Example
<form role="form" method="POST" action="" enctype="text/turtle" resource="" typeof=""
    onsubmit="calli.submitTurtle(event,calli.slugify($('#label').val()))">

10.4.5. calli.submitTurtleAs
Description

Prompts the user to adjust the folder and localPart, then parses the RDFa of the target form (as the chosen resource) and serializes it as text/turtle in an HTTP POST request body. The page is then redirected to the response body URL.

Signature

calli.submitTurtleAs(event, localPart, create, folder)
Parameter Description
event HTML event
localPart The suggested local name of the resource
create The class IRI that this resource is an instance of
folder The suggested target namespace for the resource
Example

<head>
    <title resource="?this">{skos:prefLabel}</title>
    <link id="type" href="../classes/Concept" />
</head>
<body resource="?this" onload="comparison=calli.copyResourceData('#form')">
    <form role="form" id="form" method="POST" action="" enctype="application/sparql-update"
            resource="?this" typeof="skos:Concept" onsubmit="calli.submitUpdate(comparison, event)">
        <div class="form-group">
            <label for="label">Label</label>
            <div>
                <input type="text" id="label" value="{skos:prefLabel}" class="form-control"
                    onchange="calli.updateProperty(event, 'skos:prefLabel')" />
            </div>
        </div>
        <button id="save" type="submit" class="btn btn-primary">Save</button>
        <button id="saveas" type="button" class="btn btn-info"
            onclick="calli.submitTurtleAs(event, calli.slugify($('#label').val()), $('#type').attr('href'), './')">Save as...</button>
        <button id="cancel" type="button" onclick="window.location.replace('?view')" class="btn btn-default">Cancel</button>
        <button id="delete" type="button" onclick="calli.deleteResource(event)" class="btn btn-danger">Delete</button>
    </form>
</body>

10.4.6. calli.submitUpdate
Description

Parses the target form's RDFa data and submits application/sparql-update of the difference with the parameter. Then replaces the current page with the response body URL.

Signature

calli.submitUpdate(comparedData, event)
Parameter Description
comparedData Data previously returned from calli.copyResourceData
event HTML submit event, to be cancelled
Example

<body resource="?this" onload="comparison=calli.copyResourceData('#form')">
    <form id="form" role="form" method="POST" action="" enctype="application/sparql-update" resource="?this"
            onsubmit="calli.submitUpdate(comparison,event)">
        <div class="form-group">
            <label for="label">Label</label>
            <input type="text" class="form-control" id="label" value="{rdfs:label}"
                onchange="calli.updateProperty(event, 'rdfs:label')" />
        </div>
        <button type="submit" class="btn btn-primary">Save</button>
    </form>
</body>

10.4.7. calli.deleteResource
Description

Issues a HTTP DELETE request to the current resource (i.e. current form action target). If the request is successful the browser page is replaced by the URL in the response body, usually the resource's container.

Signature

calli.deleteResource(event)
Parameter Description
event HTML click event
Example

<form id="form" role="form" method="POST" action="" enctype="application/sparql-update" resource="?this"
        onsubmit="calli.submitUpdate(comparison,event)">
    <button type="button" onclick="calli.deleteResource(event)" class="btn btn-danger">Delete</button>
</form>

10.4.8. calli.postForm
Description

Submits the form to a hidden iframe and returns a promise of the response body URL or rejects the document as an object with a message.

Signature

calli.postForm(form)
Parameter Description
form HTML form element or a CSS selector
Example

$('#form').submit(function(event) {
    event = calli.fixEvent(event);
    event.preventDefault();
    var form = event.target;
    var btn = $(form).find('button[type="submit"]');
    btn.button('loading');
    return calli.postForm(form).then(function(redirect){
        return redirect && redirect + "?view";
    }).then(function(redirect){
        window.location.href = redirect;
    }, function(error) {
        btn.button('reset');
        return calli.error(error);
    });
});

10.4.9. calli.postTurtle
Description

Issues an HTTP POST request to the given URL with the given data formatted as turtle. Returns a promise of the response body, or rejects the XMLHttpRequest object.

Signature
calli.postTurtle(url, data, headers)
Parameter Description
url http: URL
data Object previously returned by calli.copyResourceData
headers Optional hash of header name and value
Example
calli.copyResourceData('#form').then(function(data){
    return calli.postTurtle($('#form').prop('action'), data);
}).then(function(redirect){
    window.location.replace(redirect);
}, calli.error);

10.4.10. calli.postUpdate
Description

Issues an HTTP POST request to the given URL with the difference between the given datasets as SPARQL-update. Returns a promise of the response body, or rejects the XMLHttpRequest object. Triples that appear in both the deleteData and insertData arguments will not be included in the update.

Signature

calli.postUpdate(url, deleteData, insertData)
Parameter Description
url http: URL
deleteData Data (previously returned from calli.copyResourceData) to be removed in update
insertData Data (previously returned from calli.copyResourceData) to be inserted in update
Example

calli.ready().then(function(){
  var comparison = calli.copyResourceData('#form');
  $('#form').submit(function(event){
    var insertData = calli.copyResourceData(event.target);
    calli.postUpdate(event.target.action, comparison, insertData).then(function(redirect){
      return window.location.replace(redirect);
    }, calli.error);
  });
});

10.5. Ajax

These functions allow data to be loaded from the server without a browser page refresh.

Many of these functions track the Last-Modification response header for use with conditional requests. This can be used to ensure multiple users don't overright each other's changes.

10.5.1. calli.headText
Description

Issues an HTTP HEAD request to the given URL. Returns a promise of the empty response body, or rejects the XMLHttpRequest object.

Signature

calli.headText(url)
Parameter Description
url http: URL
Example

calli.headText(uri).then(function() {
    if (confirm("Replace it?"))
        return replaceResource(uri);
}, function(xhr){
    if (xhr.status == 404)
        return createResource(uri);
    return calli.error(xhr);
});

10.5.2. calli.getText
Description

Issues an HTTP GET request to the given URL and returns a promise of the response body, or rejects the XMLHttpRequest object.

Signature

calli.getText(url)
Parameter Description
url http: URL
Example

$("#link").click(function(event) {
    event.preventDefault();
    var url = event.target.href;
    calli.getText(url).then(function(doc) {
        return handleLink(url, doc);
    }, calli.error);
});

10.5.3. calli.getJSON
Description

Issues an HTTP GET request to the given URL and returns a promise of the parse JSON response body, or rejected the XMLHttpRequest object.

Signature

calli.getJSON(url)
Parameter Description
url http: URL
Example

calli.getJSON($('#menu-json').prop('href')).then(showMenu).then(undefined, calli.error);

10.5.4. calli.getXML
Description

Issues an HTTP GET request to the given URL and returns a promise of the parse XML response body document, or rejects the XMLHttpRequest object.

Signature

calli.getXML(url)
Parameter Description
url http: URL
Example

var url = $('link[rel="contents"]').attr('href');
calli.getXML(url).then(calli.ready).then(function(doc) {
    var results = $(doc.documentElement).children();
    var totalResults = results.length;
    $('#totalResults').text(totalResults);
    $('#results').append(results);
});

10.5.5. calli.postText
Description

Issues an HTTP POST request to the given URL with the given payload. Returns a promise of the response body, or rejects the XMLHttpRequest object.

To issue a conditional request, use calli.updateText.

Signature
calli.postText(url, data, contentType, headers)
Parameter Description
url http: URL
data String of request body
contentType Content-Type request header value
headers Optional hash of header name and value
Example
$('#form').submit(function(event){
    calli.postText(event.target.action, $(form).serialize(), "application/x-www-form-urlencoded").then(function(data){
        var content = $(data).find('#content');
        $('#result').empty().append(content);
    });
});

10.5.6. calli.updateText
Description

Issues a conditional HTTP POST request to the given URL with the given payload. Returns a promise of the response body, or rejects the XMLHttpRequest object.

This method uses a conditional request to ensure the target resource has not been modified, since it was last read. Use calli.postText to issue an unconditional request.

Signature

calli.updateText(url, data, contentType)
Parameter Description
url http: URL
data String of the request body
contentType Content-Type request header
Example

$('#form').submit(function(event){
    calli.updateText(event.target.action, $(form).serialize(), "application/x-www-form-urlencoded").then(function(data){
        window.location.reload();
    }, function(xhr){
        alert("Resource has since been modified");
    });
});

10.5.7. calli.putText
Description

Issues a conditional HTTP PUT request to the given URL with the given payload. Returns a promise of the empty response body, or rejects the XMLHttpRequest object.

Signature

calli.putText(url, data, contentType)
Parameter Description
url http: URL
data string of the request body
contentType Content-Type request header value
Example

$('#form').submit(function(event){
  event.preventDefault();
  var text = $('textarea').val();
  calli.putText(event.target.action, text, 'text/plain').then(function(){
    window.location.reload();
  }, calli.error);
});

10.5.8. calli.deleteText
Description

Issues a conditional HTTP DELETE request to the given URL. Returns a promise of the empty 204 response body, or rejects the XMLHttpRequest object.

Signature

calli.deleteText(url)
Parameter Description
url http: URL
Example

$('#delete').click(function(event){
    if (confirm("Are you sure you want to delete " + document.title + "?")) {
        calli.deleteText(event.target.form.action).then(function(){
            window.location.replace('./');
        }).then(undefined, calli.error);
    }
});

10.5.9. calli.lastModified
Description

Retrieves or sets the last modification date for this resource (local to this browser session).

Signature

calli.lastModified(resource)

calli.lastModified(resource, modified)
Parameter Description
resource String URL or IRI of the resource
modified String of the Last-Modified response header value
Example

var xhr = $.ajax({
    type: "PUT",
    url: url,
    contentType: "text/plain",
    data: data,
    headers: {
        "If-Unmodified-Since": calli.lastModified(url)
    },
    success: function() {
        calli.lastModified(url, xhr.getResponseHeader('Last-Modified'));
    }
});

10.6. Document Editors

A number of document editors are provided. Below is a list of JavaScript functions that can be used to initialize and submit the editor's' contents.

10.6.1. calli.initEditor
Description

Called once the editor has loaded into an iframe and initializes the content of the editor.

Signature

calli.initEditor(event, text)
Parameter Description
event HTML iframe load event
text Initial content to load into editor
Example

<pre id="template" class="hidden"><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>Untitled Article</title>
  </head>
  <body>
    <h1>Untitled Article</h1>
    <p>&#160;</p>
  </body>
</html>]]></pre>
<iframe src="/callimachus/document-editor.html"
    onload="calli.initEditor(event,$('#template').text())"> </iframe>

10.6.2. calli.loadEditor
Description

Called once the editor has initialized to load the remote document content into the editor.

Signature

calli.loadEditor(event, url)
Parameter Description
event HTML iframe load event
url Document URL to be loaded into the editor
Example

<iframe src="/callimachus/document-editor.html" onload="calli.loadEditor(event,'doc.xhtml')"></iframe>

10.6.3. calli.readEditorText
Description

Returns a promise of the contents of the editor.

Signature

calli.readEditorText(editorWindow)
Parameter Description
editorWindow contentWindow of the editor
Example

$('#form').submit(function(event){
    event.preventDefault();
    var form = $(event.target);
    var btn = form.find('button[type="submit"]');
    btn.button('loading');
    return calli.resolve().then(function(){
        var editor = form.find('iframe')[0].contentWindow;
        return calli.readEditorText(editor);
    }).then(function(text) {
        return calli.putText(form.prop('action'), text, form.attr('enctype'));
    }).then(function(){
        btn.button('reset');
    }, function(error) {
        btn.button('reset');
        return calli.error(error);
    });
});

10.6.4. calli.submitEditor
Description

Saves or creates the document resource using the contents of the editor in the first iframe of the target form. If a local resource is provided, a POST request is sent to the form action, otherwise a PUT request is sent to the form action with a resource query parameter of the local value appended.

Signature

calli.submitEditor(event)

calli.submitEditor(event, local)
Parameter Description
event HTML submit event
local Name of the resource to be created
Example

<form role="form" method="POST" action="" enctype="application/xhtml+xml"
        onsubmit="calli.submitEditor(event, $('#local').val())">
    <fieldset class="form-group">
        <div>
            <input id="local" type="text" class="form-control" value="untitled.docbook" />
        </div>
    </fieldset>
    <fieldset class="form-group">
        <iframe src="/callimachus/document-editor.html"
            onload="calli.initEditor(event,'')"> </iframe>
    </fieldset>
    <fieldset class="form-group">
        <button type="submit" class="btn btn-success">Create</button>
    </fieldset>
</form>

10.6.5. calli.submitEditorAs
Description

Prompts the user as to where and what to save the editor contents as.

Signature

calli.submitEditorAs(event, local, create, folder)
Parameter Description
event HTML submit event
local Suggested local name of the resource to save
create URI of the type of resource to save
folder Suggested location of the resource to save
Example

<form role="form" method="PUT" action="doc.xhtml" enctype="application/xhtml+xml"
        onsubmit="calli.submitEditor(event)">
    <iframe src="/callimachus/document-editor.html" onload="calli.loadEditor(event,'doc.xhtml')"></iframe>
    <fieldset class="form-group">
        <button type="submit" class="btn btn-primary">Save</button>
        <button id="saveas" type="button" class="btn btn-info"
            onclick="calli.submitEditorAs(event, 'untitled.docbook', '/callimachus/1.4/types/Article', './')">Save as...</button>
        <button type="button" onclick="window.location.replace('?view')" class="btn btn-default">Cancel</button>
        <button type="button" onclick="calli.deleteResource(event)" class="btn btn-danger">Delete</button>
    </fieldset>
</form>

10.7. Authentication

While the authentication system is pluggable, the browser authentication state can be accessed and changed via these functions.

10.7.1. calli.getCurrentUserAccount
Description

Returns a promise of the authenticated user's account IRI or undefined, if the user is not authenticated.

Signature

calli.getCurrentUserAccount()
Example

calli.getCurrentUserAccount().then(function(iri){
    return $('#menu-json').prop('href') + encodeURIComponent(iri);
}).then(function(url){
    return calli.getJSON(url);
}).then(function(json) {
    return showUserMenu(json);
}).then(undefined, calli.error);

10.7.2. calli.getCurrentUserName
Description

Returns a promise of the authenticated user's username, or undefined if the user is not authenticated.

Signature

calli.getCurrentUserName()
Example

calli.getCurrentUserName().then(function(username){
    if (username)
        alert('Welcome ' + username);
    else
        altert('Please login');
});

10.7.3. calli.login
Description

Called to indicate the current user is now authenticated with the provider and the their authentication state should be updated.

Signature

calli.login(username)
Parameter Description
username The username or email address that was used to authenticate the user
Example

postCredentials().then(function(){
    calli.login("john");
});

10.7.4. calli.logout
Description

Gracefully de-authenticates the current user. While this method removes the current login state, there may still exist authentication cookies left by the authentication provider that may still need to be remove, potentially along with remote provide authentication states.

Signature

calli.logout()
Example

calli.logout().then(function(){
    window.location.replace('./');
});

10.8. Utilities

10.8.1. calli.slugify
Description

Returns a string suitable for use in a URL path segment. This returns a string made of the alpha-numeric characters and the following characters.

- . _ ~  ! $ & ' ( ) * + , ; =
Signature
calli.slugify(title)
Parameter Description
title Any string
Example
<form role="form" method="POST" action="" enctype="text/turtle" resource="" typeof=""
        onsubmit="calli.submitTurtle(event,calli.slugify($('#label').val()))">
    <div class="form-group">
        <label for="label">Label</label>
        <input type="text" class="form-control" id="label" value="{rdfs:label}" required="required"
            onchange="calli.updateProperty(event, 'rdfs:label')" />
    </div>
    <button type="submit" class="btn btn-success">Create</button>
</form>

10.8.2. calli.parseDateTime
Description

Returns a new Date object set to the number of milliseconds since January 1, 1970 00:00:00 UTC and the point in time represented by the argument.

Signature

calli.parseDateTime(isoDateString)

calli.parseDateTime(formattedDateString)

calli.parseDateTime(timeElement)
Parameter Description
isoDateString Date time string in the ISO 8601 format, such as 2011-10-10T14:48:00Z
formattedDateString Date time string in the RFC 822 format, such as Mon, 25 Dec 1995 13:30:00 GMT
timeElement The time string is read from the element's datetime attribute
Example

Created at <time id="created" datetime="{dcterms:created}" />
<script type="text/javascript">
$('#created').text(function(){
    return calli.parseDateTime(this).toLocaleString();
});
</script>

10.8.3. calli.compareElementsBy
Description

Higher order function that returns an element comparator for use with Array sort or similar. The comparator will sort the elements using the natural numeric or alpha sort of the elements text content, unless a parameter is provided.

Signature

calli.compareElementsBy()

calli.compareElementsBy(selector)

calli.compareElementsBy(valueOfFunction)
Parameter Description
selector The comparator will sort the elements using the natural numeric or alpha sort by the text content of each of their first descending element matching the given CSS selector.
valueOfFunction The comparator will sort the elements using the natural sort of the valueOfFunction(element).
Example

<ul id="members">
    <li rel="calli:member" resource="?member">
        <a href="?member" property="rdfs:label" />
    </li>
</ul>
<script type="text/javascript">
    $('#members li').sort(calli.compareElementsBy('a')).appendTo('#members');
</script>

10.8.4. calli.isEmptyResource
Description

Returns false if the element or any of its descendants have RDFa attributes, otherwise returns true.

Signature
calli.isEmptyResource()
calli.isEmptyResource(element)
Parameter Description
element DOM element, if not an objects defaults to this
Example
<script type="text/javascript">
    $('aside').filter(calli.isEmptyResource).remove();
</script>

10.8.5. calli.parseCreole
Description

Formats the provided wiki text as a DOM element and returns it.

Signature

calli.parseCreole(wiki)

calli.parseCreole(element)
Parameter Description
wiki Wiki text string
element Element such as pre or script, with wiki text content
Example

<p property="rdfs:comment" />
<script type="text/javascript">
    jQuery(function($){
        $('pre[property]').replaceWith(calli.parseCreole);
    });
</script>

10.8.6. calli.fillElement
Description

Expand the element's width and height to fill the available screen.

Signature

calli.fillElement(element)
Parameter Description
element DOM element or CSS selector
Example

<script type="text/javascript">
    $(function() {
        calli.fillElement('iframe');
    });
</script>


Chapter 11. XProc Reference

XProc is a W3C recommended XML Pipeline Language.

Callimachus provides the following steps that can be used by importing the /callimachus/library.xpl file. <p:import href="/callimachus/library.xpl" />

11.1. calli:decode-text

The calli:decode-text step removes encoding of text. This step behaves like p:unescape-markup, but only decodes it and does not convert text to XML.


<p:declare-step type="calli:decode-text">
    <p:input port="source" sequence="true" primary="true" />
    <p:option name="content-type" select="'text/plain'"/>
    <p:option name="encoding"/>
    <p:option name="charset"/>
    <p:output port="result" sequence="true" />
</p:declare-step>
Option Description Example
content-type The content-type of the data to be decoded application/sparql
charset The character set of the encoded text UTF-8
encoding

One of the following encodings

  • base64
  • base32
  • hex
  • binary
  • quoted-printable
  • www-form-urlencoded
base64

11.2. calli:render-html

The calli:render-html step populates a template using RDF data. The data is retrived using the calli:sparql step.


<p:declare-step name="render-html" type="calli:render-html">
    <p:serialization port="result" media-type="text/html" method="html" doctype-system="about:legacy-compat" />
    <p:input port="source" sequence="true" primary="true" />
    <p:input port="parameters" kind="parameter" primary="true" />
    <p:input port="query" sequence="false" />
    <p:input port="template" sequence="false" />
    <p:output port="result" sequence="true" primary="true" />
    <p:option name="output-base-uri" select="''" />
    <p:option name="endpoint" select="''" />
</p:declare-step>

The RDF data can be provided in the source port as RDF/XML or with the provided SPARQL endpoint.

The SELECT query (and its parameters) are used to select the (exactly one) variable and zero or more bindings. The actualy SPARQL Query sent to the endpoint will be created as a combination of the provided query and the properties and relationships referenced in the template.

11.3. calli:sparql

The calli:sparql step produces application/sparql-results+xml from RDF data.


<p:declare-step type="calli:sparql">
    <p:input port="source" sequence="true" primary="true" />
    <p:input port="query" sequence="true" />
    <p:input port="parameters" kind="parameter" primary="true"/>
    <p:option name="output-base-uri" />
    <p:option name="endpoint" />
    <p:output port="result" sequence="true" />
</p:declare-step>

The RDF data can be provided in the source port as RDF/XML or with the provided SPARQL endpoint.

The SELECT parameters are populated in the query before evaluating the query against the data source.


Chapter 12. XQuery Reference

XQuery is a W3C recommended XML Query Language.

Callimachus provides the following functions that can be used by importing the /callimachus/layout-functions.xq file. import module namespace calli = "http://callimachusproject.org/rdf/2009/framework#" at "/callimachus/layout-functions.xq";

12.1. calli:head-nodes

Copies the XML nodes from the template's <head> element.


<head>
    {calli:head-nodes()}
</head>

12.2. calli:body-attributes

Copies the template's body attributes. It is important that this function be called directly after an element start tag, although some whitespace is permitted.


<head>
    {calli:head-nodes()}
</head>
<body>
    {calli:body-attributes()}
    <div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
    </div>
</body>

12.3. calli:body-nodes

Copies all the template's body XML nodes.


<div>
    {calli:body-nodes()}
</div>

12.4. calli:head-links

Copies the @href and other links from the template's <link> element that include a @title. The attributes are copied to the first given element and the @title is used as the content. The second given element is also returned if the template has titled <link> elements at all.


<menu type="list">
    {calli:head-links(<li><a /></li>,<li class="divider" />)}
</menu>

12.5. calli:styles-href

Adds an @href, of the default style sheet, to the given element.


{calli:styles-href(<link rel="stylesheet" />)}

12.6. calli:scripts-src

Adds @src, of the default script bundle, to the given element.


{calli:scripts-src(<script type="text/javascript" />)}

12.7. calli:lookup-form

Returns an HTML search form, searching the current realm, with the given string as a placeholder.


<div class="pull-right hidden-logout">{calli:lookup-form('Lookup...')}</div>

12.8. calli:breadcrumb-list

Creates a placeholder for breadcrumbs that will use the given list element. List items with links and text content will be added to the given list element.

{calli:breadcrumb-list(<ol class="breadcrumb navbar-left hidden-iframe"></ol>)}

12.9. calli:activate-nav

Create a placeholder element that will add @class="active" and remove @href and @onclick, to any <a> element with a @href of the query string (starting with '?').


{calli:activate-nav(<nav class="nav nav-tabs">
    <li><a href="?view">View</a></li>
    <li><a href="?edit">Edit</a></li>
</nav>)}

12.10. calli:lastmod-time

Create a place holder element that will subsitute the <time> element within the given element with the last modification timestamp of the resource, or nothing if unknown.


<footer>
    {calli:lastmod-time(<p>This resource was last modified at <time class="abbreviated"/></p>)}
</footer>

12.11. calli:error-alert

Creates an error template that will be used by calli.error. An error message is appended to a copy of the given element.


{calli:error-alert(<div class="alert alert-error alert-block alert-dismissable">
    <button type="button" class="close" data-dismiss="alert">&#215;</button>
    <h4>Oops!</h4>
</div>)}

12.12. calli:generator-p

Appends markup about Callimachus to the given element.


<footer>
    {calli:generator-p(<p class="pull-right" />)}
</footer>

12.13. calli:home-href

Adds an @href to the given element that links to the home folder's directory target.


<header>
    {calli:home-href(<a>Callimachus</a>)}
</header>

12.14. calli:folder-href

Adds an @href to the given element for the view page of the home folder.


<ul role="menu" class="dropdown-menu">
    <li>{calli:folder-href(<a>Home folder</a>)}</li>
</ul>

12.15. calli:changes-href

Adds an @href to the give element that links to the recent changes for the current realm.


<div class="btn-group">
    <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">Menu</a>
    <ul class="dropdown-menu" role="menu">
        <li>{calli:folder-href(<a>Home folder</a>)}</li>
        <li>{calli:changes-href(<a>Recent changes</a>)}</li>
    </ul>
</div>

12.16. calli:view-href

Adds @href to the given element that links to the view page of the current resource.


<ul class="nav nav-tabs">
    <li>{calli:view-href(<a>View</a>)}</li>
    <li>{calli:edit-href(<a>Edit</a>)}</li>
    <li>{calli:discussion-href(<a>Discussion</a>)}</li>
    <li>{calli:describe-href(<a>Describe</a>)}</li>
    <li>{calli:history-href(<a>History</a>)}</li>
</ul>

12.17. calli:edit-href

Adds @href to the given element that links to the edit page of the current resource.


<ul class="nav nav-tabs">
    <li>{calli:view-href(<a>View</a>)}</li>
    <li>{calli:edit-href(<a>Edit</a>)}</li>
    <li>{calli:discussion-href(<a>Discussion</a>)}</li>
    <li>{calli:describe-href(<a>Describe</a>)}</li>
    <li>{calli:history-href(<a>History</a>)}</li>
</ul>

12.18. calli:discussion-href

Adds @href to the given element that links to the discussion page of the current resource.


<ul class="nav nav-tabs">
    <li>{calli:view-href(<a>View</a>)}</li>
    <li>{calli:edit-href(<a>Edit</a>)}</li>
    <li>{calli:discussion-href(<a>Discussion</a>)}</li>
    <li>{calli:describe-href(<a>Describe</a>)}</li>
    <li>{calli:history-href(<a>History</a>)}</li>
</ul>

12.19. calli:describe-href

Adds @href to the given element that links to the describe page of the current resource.


<ul class="nav nav-tabs">
    <li>{calli:view-href(<a>View</a>)}</li>
    <li>{calli:edit-href(<a>Edit</a>)}</li>
    <li>{calli:discussion-href(<a>Discussion</a>)}</li>
    <li>{calli:describe-href(<a>Describe</a>)}</li>
    <li>{calli:history-href(<a>History</a>)}</li>
</ul>

12.20. calli:history-href

Adds @href to the given element that links to the history page of the current resource.


<ul class="nav nav-tabs">
    <li>{calli:view-href(<a>View</a>)}</li>
    <li>{calli:edit-href(<a>Edit</a>)}</li>
    <li>{calli:discussion-href(<a>Discussion</a>)}</li>
    <li>{calli:describe-href(<a>Describe</a>)}</li>
    <li>{calli:history-href(<a>History</a>)}</li>
</ul>

12.21. calli:whatlinkshere-href

Adds @href to the give element that links to the what-links-here page of the current resource.


{calli:whatlinkshere-href(<a>What links here</a>)}

12.22. calli:relatedchanges-href

Adds @href to the given element that links to the related changes page of the current resource.


{calli:relatedchanges-href(<a>Related changes</a>)}

12.23. calli:permissions-href

Adds @href to the given element that links to the permission page of the current resource.


{calli:permissions-href(<a>Permissions</a>)}

12.24. calli:introspect-href

Adds @href to the given element that links to the introspect page of the current resource.


{calli:introspect-href(<a>Introspect resource</a>)}

12.25. calli:admin-href

Adds the href attribute to the given a element to the user group administration page.


<p>
    To Invite a new user open the {calli:admin-href(<a class="btn btn-default">group adminstration page</a>)}!
</p>

12.26. calli:login-href

Adds attributes to the given element that are needed to activate the login process.


<div class="hidden-login">
    {calli:login-href(<a class="btn btn-default navbar-btn">Sign in <span class="glyphicon glyphicon-log-in" /></a>)}
</div>

12.27. calli:profile-href

Adds attributes to the given element that will link to the current user's identifier/profile page. The content of the element will be replace.


{calli:profile-href(<a>My account</a>)}

12.28. calli:logout-href

Adds attributes to the given element that will initiate the logout sequence when clicked.


{calli:logout-href(<a>Sign out</a>)}

Chapter 13. SPARQL Reference

SPARQL is a W3C recommended query language for RDF.

13.1. keyword:phone

All of the words in the values of the listed properties will also be indexed using the predicate keyword:phone that can be used to search for resources by label word.


PREFIX keyword:<http://www.openrdf.org/rdf/2011/keyword#>

SELECT ?resource
WHERE {
    ?resource keyword:phone ?soundex
    FILTER sameTerm(?soundex, keyword:soundex("example"))
    FILTER EXISTS { ?resource ?p ?term FILTER regex(?term, keyword:regex("example")) }
}

13.2. keyword:soundex

The keyword:soundex SPARQL function converts the given string into a soundex code (comatible with keyword:phone).

13.3. keyword:regex

The keyword:regex SPARQL function provides a accent/case-insensitive regular expression that can be used to further filter the match.

13.4. List of searched labels

The following RDF properties may be searched.

Common QName URI
og:title http://ogp.me/ns#title
dc:title http://purl.org/dc/elements/1.1/title
dcterms:title http://purl.org/dc/terms/title
gr:legalName http://purl.org/goodrelations/v1#legalName
rss:title        http://purl.org/rss/1.0/title
fb:type.object.name        http://rdf.freebase.com/ns/type.object.name
sioc:name http://rdfs.org/sioc/ns#name
gn:alternateName http://www.geonames.org/ontology#alternateName
gn:name http://www.geonames.org/ontology#name
gn:officialName http://www.geonames.org/ontology#officialName
gn:shortName        http://www.geonames.org/ontology#shortName
rdfs:label http://www.w3.org/2000/01/rdf-schema#label
skos:altLabel http://www.w3.org/2004/02/skos/core#altLabel
skos:hiddenLabel http://www.w3.org/2004/02/skos/core#hiddenLabel
skos:prefLabel http://www.w3.org/2004/02/skos/core#prefLabel
vcard:additional-name        http://www.w3.org/2006/vcard/ns#additional-name
vcard:family-name http://www.w3.org/2006/vcard/ns#family-name
vcard:fn http://www.w3.org/2006/vcard/ns#fn
vcard:given-name http://www.w3.org/2006/vcard/ns#given-name
vcard:label http://www.w3.org/2006/vcard/ns#label
vcard:nickname http://www.w3.org/2006/vcard/ns#nickname
vcard:organization-name http://www.w3.org/2006/vcard/ns#organization-name
vcard:organization-unit http://www.w3.org/2006/vcard/ns#organization-unit
skosxl:literalForm http://www.w3.org/2008/05/skos-xl#literalForm
foaf:name        http://xmlns.com/foaf/0.1/name

Chapter 14. Callimachus REST API

Most Callimachus features may be accessed via REST API calls, which makes it easy to integrate Callimachus with other applications.

This chapter provides a summary of features available via REST, examples of usage, and programmatic guidance for developers.

14.1. About the Callimachus REST API

REpresentational State Transfer (REST) is a resource-oriented architectural style commonly used on the World Wide Web.

RESTful manipulation of resources in Callimachus requires some caveats. Readers may think of some kinds of content as "file" oriented, such as a HTML or plain text file, a JPEG image or a Javascript document, and other types of more conceptual content as "data" or "metadata", such as a user, group, menu definition or concept. Callimachus' REST API makes similar distinctions between Binary Large Object (BLOB) content and RDF content; however, the distinctions are not always as you might expect. How should we treat an RDF document that is uploaded to Callimachus, represented as a "file" in Callimachus' folder interface and yet whose contents are stored in an RDF database? Appendices B: BLOB Resource Types and C: RDF Resource Types list the various content types in Callimachus and associates them with the appropriate segments of the API. Please read carefully :)

Examples are provided that use a fictitious Callimachus authority (http://example.com:8080), fictitious URL paths, and fictitious parameters. This is intentional to encourage you to discover the correct URLs in accordance with this documentation. Any specific URL patterns we might otherwise document would be subject to change in future releases. Keep in mind that the service URLs may be on different hosts than the requested URI. You will thus not be able to copy-and-paste the examples directly into your browser; you will need to change the examples to match your environment. Examples requiring authentication show a username of "john"; your name may be different, so you will need to modify them as appropriate for your Callimachus username.

Examples show HTTP requests and responses, including relevant headers. Examples are also given that use the curl command-line utility, which is available for all major operating systems. See http://curl.haxx.se/ for details on curl.

NB: Callimachus includes (as of version 0.15) a script to clear its server-side cache. It is possible under some circumstances (e.g. removing triples from blank resources using the sparql endpoint) for the server-side cache to become stale. A systems administrator may run the command <installation directory>/bin/callimachus-reset.sh (or .bat) if server-side caching problems are suspected.

14.1.1. Authentication

Some functionality may only be accessed by authenticated users. Which functionality is restricted may be controlled by Callimachus' permissions system. However, by default the SPARQL endpoint and Create/Update/Delete functions are so restricted.

Callimachus uses HTTP Digest access authentication curl commands for authenticated commands require the --digest and --user parameters:

curl --digest --user john …
14.1.2. Correct URL Discovery

The URLs in the examples below are completely fictitious. HTTP does not transmit fragment identifiers, so the use of "#rel=..." in the examples below is mainly intended as a identifier of where the correct URL can be found or should be put. The correct URL itself can be discovered using an HTTP OPTIONS request or from an earlier response.

14.2. Browsing content

Callimachus supports iterative resource-oriented discovery of folder and "file" resources. Callimachus folders may be discovered and traversed using the REST API. Each folder may be introspected to discover its contents. Contents of folders may be either file-like resources (Binary Large Objects or BLOBs) or RDF resources (in RDF/XML or Turtle formats). BLOBs are stored in a BLOB store and RDF is stored in an RDF database. Folders are virtual constructs so you do not need to know what kind of resource you are dealing with; the interface abstracts one away from that information. The various resource types are described in Appendices.

General metadata regarding a Callimachus instance may be found by requesting an HTTP OPTIONS response from the top-level URL:

OPTIONS http://example.com:8080/ HTTP/1.1

The equivalent curl command is:

curl -i --digest --user john -X OPTIONS "http://example.com:8080/"

A typical response is shown below. Look specifically at the link: header:

HTTP/1.1 204 No Content
Age: 0
ETag: W/"274dde21-a038f4fe"
Last-Modified: Fri, 17 Feb 2012 15:24:45 GMT
Date: Fri, 17 Feb 2012 16:25:20 GMT
Cache-Control: public
access-control-allow-headers: Authorization,Host,Cache-Control,Location,Range,Accept,Accept-Charset,Accept-Encoding,
  Accept-Language,Content-Encoding,Content-Language,Content-Length,Content-Location,Content-MD5,Content-Type,
  If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since
access-control-allow-origin: *
allow: OPTIONS, TRACE, POST, GET, HEAD, DELETE, PUT
link: <http://example.com:8080/#rel=version-history>; rel="version-history"; type="application/atom+xml;q=0.5 text/html"
link: <http://example.com:8080/#rel=search>; rel="search"; type="application/opensearchdescription+xml"
link: <http://example.com:8080/#rel=describedby>; rel="describedby"; type="text/html"; title="RDF Describe"
link: <http://example.com:8080/#rel=contents>; rel="contents"; type="application/atom+xml;q=0.5"
link: <http://example.com:8080/#rel=..archive>; rel="http://callimachusproject.org/rdf/2009/framework#archive"
link: <http://example.com:8080/#rel=alternate&type=html>; rel="alternate"; type="text/html"
link: <http://example.com:8080/#rel=alternate&type=atom>; rel="alternate"; type="text/html application/atom+xml;q=0.5"
content-version: "274dde21"
vary: Accept,Access-Control-Request-Method
access-control-allow-methods: OPTIONS, TRACE, POST, GET, HEAD, DELETE, PUT
Accept-Ranges: bytes
Content-Length: 0
Server: Callimachus Server/Callimachus 0.15

There are two ways to get a list of top-level resources. To get an XML atom feed, look for the Contents URL in the link header with rel=”contents” (in this fictitious case: http://example.com:8080/#rel=contents). Perform an HTTP GET on the URL using an Accept: header as noted in the type attribute (in this case, application/atom+xml), e.g.

GET http://example.com:8080/#rel=contents HTTP/1.1
Accept: application/atom+xml

The equivalent curl command is:

curl -H "Accept: application/atom+xml" "http://example.com:8080/#rel=contents"

Typical results will look like the following. Note that only the first one hundred resources are shown.

<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:calli="http://callimachusproject.org/rdf/2009/framework#"
  xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:app="http://www.w3.org/2007/app">
        <id>http://example.com:8080/#rel=contents</id>
        <link href="http://example.com:8080/#rel=describedby" rel="describedby"/>
        <title>example.com:8080</title>
        <app:collection href="http://example.com:8080/#app:collection">
                <title>example.com:8080</title>
                <app:accept>text/plain</app:accept>
                <app:accept>application/rdf+xml</app:accept>
                <app:accept>text/turtle</app:accept>
                <app:accept>application/xhtml+xml</app:accept>
                <app:accept>application/font-woff</app:accept>
                <app:accept>application/sparql-query</app:accept>
                <app:accept>application/docbook+xml</app:accept>
                <app:accept>text/css</app:accept>
                <app:accept>text/xsl</app:accept>
                <app:accept>text/html</app:accept>
                <app:accept>image/gif</app:accept>
                <app:accept>image/vnd.microsoft.icon</app:accept>
                <app:accept>image/png</app:accept>
                <app:accept>image/svg+xml</app:accept>
                <app:accept>image/jpeg</app:accept>
                <app:accept>text/javascript</app:accept>
        </app:collection>
        <link href="http://example.com:8080/#rel=alternate&amp;type=atom" rel="alternate" type="application/atom+xml"/>
        <updated>2012-02-23T13:55:59.504Z</updated>
        <openSearch:totalResults>5</openSearch:totalResults>
        <link href="http://example.com:8080/#rel=search" rel="search" type="application/opensearchdescription+xml"/>
        <entry>
                <id>http://example.com:8080/.well-known/</id>
                <title>.well known</title>
                <updated>2012-02-17T15:02:22.556Z</updated>
                <icon>http://example.com:8080/callimachus/folder.png</icon>
                <link href="http://example.com:8080/auth/groups/users" rel="http://callimachusproject.org/rdf/2009/framework#reader" title="users"/>
                <link href="http://example.com:8080/auth/groups/staff" rel="http://callimachusproject.org/rdf/2009/framework#reader" title="staff"/>
                <link href="http://example.com:8080/auth/groups/admin" rel="http://callimachusproject.org/rdf/2009/framework#administrator" title="admin"/>
                <content src="http://example.com:8080/.well-known/"/>
                <link href="http://example.com:8080/.well-known/#rel=contents" rel="contents" type="application/atom+xml"/>
                <link href="http://example.com:8080/.well-known/#rel=..archive" rel="http://callimachusproject.org/rdf/2009/framework#archive" type="application/zip"/>
                <link href="http://example.com:8080/.well-known/#rel=alternate&amp;type=html" rel="alternate" type="text/html"/>
                <link href="http://example.com:8080/.well-known/#rel=describedby" rel="describedby"/>
                <link href="http://example.com:8080/.well-known/#rel=version-history" rel="version-history"/>
        </entry>
        <entry>
                <id>http://example.com:8080/callimachus/</id>
                <title>callimachus</title>
                <updated>2012-02-09T17:35:14.984Z</updated>
                <icon>http://example.com:8080/callimachus/folder.png</icon>
                <link href="http://example.com:8080/auth/groups/staff" rel="http://callimachusproject.org/rdf/2009/framework#reader" title="staff"/>
                <link href="http://example.com:8080/auth/groups/admin" rel="http://callimachusproject.org/rdf/2009/framework#administrator" title="admin"/>
                <content src="http://example.com:8080/callimachus/"/>
                <link href="http://example.com:8080/callimachus/#rel=contents" rel="contents" type="application/atom+xml"/>
                <link href="http://example.com:8080/callimachus/#rel=..archive" rel="http://callimachusproject.org/rdf/2009/framework#archive" type="application/zip"/>
                <link href="http://example.com:8080/callimachus/#rel=alternate&amp;type=html" rel="alternate" type="text/html"/>
                <link href="http://example.com:8080/callimachus/#rel=describedby" rel="describedby"/>
                <link href="http://example.com:8080/callimachus/#rel=version-history" rel="version-history"/>
        </entry>
        <entry>
                <id>http://example.com:8080/main-article.docbook</id>
                <title>main article</title>
                <updated>2012-02-06T01:27:09.545Z</updated>
                <icon>http://example.com:8080/callimachus/article.png</icon>
                <link href="http://example.com:8080/auth/groups/users" rel="http://callimachusproject.org/rdf/2009/framework#reader" title="users"/>
                <link href="http://example.com:8080/auth/groups/staff" rel="http://callimachusproject.org/rdf/2009/framework#editor" title="staff"/>
                <link href="http://example.com:8080/auth/groups/admin" rel="http://callimachusproject.org/rdf/2009/framework#administrator" title="admin"/>
                <link href="http://example.com:8080/main-article.docbook#rel=edit-media" rel="edit-media"/>
                <content src="http://example.com:8080/main-article.docbook" type="application/docbook+xml"/>
                <link href="http://example.com:8080/main-article.docbook#rel=alternate&amp;type=html" rel="alternate" type="text/html"/>
                <link href="http://example.com:8080/main-article.docbook#rel=describedby" rel="describedby"/>
                <link href="http://example.com:8080/main-article.docbook#rel=version-history" rel="version-history"/>
        </entry>
        <entry>
                <id>http://example.com:8080/sparql</id>
                <title>sparql</title>
                <contributor>
                        <name>James Leigh</name>
                        <uri>http://example.com:8080/user/james</uri>
                </contributor>
                <updated>2012-02-23T13:55:59.504Z</updated>
                <link href="http://example.com:8080/auth/groups/admin" rel="http://callimachusproject.org/rdf/2009/framework#administrator" title="admin"/>
                <content src="http://example.com:8080/sparql"/>
                <link href="http://example.com:8080/sparql#rel=alternate&amp;type=html" rel="alternate" type="text/html"/>
                <link href="http://example.com:8080/sparql#rel=describedby" rel="describedby"/>
                <link href="http://example.com:8080/sparql#rel=version-history" rel="version-history"/>
        </entry>
</feed>

The response above provided the contents and description of the top-level folder. The details may change in subsequent Callimachus releases. Resolving the URL of a folder will allow you to traverse the folder hierarchy.

Folders may be identified by the presence of an Atom feed with rel="contents" type="application/atom+xml" in a resource record. News readers may be used to track changes to Callimachus folders by subscribing to the alternate Atom feed (with rel="alternate" and type="application/atom+xml"), which will sort resources by last modified data. e.g.

<link href="http://example.com:8080/#rel=alternate&amp;type=atom" rel="alternate" type="application/atom+xml"/>

To get an RDF content listing, look for the describedby URL in the link header with rel="describedby" (in this fictitious case: http://example.com:8080/#rel=describedby). Perform an HTTP GET on the URL using an Accept header as noted in the type attribute (one or more of application/ld+json application/rdf+xml text/turtle). Such as

GET http://example.com:8080/#rel=describedby HTTP/1.1
Accept: text/turtle

The equivalent curl command is:

curl -H "Accept: text/turtle" "http://example.com:8080/#rel=describedby"

Typical results will look like the following.

@prefix calli: <http://callimachusproject.org/rdf/2009/framework#> .
@prefix dcterms: <http://purl.org/dc/terms/> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix prov: <http://www.w3.org/ns/prov#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix ldp: <http://www.w3.org/ns/ldp#> .

<.> a calli:Folder , calli:Origin , calli:Realm ;
    calli:allowOrigin "http://example.com:8080" ;
    calli:copy "index.xhtml?view" ;
    calli:describedby "main-article.docbook?view" ;
    rdfs:label "example.com:8080" ;
    calli:administrator <auth/groups/admin> ;
    calli:authentication <auth/digest+accounts> ;
    calli:contributor <auth/groups/users> ;
    calli:editor <auth/groups/staff> ;
    calli:error <callimachus/error.xpl> ;
    calli:forbidden <callimachus/forbidden.html> ;
    calli:hasComponent <.well-known/> , <admin> , <auth/> , <callimachus/> , <favicon.ico> , <main-article.docbook> , <robots.txt> , <sparql> ;
    calli:layout <callimachus/default-layout.xq> ;
    calli:reader <auth/groups/public> , <auth/groups/system> ;
    calli:secret <auth/secrets/71cc0b5b-f40f-4ff1-a329-7e75f52bd2df> ;
    calli:subscriber <auth/groups/everyone> ;
    calli:unauthorized <callimachus/unauthorized.html> ;
    prov:wasGeneratedBy <callimachus/changes/2014/10/22/t149391780dcx9#provenance> .

<> a ldp:Container , ldp:IndirectContainer , ldp:RDFSource ;
    ldp:contains <.well-known/?describe> , <admin?describe> , <auth/?describe> , <callimachus/?describe> , <favicon.ico> , <favicon.ico?describe> , <main-article.docbook> , <main-article.docbook?describe> , <robots.txt> , <robots.txt?describe> , <sparql?describe> ;
    ldp:hasMemberRelation calli:hasComponent ;
    ldp:insertedContentRelation foaf:primaryTopic ;
    ldp:membershipResource <.> ;
    foaf:primaryTopic <.> .

The response above provided the contents and description of the top-level folder. The calli:hasComponent and ldp:contains properties can be omitted using the Prefer request header.

14.3. Bulk changes

The entire contents of Callimachus folders, including all BLOB and RDF resources, may be exported into a Callimachus Archive (CAR) file. A CAR file is a ZIP version 3 formatted file that contains Callimachus-specific metadata. Exporting a CAR file from a folder recursively creates an archive of that folder's contents (not the folder itself), including any subfolders.

Exportation of CAR files may be performed at runtime and may be used for "hot" backup of the contents of a Callimachus server. Please also note that exportation of large amounts of RDF content will increase server load and may best be scheduled during quiet usage periods.

14.3.1. Export

Performing an HTTP OPTIONS on a folder URL returns a link: header with rel=”...#archive”, a content type and the folder's Archive URL to be used to get an export of the folder's contents. Performing a GET on the Archive URL using an Accept: header as noted in the type attribute (generally application/zip) will download the folder's contents as a ZIP version 3 file containing Callimachus-specific content. This is called a Callimachus Archive (CAR) file.

To get an export of a folder called "/exportme/":

GET http://example.com:8080/exportme/#rel=..archive HTTP/1.1
Accept: application/zip
Authorization: Digest username="john", realm="http://example.com:8080/", ...

The equivalent curl command is:

curl --digest --user john -H "Accept: application/zip" "http://example.com:8080/exportme/#rel=..archive" > exportme.car

Normal HTTP response codes are used to indicate success or failure of the request:

HTTP/1.1 200 OK
Content-Disposition:  attachment;filename="test-example.com.car"
Content-Type:  application/zip
Server:  Callimachus Server/Callimachus 0.15

<Binary ZIP file content here>

NB: CAR files contain a folder's contents, including any subfolders and their contents. CAR files do not contain a top-level folder; a new folder must be first created when importing CAR files.

14.3.2. Import

CAR files do not contain a top-level folder and must thus be imported into an existing folder. Create a folder before importing a CAR into it. It is not recommended to import CAR files into the top-level folder due to the presence of folders and resources necessary to the operation of Callimachus.

Performing an HTTP OPTIONS on a folder URL returns a link: header with rel=”...#archive”, a content type and the folder's Archive URL to be used to import the folder's contents. Performing an HTTP PUT with a Content-Type: header of application/zip and a body of a CAR file will replace the contents of a folder.

To replace the contents of a folder called "/importme/" with the CAR file exportme.car, first make the folder "/importme/" and then:

PUT http://example.com:8080/importme/#rel=..archive HTTP/1.1
Content-Type: application/zip
Authorization: Digest username="john", realm="http://example.com:8080/", ...

Normal HTTP response codes are used to indicate success or failure of the request:

HTTP/1.1 204 No Content
Server: Callimachus Server/Callimachus 0.15
...
14.3.3. Delete

Performing an HTTP OPTIONS on a folder URL returns a link: header with rel=”...#archive”, a content type and the folder's Archive URL to be used to delete the folder's contents. Performing an HTTP DELETE will delete the entire contents of a folder recursively, but it will not delete the folder itself.

To delete the contents of a folder called /deleteme/:

DELETE http://example.com:8080/deleteme/#rel=..archive
Authorization: Digest username="john", realm="http://example.com:8080/", ...

Normal HTTP response codes are used to indicate success or failure of the request:

HTTP/1.1 204 No Content
Server: Callimachus Server/Callimachus 1.0
...

14.4. CRUD operations on BLOB content

14.4.1. Overview

This describes how to create, retrieve, update and delete BLOB content in Callimachus. 

BLOB files in Callimachus may include text or HTML pages, images, CSS stylesheets, etc. See Appendix for supported file types. However, bulk RDF instance data is also loaded via files and is thus treated as a BLOB for the purposes of this API, even though Callimachus will load it into an RDF database after ingestion.

To perform CRUD operations on BLOB content, first retrieve the Atom contents feed for the folder you want to operate in. See the section on Browsing Content above for details.

Operations
14.4.2. Create

Content may be created in a folder by issuing an HTTP POST to the container's rel=describedby URL (found in a Link response header and the corresponding ldp:Container resource in a response) or to the folder's URL provided in the app:collection element of the folder's Atom contents feed. The body of the POST consists of the contents of the file you wish to upload. The HTTP header Content-Type: must be set appropriately for the type of file. Take note of the acceptable file types in Appendix. The file name you wish to create should be provided in the HTTP request header Slug, whose value should be the local part of its URI, otherwise a random local part will be used. See slug syntax.

The app:collection tag also lists the MIME types that are acceptable to your Callimachus server.

When creating BLOB content with an RDF Content-Type, include a Link header with a type of ldp:NonRDFSource (as shown below) to distinguish between creating pure-RDF resources.

For example, let's say you wanted to create an image called mylogo.png in the top-level folder. If the image file is located in a file of that name in the present working directory:

POST http://example.com:8080/#rel=describedby HTTP/1.1
Slug: mylogo.png
Content-Type: image/png
Link: <http://www.w3.org/ns/ldp#NonRDFSource>;rel="type"
Authorization: Digest username="john", realm="http://example.com:8080/", ...

The equivalent curl command is:

curl --digest --user john --data-binary @mylogo.png -H 'Link:<http://www.w3.org/ns/ldp#NonRDFSource>;rel="type"' \
  -H "Content-Type: image/png" -H "Slug: mylogo.png" "http://example.com:8080/#rel=describedby"

Normal HTTP response codes are used to indicate success or failure of the request:

HTTP/1.1 201 Created
Location:  http://example.com:8080/mylogo.png#rel=edit-media
Server:  Callimachus Server/Callimachus 0.15

NB: Callimachus Folders are RDF resources. See the section CRUD Operations on RDF Content for details on how to create folders.

14.4.3. Retrieve

Resources may be retrieved by performing an HTTP GET on either the Location value in a 201 response or the resource's rel=edit-media URL. A resource's rel=edit-media URL may be discovered by looking for the appropriate entry tag in the containing folder's Atom feed and then finding the link tag with rel="edit-media" and in a Link response header.

To retrieve the image created above:

GET http://example.com:8080/mylogo.png#rel=edit-media HTTP/1.1
Accept: image/png

The equivalent curl command is:

curl "http://example.com:8080/mylogo.png#rel=edit-media" > mylogo_copy.png
14.4.4. Replace

Resources may be updated by performing an HTTP PUT on the resource's edit media URL. A resource's rel=edit-media URL may be discovered by looking for the appropriate entry tag in the containing folder's Atom feed and then finding the link tag with rel="edit-media" or in a Link response header.

The body of the PUT consists of the contents of the file you wish to upload. The HTTP header Content-Type: must be set appropriately for the type of the file.

To update the image created above:

PUT http://example.com:8080/mylogo.png#rel=edit-media HTTP/1.1
Content-Type: image/png
Authorization: Digest username="john", realm="http://example.com:8080/", ...

The equivalent curl command is:

curl --digest --user john --upload-file "mylogo.png" -H "Content-Type: image/png" \
  "http://example.com:8080/mylogo.png#rel=edit-media"

Normal HTTP response codes are used to indicate success or failure of the request.

14.4.5. Delete

Resources may be deleted by performing an HTTP DELETE on the resource's rel=edit-media URL. A resource's URL may be discovered by looking for the appropriate entry tag in the containing folder's Atom feed and then finding the link tag with rel="edit-media" or in a Link response header.

To delete the image created above:

DELETE http://example.com:8080/mylogo.png#rel=edit-media HTTP/1.1
Authorization: Digest username="john", realm="http://example.com:8080/", ...

The equivalent curl command is:

curl --digest --user john -I -X DELETE "http://example.com:8080/mylogo.png#rel=edit-media"

Normal HTTP response codes are used to indicate success or failure of the request. In this case, a successful delete is indicated by a 204 (No Content) response.

14.5. CRUD operations on RDF content

14.5.1. Overview

This describes how to create, retrieve, update and delete RDF content. 

Many resources in Callimachus are defined solely by RDF statements. These include folders, users, groups and concepts, but not bulk RDF instance data (see the section CRUD Operations on BLOB Content for those). See Appendix for supported RDF resource types.

Operations
14.5.2. Create

RDF resources are created by performing an HTTP POST to the URL enclosing folder's describedby URL with a Content-Type of text/turtle, application/rdf+xml or application/ld+json and a body of the corresponding RDF data. The response will include a Location: header with the URL of the created resource's describedby URL. The RDF data needs to include a supported rdf:type (see Appendix for details). This approach may only be used to insert one resource at a time (a single primary topic; additional resources may be inserted if they are blank nodes or hash URIs off of the primary topic).

Permissions on the resource's Class also apply to its members and it is not be necessary to include them in the request body. However, the permissions of the container are NOT inherited by its members, when POST'ing to the describedby URL. Any resource specific permissions should be included in the body of the request.

As a reminder, the enclosing folder's describedby URL may be found via its Atom feed (where the attribute rel="describedby") or Link response header. See the earlier Browsing Content section for more details.

If you wanted to make a folder called "test" at the top level, first create a file with the appropriate RDF data. We'll save this file with a name of "testcreate.ttl":

@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix dcterms: <http://purl.org/dc/terms/> .
@prefix ldp: <http://www.w3.org/ns/ldp#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix calli: <http://callimachusproject.org/rdf/2009/framework#> .

<> a ldp:RDFSource;
    foaf:primaryTopic <test/> .

<test/> a calli:Folder ;
    rdfs:label "test" ;
    calli:reader </auth/groups/public> ;
    calli:editor </auth/groups/staff> ;
    calli:administrator </auth/groups/admin> .

The HTTP POST looks like this:

POST http://example.com:8080/#rel=describedby HTTP/1.1
Content-Type: text/turtle
Authorization: Digest username="john", realm="http://example.com:8080/", ...

@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix dcterms: <http://purl.org/dc/terms/> .
@prefix ldp: <http://www.w3.org/ns/ldp#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix calli: <http://callimachusproject.org/rdf/2009/framework#> .

<> a ldp:RDFSource;
    foaf:primaryTopic <test/> .

<test/> a calli:Folder ;
    rdfs:label "test" ;
    calli:reader </auth/groups/public> ;
    calli:editor </auth/groups/staff> ;
    calli:administrator </auth/groups/admin> .

The equivalent curl command is:

curl --digest --user john --data-binary @testcreate.ttl -H "Content-Type: text/turtle" \
  "http://example.com:8080/#rel=describedby"

If no foaf:primaryTopic is used (off the document-uri, often a null relative URI), the first (and only) non-hash and non-blank subject is assumed to be the primary topic. If a request Slug header is present, it will be used as the local part of the document-uri when parsing the request payload, otherwise a random local part is used. For example, the following is another valid create request.

POST http://example.com:8080/#rel=describedby HTTP/1.1
Content-Type: text/turtle
Slug: callimachusproject.org
Authorization: Digest username="john", realm="http://example.com:8080/", ...

@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix calli: <http://callimachusproject.org/rdf/2009/framework#> .

<> a calli:Purl ;
    rdfs:label "callimachusproject.org" ;
    calli:alternate <http://callimachusproject.org/> ;
    calli:reader </auth/groups/public> ;
    calli:editor </auth/groups/staff> ;
    calli:administrator </auth/groups/admin> .

Normal HTTP response codes are used to indicate success or failure of the request. The Location header of a 201 response contains the created resource's rel=describedby URL.

HTTP/1.1 201 Created
Location:  http://example.com:8080/callimachusproject.org#rel=describedby
14.5.3. Retrieve

Performing an HTTP GET on the rel=describedby URL with an Accept: header of text/turtle, application/ld+json, or application/rdf+xml will return an RDF representation of the resource. In a case where the Turtle format is requested, the result would be a Turtle document with many of the triples used in the Create section, above.

GET http://example.com:8080/test/#rel=describedby HTTP/1.1
Accept: text/turtle

The equivalent curl command is:

curl -H "Accept: text/turtle" "http://example.com:8080/test/#rel=describedby"

Normal HTTP response codes are used to indicate success or failure of the request.

200 OK
Content-Type: text/turtle; charset=UTF-8
ETag: W/"5c5717a4-2d11b05e"
Last-Modified: Thu, 23 Oct 2014 18:28:09 GMT
Date: Thu, 23 Oct 2014 18:02:41 GMT
Allow: OPTIONS, GET, HEAD, PUT, POST, PATCH, DELETE
Accept-Patch: application/sparql-update
Accept-Post: text/turtle, application/rdf+xml, application/ld+json
Link: <http://www.w3.org/ns/ldp#IndirectContainer>;rel="type"
Link: <http://www.w3.org/ns/ldp#Resource>;rel="type"
Link: <http://localhost:8080/test/>; rev="describedby"; type="text/html application/ld+json application/rdf+xml text/turtle"; title="RDF Describe"

@prefix calli: <http://callimachusproject.org/rdf/2009/framework#> .
@prefix dcterms: <http://purl.org/dc/terms/> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix ldp: <http://www.w3.org/ns/ldp#> .
@prefix prov: <http://www.w3.org/ns/prov#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .

<.> a calli:Folder , </callimachus/1.4/types/Folder> ;
    rdfs:label "test" ;
    calli:administrator </auth/groups/admin> ;
    calli:editor </auth/groups/staff> ;
    calli:reader </auth/groups/public> .

<> a ldp:Container , ldp:IndirectContainer , ldp:RDFSource ;
    ldp:hasMemberRelation calli:hasComponent ;
    ldp:insertedContentRelation foaf:primaryTopic ;
    ldp:membershipResource <.> ;
    foaf:primaryTopic <.> .
14.5.4. Replace

Performing an HTTP PUT on the rel=describedby URL with modified a body of the GET response will update the resource. When using PUT, the request header If-Match is required, but may be wild.

PUT /test/#rel=describedby HTTP/1.1
Host: example.com:8080
If-Match: W/"5c5717a4-2d11b05e"
Content-Type: text/turtle; charset=UTF-8

@prefix calli: <http://callimachusproject.org/rdf/2009/framework#> .
@prefix dcterms: <http://purl.org/dc/terms/> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix ldp: <http://www.w3.org/ns/ldp#> .
@prefix prov: <http://www.w3.org/ns/prov#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .

<.> a calli:Folder , </callimachus/1.4/types/Folder> ;
    rdfs:label "test Folder" ;
    calli:administrator </auth/groups/admin> ;
    calli:editor </auth/groups/staff> ;
    calli:reader </auth/groups/public> .

<> a ldp:Container , ldp:IndirectContainer , ldp:RDFSource ;
    ldp:hasMemberRelation calli:hasComponent ;
    ldp:insertedContentRelation foaf:primaryTopic ;
    ldp:membershipResource <.> ;
    foaf:primaryTopic <.> .

A similar curl command is:

curl -H accept:text/turtle "http://example.com:8080/test/#rel=describedby" \
  |sed 's/"test"/"Test Folder"/' \
  |curl -T - -H 'If-Match:*' -H content-type:text/turtle "http://example.com:8080/test/#rel=describedby"
14.5.5. Update

Performing an HTTP PATCH on the describedby URL with an Content-Type: header of application/sparql-update and a body of a SPARQL DELETE INSERT will update the resource.

NB: Updating a Folder, User, Group etc, has the potential to negatively impact internal Callimachus state: Be Careful!

To update the RDF definition of the "/test/" folder, first create a SPARQL DELETE INSERT query and put it into a file (in this case we'll call the file "testupdate.ru"). The contents of the file might look like this:

BASE <http://example.com:8080/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
​DELETE {
        </test/> rdfs:label ?label .
}
INSERT {
        </test/> rdfs:label "Test Folder" .
}
WHERE {
        </test/> rdfs:label ?label .
}

The HTTP command is then:

PATCH http://example.com:8080/test/#rel=describedby HTTP/1.1
Content-Type: application/sparql-update
Authorization: Digest username="john", realm="http://example.com:8080/", ...

BASE <http://example.com:8080/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>

DELETE {
        </test/> rdfs:label ?label .
}
INSERT {
        </test/> rdfs:label "Test Folder" .
}
WHERE {
        </test/> rdfs:label ?label .
}

The equivalent curl command is:

curl --digest --user john -X PATCH --data-binary @testupdate.ru -H "Content-Type: application/sparql-update" \
  "http://example.com:8080/test/#rel=describedby"

Normal HTTP response codes are used to indicate success or failure of the request:

HTTP/1.1 204 No Content
Server: Callimachus Server/Callimachus 0.1
...
14.5.6. Delete

Performing an HTTP DELETE on the rel=describedby URL will delete the resource.

To delete the "/test/" folder:

DELETE http://example.com:8080/test/#rel=describedby HTTP/1.1
Authorization: Digest username="john", realm="http://example.com:8080/", ...

The equivalent curl command is:

curl --digest --user john -I -X DELETE "http://example.com:8080/test/#rel=describedby"

Normal HTTP response codes are used to indicate success or failure of the request. In this case, a successful delete is indicated by a 200 (OK) or 204 (No Content) response.

14.6. Searching content

Here we will explore two RESTful ways of searching for content using Callimachus:

14.6.1. Keyword searches

Keyword searches may be performed on certain RDF properties. See Appendix A for a list of RDF properties that may be searched.

An OpenSearch description document may be discovered by resolving the top-level OPTIONS and looking for the Search URL. Find the link:header with rel="search" (See the section Browsing Content for details). Search results are returned in an Atom document augmented with OpenSearch response elements.

Perform an HTTP GET on the Search URL. Provide an Accept: header including its associated content type. For example:

GET http://example.com/#rel=search HTTP/1.1
Accept: application/opensearchdescription+xml

The equivalent curl command is:

curl -H "Accept: application/opensearchdescription+xml" "http://example.com/#rel=search"

Which will result in:

<?xml version="1.0" encoding="UTF-8"?>
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
<ShortName>example.com</ShortName>
<Url type="application/atom+xml" template="http://example.com/#rel=search&amp;searchTerms={searchTerms}"/>
</OpenSearchDescription>

You may then perform a subsequent HTTP GET on the Template URL using the content type specified (in the Url tag's template and typeattributes), substituting your search terms for "{searchTerms}". Note that keyword searches require authentication. To actually perform a keyword search on, for example, the word "Callimachus":

GET http://example.com/#rel=search&searchTerms=Callimachus HTTP/1.1
Accept: application/atom+xml
Authorization: Digest username="john", realm="http://example.com/", ...

The equivalent curl command is:

curl --digest --user john -H "Accept: application/atom+xml" "http://example.com/#rel=search&searchTerms=Callimachus"

Results will look like:

<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:calli="http://callimachusproject.org/rdf/2009/framework#"
  xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:app="http://www.w3.org/2007/app">
        <id>http://example.com/#rel=search&amp;searchTerms=Callimachus</id>
        <title>example.com:8080</title>
        <updated>2012-02-23T13:55:59.504Z</updated>
        <entry>
                <id>http://example.com/callimachus/images/callimachus-icon.ico</id>
                <link href="http://example.com/callimachus/images/callimachus-icon.ico#rel=alternate&amp;type=html" rel="alternate"
  type="text/html"/>
                <title>callimachus icon</title>
                <updated>2012-02-24T01:25:04.753Z</updated>
                <content src="http://example.com/callimachus/images/callimachus-icon.ico" type="text/xsl"/>
        </entry>
        <entry>
                <id>http://example.com/callimachus/callimachus-ontology.ttl</id>
                <link href="http://example.com/callimachus/callimachus-ontology.ttl#rel=alternate&amp;type=html" rel="alternate"
  type="text/html"/>
                <title>callimachus ontology</title>
                <updated>2012-02-24T01:24:55.979Z</updated>
                <content src="http://example.com/callimachus/callimachus-ontology.ttl" type="text/xsl"/>
        </entry>
        ...
</feed>

See the OpenSearch description for details on the OpenSearch description document syntax and the OpenSearch response elements.

14.6.2. SPARQL queries

The SPARQL Query Language may be used to query RDF content. Requesting Callimachus' SPARQL endpoint via an HTTP GET with an Accept: header of text/html or application/xhtml+xml (as a browser should) will return an HTML form suitable for human-centric queries. The SPARQL endpoint may also be directly used via REST calls as described below.

The location of the SPARQL endpoint may be discovered by resolving Callimachus' VoID description and parsing out its location.

GET http://example.com/.well-known/void HTTP/1.1
Accept: text/turtle

Note that this and other responses may respond with an HTTP 303 (See Other) response directing you to another location via the Location:header:

HTTP/1.1 303 See Other
Location: http://example.com/.well-known/void#rel=describedby
Content-Length: 0
...

Resolve the URL provided there for the canonical location of the VoID description:

GET http://example.com/.well-known/void#rel=describedby HTTP/1.1
Accept: text/turtle

The equivalent curl command is:

curl -L -H "Accept: text/turtle" "http://example.com/.well-known/void"

A typical response looks like:

HTTP/1.1 200 OK
Link: <http://www.w3.org/ns/ldp#Resource>;rel="type"
Link: <http://localhost:8080/.well-known/void>; rev="describedby"; type="text/html application/ld+json application/rdf+xml text/turtle"; title="RDF Describe"
Content-Type: text/turtle; charset=UTF-8
Last-Modified: Thu, 23 Oct 2014 18:01:38 GMT
Date: Thu, 23 Oct 2014 18:55:43 GMT
ETag: W/"4ffefe4d-2d11b05e"

@prefix calli: <http://callimachusproject.org/rdf/2009/framework#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix ldp: <http://www.w3.org/ns/ldp#> .
@prefix prov: <http://www.w3.org/ns/prov#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix void: <http://rdfs.org/ns/void#> .

<> a ldp:RDFSource ;
    foaf:primaryTopic <void> .

<void> a </callimachus/1.4/types/Serviceable> , void:DatasetDescription ;
    rdfs:label "void" ;
    calli:reader </auth/groups/public> ;
    foaf:primaryTopic <void#dataset> .

<void#dataset> a void:Dataset ;
    void:openSearchDescription </?search> ;
    void:rootResource </> ;
    void:sparqlEndpoint </sparql> ;
    void:uriLookupEndpoint </sparql?uri=> ;
    void:uriSpace </> ;
    foaf:homepage </> .

The SPARQL endpoint URL is provided in the void:sparqlEndpoint tag.

Use the SPARQL Protocol to perform queries via REST. See the SPARQL Protocol specification for URL parameters and the SPARQL Query Language specification for details of the query language.

curl --digest --user john --data-urlencode query@test.rq -H accept:application/sparql-results+xml http://example.com/sparql
curl --digest --user john --data-urlencode update@test.ru http://example.com/sparql

14.7. BLOB Resource Types

Here are the BLOB resource types that you can use in Callimachus.

Resource type Content type
Article application/docbook+xml
Font application/font-woff
PDF application/pdf
JSON application/json
NamedGraph application/rdf+xml (goes into RDF and BLOB store)
NamedQuery application/sparql-query
Page application/xhtml+xml
Pipeline application/xproc+xml
XQuery application/xquery
AnimatedGraphic image/gif
Photo image/jpeg
NetworkGraphic image/png
VectorGraphic image/svg+xml
IconGraphic image/vnd.microsoft.icon
Style text/css
HypertextFile text/html
Script text/javascript
TextFile text/plain
GraphDocument text/turtle (goes into RDF and BLOB store)
Transform text/xsl
Markdown text/x-markdown

14.8. RDF Resource Types

Here are the default RDF resource types used in Callimachus. Users can create their own RDF resource types by creating a Callimachus class.

Resource type Content type Required Property
SKOS Concept skos:Concept skos:prefLabel
Folder calli:Folder rdfs:label
Purl calli:Purl rdfs:label
Group calli:Group rdfs:label
Class owl:Class rdfs:subClassOf </callimachus/1.4/types/Serviceable>