rdftemplate

Library for generating XML documents from RDF data using templates
git clone https://code.djc.id.au/git/rdftemplate/
commit df659215b05dcb9c6bbfc124ed8295e9f76a5744
parent 438ba4c348fa7c7768e69ad312ae0d8b4b3462dc
Author: Dan Callaghan <djc@djc.id.au>
Date:   Sat,  7 Aug 2010 16:33:59 +1000

using sphinx instead of mvn site

Diffstat:
Asrc/doc/sphinx/_static/default.css | 88+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/doc/sphinx/_templates/layout.html | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/doc/sphinx/_templates/localtoc.html | 6++++++
Asrc/doc/sphinx/_templates/searchbox.html | 12++++++++++++
Asrc/doc/sphinx/conf.py | 175+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/doc/sphinx/example-graph.rst.inc | 20++++++++++++++++++++
Asrc/doc/sphinx/index.rst | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/doc/sphinx/selector.rst | 296+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/doc/sphinx/spring.rst | 43+++++++++++++++++++++++++++++++++++++++++++
Asrc/doc/sphinx/xml-template.rst | 269+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/site/site.xml | 8--------
11 files changed, 1036 insertions(+), 8 deletions(-)
diff --git a/src/doc/sphinx/_static/default.css b/src/doc/sphinx/_static/default.css
@@ -0,0 +1,88 @@
+@import url("http://fonts.googleapis.com/css?family=Crimson+Text");
+@import url("http://fonts.googleapis.com/css?family=Inconsolata");
+@import url("http://fonts.googleapis.com/css?family=Nobile");
+
+body {
+    font-family: sans-serif;
+    font-size: 0.9em;
+    line-height: 2.75ex;
+}
+img {
+    border: none;
+}
+
+div.document {
+    margin: 0 auto;
+    max-width: 95ex;
+}
+div.body {
+    margin-right: 27ex;
+}
+div.sidebar {
+    font-size: 0.9em;
+    width: 27ex;
+    margin-left: 80ex;
+    position: fixed;
+}
+
+dt {
+    margin-top: 1.5em;
+}
+dd {
+    margin-left: 1.5em;
+}
+
+pre {
+    background-color: #ffffd0;
+    padding: 0.5em 1em;
+    overflow: auto;
+}
+
+tt.xref {
+    font-weight: bold;
+}
+tt.descname {
+    font-weight: bold;
+    font-size: 1.2em;
+}
+dt:target, .highlighted {
+    background-color: #fbe54e;
+}
+
+div.sidebar h3 {
+    margin: 1em 0 0 0;
+}
+div.sidebar div.toc ul {
+    margin: 0;
+    padding: 0;
+}
+div.sidebar div.toc ul li {
+    margin: 0 0 0 1.25em;
+    padding: 0.5em 0 0 0;
+    line-height: 1.2em;
+}
+div.sidebar input[type=text] {
+    width: 17ex;
+}
+
+a.headerlink {
+    color: #aa0000;
+    text-decoration: none;
+    visibility: hidden;
+    padding-left: 0.35em;
+}
+h1:hover > a.headerlink,
+h2:hover > a.headerlink,
+h3:hover > a.headerlink,
+h4:hover > a.headerlink,
+h5:hover > a.headerlink,
+h6:hover > a.headerlink,
+dt:hover > a.headerlink {
+    visibility: visible;
+}
+
+div.admonition {
+}
+p.admonition-title {
+    font-weight: bold;
+}
diff --git a/src/doc/sphinx/_templates/layout.html b/src/doc/sphinx/_templates/layout.html
@@ -0,0 +1,70 @@
+{%- block doctype -%}
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+{%- endblock %}
+{%- set url_root = pathto('', 1) %}
+{%- if url_root == '#' %}{% set url_root = '' %}{% endif %}
+
+{%- macro sidebar() %}
+      <div class="sidebar">
+          {%- if sidebars != None %}
+            {#- new style sidebar: explicitly include/exclude templates #}
+            {%- for sidebartemplate in sidebars %}
+            {%- include sidebartemplate %}
+            {%- endfor %}
+          {%- endif %}
+      </div>
+{%- endmacro %}
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset={{ encoding }}" />
+    {{ metatags }}
+    {%- block htmltitle %}
+    <title>{{ title|striptags|e }}</title>
+    {%- endblock %}
+    <link rel="stylesheet" href="{{ pathto('_static/' + style, 1) }}" type="text/css" />
+    <link rel="stylesheet" href="{{ pathto('_static/pygments.css', 1) }}" type="text/css" />
+    {%- for cssfile in css_files %}
+    <link rel="stylesheet" href="{{ pathto(cssfile, 1) }}" type="text/css" />
+    {%- endfor %}
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+        URL_ROOT:    '{{ url_root }}',
+        VERSION:     '{{ release|e }}',
+        COLLAPSE_INDEX: false,
+        FILE_SUFFIX: '{{ '' if no_search_suffix else file_suffix }}',
+        HAS_SOURCE:  {{ has_source|lower }}
+      };
+    </script>
+    {%- for scriptfile in script_files %}
+    <script type="text/javascript" src="{{ pathto(scriptfile, 1) }}"></script>
+    {%- endfor %}
+{%- block linktags %}
+    <link rel="search" title="{{ _('Search') }}" href="{{ pathto('search') }}" />
+    <link rel="top" title="{{ docstitle|e }}" href="{{ pathto('index') }}" />
+{%- endblock %}
+{%- block extrahead %} {% endblock %}
+  </head>
+  <body>
+{%- block header %}{% endblock %}
+
+{%- block content %}
+
+    <div class="document">
+      {{ sidebar() }}
+
+  {%- block document %}
+      <div class="body">
+        {%- if pagename != 'index' %}
+            <a href="./">{{ shorttitle|e }}</a> &raquo;
+        {%- endif %}
+
+        {% block body %} {% endblock %}
+      </div>
+  {%- endblock %}
+
+    </div>
+{%- endblock %}
+
+  </body>
+</html>
diff --git a/src/doc/sphinx/_templates/localtoc.html b/src/doc/sphinx/_templates/localtoc.html
@@ -0,0 +1,6 @@
+{%- if display_toc %}
+    <div class="toc">
+        <h3>Contents</h3>
+        {{ toc }}
+    </div>
+{%- endif %}
diff --git a/src/doc/sphinx/_templates/searchbox.html b/src/doc/sphinx/_templates/searchbox.html
@@ -0,0 +1,12 @@
+{%- if pagename != "search" %}
+<div id="searchbox" style="display: none">
+  <h3>{{ _('Quick search') }}</h3>
+    <form class="search" action="{{ pathto('search') }}" method="get">
+      <input type="text" name="q" size="18" />
+      <input type="submit" value="{{ _('Go') }}" />
+      <input type="hidden" name="check_keywords" value="yes" />
+      <input type="hidden" name="area" value="default" />
+    </form>
+</div>
+<script type="text/javascript">$('#searchbox').show(0);</script>
+{%- endif %}
diff --git a/src/doc/sphinx/conf.py b/src/doc/sphinx/conf.py
@@ -0,0 +1,175 @@
+# -*- coding: utf-8 -*-
+#
+# rdftemplate documentation build configuration file, created by
+# sphinx-quickstart on Wed Jul 28 08:11:55 2010.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+sys.path.insert(0, '/home/dan/miskinhill/sphinx-contrib/javadomain')
+sys.path.insert(0, '/home/dan/miskinhill/sphinx-contrib/javadocref')
+
+import lxml.etree
+pom = lxml.etree.parse(open(os.path.join('..', '..', '..', 'pom.xml')))
+def pom_xpath(expr):
+    return lxml.etree.XPath(expr, namespaces={'pom': 'http://maven.apache.org/POM/4.0.0'})(pom)
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['sphinx.ext.todo', 'sphinx.ext.viewcode', 'sphinx.ext.graphviz',
+        'sphinxcontrib.javadomain', 'sphinxcontrib.javadocref']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = pom_xpath('//pom:project/pom:name/text()')[0]
+copyright = u'2010, Dan Callaghan'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = pom_xpath('//pom:project/pom:version/text()')[0]
+# The full version, including alpha/beta/rc tags.
+release = pom_xpath('//pom:project/pom:version/text()')[0]
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = []
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+highlight_language = 'java'
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+html_theme = 'basic'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further.  For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+html_style = 'default.css'
+
+# The name for this set of Sphinx documents.  If None, it defaults to
+# "<project> v<release> documentation".
+html_title = project
+
+# A shorter title for the navigation bar.  Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+html_use_smartypants = False
+
+# Custom sidebar templates, maps document names to template names.
+html_sidebars = {
+    'index': ['searchbox.html'],
+    'selector': ['localtoc.html', 'searchbox.html'],
+    'xml-template': ['localtoc.html', 'searchbox.html'],
+    'spring': ['localtoc.html', 'searchbox.html'],
+}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+html_domain_indices = True
+
+# If false, no index is generated.
+html_use_index = False
+
+# If true, links to the reST sources are added to the pages.
+html_show_sourcelink = False
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+todo_include_todos = True
+nitpicky = True
+javadocref_locations = ['http://code.djc.id.au/rdftemplate/javadoc/latest/',
+        'http://jena.sourceforge.net/javadoc/',
+        'http://download-llnw.oracle.com/javase/6/docs/api/']
diff --git a/src/doc/sphinx/example-graph.rst.inc b/src/doc/sphinx/example-graph.rst.inc
@@ -0,0 +1,20 @@
+
+.. digraph:: example
+
+   node [fontname = "Liberation Sans", fontsize = 12];
+   edge [fontname = "Liberation Sans", fontsize = 11];
+
+   bob [shape = ellipse, style = filled, color = palegreen, label = "<bob>"];
+   alice [shape = ellipse, style = filled, color = palegreen, label = "<alice>"];
+   carol [shape = ellipse, style = filled, color = palegreen, label = "<carol>"];
+
+   bob_name [shape = box, style = filled, color = peachpuff, label = "\"Bob\"" ];
+   alice_name [shape = box, style = filled, color = peachpuff, label = "\"Alice\"" ];
+   carol_name [shape = box, style = filled, color = peachpuff, label = "\"Carol\"" ];
+
+   bob -> bob_name [label = "foaf:name"];
+   alice -> alice_name [label = "foaf:name"];
+   carol -> carol_name [label = "foaf:name"];
+
+   bob -> alice [label = "foaf:knows"] ;
+   bob -> carol [label = "foaf:knows"] ;
diff --git a/src/doc/sphinx/index.rst b/src/doc/sphinx/index.rst
@@ -0,0 +1,57 @@
+rdftemplate
+===========
+
+Rdftemplate is a library for generating XML documents from RDF data using 
+templates.
+
+The library supports evaluation of “:doc:`selector expressions <selector>`”, which use an 
+XPath-inspired syntax for selecting an ordered set of nodes from an arbitrary 
+starting context node.
+
+The library also supports rendering XML from :doc:`templates <xml-template>`. The template 
+interpolator recognises a number of Genshi-inspired template directives, which 
+are used to insert the result of a selector expression into the generated 
+XML.
+
+The library uses the Jena RDF model API.
+It also includes optional support for :doc:`integrating with Spring 
+<spring>`, allowing templates to be used as Spring Web MVC views.
+
+Rdftemplate was developed for the `Miskin Hill`_ web site, where it is used to 
+generate output in various XML-based formats. You can view the `templates used 
+for Miskin Hill <http://code.miskinhill.com.au/hg/miskinhill-master/file/tip/web/src/main/resources/au/com/miskinhill/rdf/template/>`_ 
+to see some examples of how rdftemplate works.
+
+.. _Miskin Hill: http://miskinhill.com.au/
+
+Development
+-----------
+
+* `Javadoc <http://code.djc.id.au/rdftemplate/javadoc/latest/>`_
+* `Mercurial repository <http://code.djc.id.au/hg/rdftemplate/>`_
+* `Hudson build <http://hudson.miskinhill.com.au/job/rdftemplate/>`_
+* Send bugs and suggestions to `Dan C <mailto:djc@djc.id.au>`_
+
+Quick start with Maven
+----------------------
+
+Add the following to your pom.xml:
+
+.. code-block:: xml
+
+    <repositories>
+        <repository>
+            <id>code.djc.id.au</id>
+            <url>http://code.djc.id.au/maven2/</url>
+        </repository>
+    </repositories>
+
+    <dependencies>
+        <dependency>
+            <groupId>au.id.djc</groupId>
+            <artifactId>rdftemplate</artifactId>
+            <version>1.1</version>
+        </dependency>
+    </dependencies>
+
+.. todo:: more examples, like calling TemplateInterpolator or using Spring views
diff --git a/src/doc/sphinx/selector.rst b/src/doc/sphinx/selector.rst
@@ -0,0 +1,296 @@
+Selector expressions
+====================
+
+Selector expressions are a concise way of selecting some set of nodes in an RDF 
+graph, given a particular starting node. For example, given the graph:
+
+.. include:: example-graph.rst.inc
+
+evaluating the selector expression ``foaf:knows/foaf:name`` with a starting node of 
+``<bob>`` would yield two literal nodes: ``"Alice"`` and ``"Carol"``.
+
+The syntax for selector expressions was inspired by `XPath`_ syntax, so if you 
+are familiar with XPath you will notice many similarities.
+
+.. todo:: make graphviz output prettier
+
+.. _XPath: http://www.w3.org/TR/xpath/
+
+Syntax
+------
+
+Traversing
+~~~~~~~~~~
+
+At the heart of selector expressions is the notion of traversing a path through 
+the RDF graph along properties, in the same way XPath can traverse a document 
+tree. Selector expressions are always evaluated with respect to a context node 
+in the graph, which is the starting point for traversals.
+
+The simplest traversal consists of a single RDF property, such as 
+``foaf:knows``. This expression selects all nodes which are the object of 
+a foaf:knows predicate where the starting node is the subject. In other words, 
+it can be considered equivalent to the SPARQL query:
+
+.. code-block:: none
+
+   SELECT ?o
+   WHERE { ?start foaf:knows ?o . }
+
+(Actually the *simplest* traversal is the empty string, which always evaluates 
+to the starting node. This is really only meaningful when used with other 
+syntax elements described below.)
+
+If we used ``<bob>`` in the example graph above as our starting node, the 
+expression ``foaf:knows`` would evaluate to two resource nodes: ``<alice>`` and 
+``<carol>``. In general a selector expression may yield zero or more results. 
+For example, if we used ``<alice>`` as a starting node, the result would be 
+empty.
+
+Multiple traversals may be chained together using ``/`` as a separator, as in 
+``foaf:knows/foaf:name``.
+
+Note that property URIs are always given in their prefixed form. In order to 
+keep the syntax simple, there is no way to specify a complete URI reference in 
+a selector expression.
+
+Inverse traversal
+~~~~~~~~~~~~~~~~~
+
+The direction of a property traversal can be inverted by prepending ``!`` to 
+the property name. For example, given some article as a starting node, the 
+expression ``dc:creator/!dc:creator/dc:title`` might be used to select the 
+title of all articles written by the authors of the starting node.
+
+.. _predicates:
+
+Predicates
+~~~~~~~~~~
+
+The set of nodes resulting from a traversal can be filtered with a predicate. 
+The predicate is given in square brackets (``[]``) following the property name. 
+Predicates may appear at any point in the chain of traversals.
+
+The following predicates are supported:
+
+``type``
+    Includes only nodes of the given type. Use it like this: 
+    ``!dc:creator[type=bibo:Article]``.
+
+``uri-prefix``
+    Includes only resource nodes whose URI begins with the given string. Use it 
+    like this: ``dc:identifier[uri-prefix='urn:issn:']``.
+
+Multiple predicates may be applied by joining them together with the ``and`` 
+keyword, as in ``!dc:creator[type=bibo:Article and uri-prefix='http://example.com/']``.
+
+Custom predicates may be defined at runtime by supplying a custom 
+:java:class:`PredicateResolver` implementation.
+
+.. _adaptations:
+
+Adapting the result
+~~~~~~~~~~~~~~~~~~~
+
+The result of evaluating a traversal is zero or more RDF nodes (in Java, 
+implementations of Jena’s :java:class:`RDFNode 
+<com.hp.hpl.jena.rdf.model.RDFNode>` interface). However, it is often necessary 
+to convert these RDF nodes into a more useful data type, or to perform some 
+post-processing on them.
+
+An adaptation is a function which takes an RDF node and “adapts” it in some 
+way. An adaptation can be specified at the end of a selector expression, 
+preceded by ``#`` and optionally followed by an argument list. For example, the 
+expression ``foaf:knows#uri`` would evaluate to the URIs of the people known to 
+the starting node. The distinction here is important: whereas ``foaf:knows`` 
+evaluates to zero or more :java:class:`RDFNodes 
+<com.hp.hpl.jena.rdf.model.RDFNode>`, ``foaf:knows#uri`` evaluates to zero or 
+more :java:class:`Strings <java.lang.String>` giving the URI of each node.
+
+The following adaptations are supported:
+
+``uri``
+    Returns the URI of the RDF node as a :java:class:`String 
+    <java.lang.String>`. Throws an exception if applied to a node which is not 
+    a resource.
+
+``uri-slice``
+    Returns a substring of the URI. This adaptation takes a single integer 
+    argument specifying the number of characters to be removed. Use it like 
+    this: ``dc:identifier[uri-prefix='urn:issn:']#uri-slice(9)``.
+
+``uri-anchor``
+    Returns the anchor part of the URI, excluding the # character. Returns 
+    empty string if there is no anchor part.
+
+``lv``
+    Short for “literal value”. Returns the value of the literal RDF node, 
+    converted to a Java object using Jena’s type conversion facilities (see 
+    :java:method:`Literal#getValue() 
+    <com.hp.hpl.jena.rdf.model.Literal#getValue()>`). Throws an exception if 
+    applied to a node which is not a literal.
+
+``comparable-lv``
+    Essentially the same as ``lv``, but with a runtime check to ensure the 
+    literal value implements :java:class:`Comparable <java.lang.Comparable>`. 
+    Only exists for type-safety reasons.
+
+``string-lv``
+    Like ``lv``, but additionally calls toString() on the resulting object to 
+    ensure it is always a String. This adaptation also strips all tags from XML 
+    literals.
+
+``formatted-dt``
+    Short for “formatted date-time”. This adaptation can only be applied to 
+    literal nodes whose values are represented as Joda datetime types. It takes 
+    a single string argument, specifying the date-time format to apply. Use it 
+    like this: ``dc:created#formatted-dt('d MMMM yyyy')``.
+
+    .. todo:: hacks for Joda are not in stock Jena
+
+Custom adaptations may be defined at runtime by supplying a custom 
+:java:class:`AdaptationFactory` implementation.
+
+Sorting the result
+~~~~~~~~~~~~~~~~~~
+
+RDF graphs by their nature do not define any ordering, so a selector expression 
+like ``foaf:knows`` will return its results in arbitrary order. When we expect 
+the result to contain more than one node, it is often useful to ensure 
+a predictable (repeatable) ordering of the resulting nodes.
+
+Sorting can be applied at any point in the chain of traversals, by giving 
+a sort expression enclosed in parentheses (``()``). The sort expression can be 
+a complete selector expression (including multiple traversals, nested sorts, 
+and any other selector features). The set of nodes in the traversal are then 
+sorted by evaluating the sort expression for each node, and sorting with these 
+values as keys. The sort expression may optionally be prepended with ``~`` to 
+indicate a reverse sort.
+
+For example, given an author as a starting node, 
+``!dc:creator(dc:title#comparable-lv)`` would evaluate to the works created by 
+that author, ordered by the title of each work.
+
+Note that the sort expression must always evaluate to a Java object which 
+implements :java:class:`Comparable <java.lang.Comparable>`, so it is typically 
+necessary to apply the ``comparable-lv`` adaptation in the sort expression.
+
+If one expression is not enough to uniquely sort each item in the result, 
+multiple sort expressions can be specified using ``,`` to separate them.
+
+Selecting from many results
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A sort expression may optionally be followed by a subscript ``[n]``, indicating 
+that only the *n*-th node in the result should be selected. For example, 
+``!dc:creator(~dc:date)[0]/dc:title`` might be used to select the title of an 
+author’s most recent work.
+
+Combining multiple expressions
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Selector expressions can be chained together using ``|``. The result of the 
+expression will be the result of each sub-expression chained together in 
+sequence. For example: ``!dc:creator | !bibo:translator``.
+
+Evaluating expressions
+----------------------
+
+The following classes in the au.id.djc.rdftemplate.selector package are 
+relevant for compiling and evaluating selector expressions:
+
+.. java:class:: au.id.djc.rdftemplate.selector.Selector<T>
+
+   This interface represents the compiled version of a selector expression. It 
+   is parametrised on the result type of the expression.
+
+   .. java:method:: java.lang.Class<T> getResultType()
+
+      Returns the result type of this selector expression. (This is the runtime 
+      class of the type parameter T.) For a simple traversal this will be 
+      :java:class:`RDFNode <com.hp.hpl.jena.rdf.model.RDFNode>`, or if an 
+      adaptation is applied to the selector expression it will be the result 
+      type of the adaptation (such as :java:class:`String <java.lang.String>` 
+      or :java:class:`Object <java.lang.Object>`).
+
+   .. java:method:: Selector<Other> withResultType(java.lang.Class<Other> otherType)
+
+      A convenience method to cast the type parameter of this Selector. Always 
+      returns this instance. Just a dumb hack to keep Java’s static type 
+      checking happy.
+
+   .. java:method:: java.util.List<T> result(com.hp.hpl.jena.rdf.model.RDFNode node)
+
+      Evaluates this selector expression with respect to the given starting 
+      node, and returns the result.
+
+   .. java:method:: T singleResult(com.hp.hpl.jena.rdf.model.RDFNode node)
+
+      Evaluates this selector expression with respect to the given starting 
+      node, and returns the result. If the selector does not evaluate to 
+      exactly one node, an exception is thrown.
+
+.. java:class:: au.id.djc.rdftemplate.selector.AntlrSelectorFactory
+
+   Use this class to compile selector expressions into :java:class:`Selector` 
+   instances. Instances of this class can safely be shared across threads (for 
+   example, as singleton beans in Spring).
+
+   .. java:method:: au.id.djc.rdftemplate.selector.Selector<?> get(java.lang.String expression)
+
+      Compiles the given selector expression into a :java:class:`Selector` 
+      instance.
+
+      .. code-block:: java
+
+         Selector<RDFNode> s1 = factory.get("foaf:knows").withResultType(RDFNode.class);
+         Selector<String> s2 = factory.get("foaf:knows/foaf:name#string-lv").withResultType(String.class);
+
+   .. java:method:: void setAdaptationFactory(au.id.djc.rdftemplate.selector.AdaptationFactory adaptationFactory)
+
+      Configures a custom :java:class:`AdaptationFactory` implementation for 
+      selectors created by this factory. If this setter is not called, an 
+      instance of :java:class:`DefaultAdaptationFactory 
+      <au.id.djc.rdftemplate.selector.DefaultAdaptationFactory>` will be used.
+
+   .. java:method:: void setPredicateResolver(au.id.djc.rdftemplate.selector.PredicateResolver predicateResolver)
+
+      Configures a custom :java:class:`PredicateResolver` implementation for 
+      selectors created by this factory. If this setter is not called, an 
+      instance of :java:class:`DefaultPredicateResolver 
+      <au.id.djc.rdftemplate.selector.DefaultPredicateResolver>` will be used.
+
+   .. java:method:: void setNamespacePrefixMap(java.util.Map<String, String> namespacePrefixMap)
+
+      Configure namespace prefix mappings for selectors created by this 
+      factory. If this setter is not called, no namespace prefixes will be 
+      defined.
+
+.. java:class:: au.id.djc.rdftemplate.selector.AdaptationFactory
+
+   Implement this interface if you would like to use custom adaptations in your 
+   selector expressions.
+
+   Your implementation should fall back to 
+   a :java:class:`DefaultAdaptationFactory 
+   <au.id.djc.rdftemplate.selector.DefaultAdaptationFactory>` instance, so that 
+   selector expressions have access to the builtin adaptations in addition to 
+   your custom ones.
+
+.. java:class:: au.id.djc.rdftemplate.selector.PredicateResolver
+
+   Implement this interface if you would like to use custom predicates in your 
+   selector expressions.
+
+   Your implementation should fall back to 
+   a :java:class:`DefaultPredicateResolver 
+   <au.id.djc.rdftemplate.selector.DefaultPredicateResolver>` instance, so that 
+   selector expressions have access to the builtin predicates in addition to 
+   your custom ones.
+
+.. java:class:: au.id.djc.rdftemplate.selector.EternallyCachingSelectorFactory
+
+   Wrap an :java:class:`AntlrSelectorFactory` with this class if you want to 
+   avoid compiling selectors anew every time. Do not use this class if the 
+   number of different selector expressions is unbounded, as it will cause heap 
+   exhaustion.
diff --git a/src/doc/sphinx/spring.rst b/src/doc/sphinx/spring.rst
@@ -0,0 +1,43 @@
+Integrating with Spring
+=======================
+
+Evaluating selector expressions
+-------------------------------
+
+You can define a :java:class:`SelectorFactory 
+<au.id.djc.rdftemplate.selector.SelectorFactory>` bean in your application 
+context:
+
+.. code-block:: xml
+
+    <bean id="selectorFactory" class="au.id.djc.rdftemplate.selector.EternallyCachingSelectorFactory">
+        <constructor-arg>
+            <bean class="au.id.djc.rdftemplate.selector.AntlrSelectorFactory">
+                <property name="adaptationFactory">
+                    <bean class="com.example.MyAdaptationFactory" />
+                </property>
+                <property name="predicateResolver">
+                    <bean class="com.example.MyPredicateResolver" />
+                </property>
+                <property name="namespacePrefixMap">
+                    <bean class="com.example.MyNamespacePrefixMapper" />
+                </property>
+            </bean>
+        </constructor-arg>
+    </bean>
+
+Rendering templates
+-------------------
+
+Similarly, a :java:class:`TemplateInterpolator` bean can be defined:
+
+.. code-block:: xml
+
+    <bean class="au.id.djc.rdftemplate.TemplateInterpolator">
+        <constructor-arg ref="selectorFactory" />
+    </bean>
+
+Views in Spring Web MVC
+-----------------------
+
+.. todo:: RDFTemplateViewResolver
diff --git a/src/doc/sphinx/xml-template.rst b/src/doc/sphinx/xml-template.rst
@@ -0,0 +1,269 @@
+XML templates
+=============
+
+Templates are pure XML, with special directives embedded in the document as 
+attributes and elements. Substitutions are also supported inside character data 
+and attribute values.
+
+The template syntax is inspired by the `Genshi`_ templating library for Python.
+
+.. _Genshi: http://genshi.edgewall.org/
+
+XML namespace
+-------------
+
+The XML elements and attributes handled by rdftemplate are defined in 
+a dedicated namespace:
+
+.. code-block:: none
+
+    http://code.miskinhill.com.au/rdftemplate/
+
+By convention this namespace is mapped to the prefix ``rdf``. For example:
+
+.. code-block:: xml
+
+   <html xmlns="http://www.w3.org/1999/xhtml"
+         xmlns:rdf="http://code.miskinhill.com.au/rdftemplate/">
+   ...
+   </html>    
+
+All declarations of the rdftemplate namespace are stripped from the resulting 
+document when a template is rendered.
+
+Substitutions in character data and attribute values
+----------------------------------------------------
+
+Templates may contain substitutions embedded in character data or in attribute 
+values. Substitutions are delimited by ``${`` and ``}`` and contain 
+a :doc:`selector expression <selector>`, which is evaluated with respect to the 
+current context node (passed to the :java:class:`TemplateInterpolator` when 
+rendering the template).
+
+The selector expression must have exactly one result when evaluated. The type 
+of the result affects how substitution is performed:
+
+* If the selector expression evaluates to an
+  `XML literal node <http://www.w3.org/TR/rdf-concepts/#section-XMLLiteral>`_ 
+  or an instance of :java:class:`XMLStream <au.id.djc.rdftemplate.XMLStream>`, 
+  the entire XML tree is inserted into the resulting document. (This 
+  substitution is only possible in character data; if it occurs in an attribute 
+  value, an exception will be thrown.)
+
+* If the selector expression evaluates to any other type of literal node, it 
+  will be converted to a Java type using Jena’s type conversion facilities, and 
+  then toString() will be called on the converted object.
+
+* If any other Java object is encountered, toString() will be called on it. 
+  This means that when a selector expression evaluates to a :java:class:`String 
+  <java.lang.String>`, it will be inserted as-is.
+
+Consider the following example of a template for describing an article in HTML. 
+It uses subtitutions in character data and in attribute values:
+
+.. code-block:: xml
+
+    <html xmlns="http://www.w3.org/1999/xhtml"
+          xmlns:rdf="http://code.miskinhill.com.au/rdftemplate/">
+        <head>
+            <title>${dc:title#string-lv}</title>
+            <meta name="DC.creator" content="${dc:creator#string-lv}" />
+        </head>
+        <body>
+            <p>Title: ${dc:title}</p>
+        </body>
+    </html>
+
+In this example, the object of ``dc:title`` might be an XML literal containing 
+an HTML ``<span>`` element. The ``#string-lv`` :ref:`adaptation <adaptations>` 
+is used to strip markup from XML literals in the ``<title>`` element and the 
+``content`` attribute, where markup is not permitted. On the other hand, the 
+title’s complete XML tree will be inserted into the ``<p>`` element with all 
+markup preserved.
+
+This example will also work correctly if the object of ``dc:title`` is a plain 
+literal rather than an XML literal, since ``#string-lv`` will pass the plain 
+literal through untouched.
+
+Substitutions with ``rdf:content``
+----------------------------------
+
+The ``rdf:content`` attribute is used to replace an element’s content with the 
+result of evaluating a selector expression. The selector expression must have 
+exactly one result when evaluated. For example:
+
+.. code-block:: xml
+
+    <html xmlns="http://www.w3.org/1999/xhtml"
+          xmlns:rdf="http://code.miskinhill.com.au/rdftemplate/">
+        <body>
+            <h1 rdf:content="dc:title" />
+        </body>
+    </html>
+
+The ``rdf:content`` attribute is stripped from the resulting document. The 
+substitution rules described above also apply for ``rdf:content`` (so XML 
+literals will be inserted as-is into the resulting document), with one minor 
+enhancement: if the selector expression evaluates to a literal node with 
+a language tag, that language will be set on the enclosing element in an 
+`xml:lang <http://www.w3.org/TR/REC-xml/#sec-lang-tag>`_ attribute (and also an 
+XHTML ``lang`` attribute, if the document uses the XHTML namespace).
+
+If the object of the ``dc:title`` property is the literal ``"Война и мир"@ru`` 
+in the example above, then the template would be rendered as:
+
+.. code-block:: xml
+
+    <html xmlns="http://www.w3.org/1999/xhtml">
+        <body>
+            <h1 xml:lang="ru" lang="ru">Война и мир</h1>
+        </body>
+    </html>
+
+Note that if the element has any content in the template, this will be 
+discarded when rendering.
+
+Repetition with ``rdf:for``
+---------------------------
+
+The ``rdf:for`` attribute can be used to loop over zero or more results from 
+a selector expression. For each node in the results, the element and its 
+subtree will be rendered using that node as the context node. All template 
+constructs may be nested inside the subtree, including other ``rdf:for`` loops.
+
+For example, given the following RDF graph:
+
+.. include:: example-graph.rst.inc
+
+the following template could be used to produce an HTML listing of the people 
+who are known to a particular person:
+
+.. code-block:: xml
+
+    <html xmlns="http://www.w3.org/1999/xhtml"
+          xmlns:rdf="http://code.miskinhill.com.au/rdftemplate/">
+        <body>
+            <h1>${foaf:name}’s buddies</h1>
+            <ul>
+                <li rdf:for="foaf:knows(foaf:name)">
+                    <a href="#uri" rdf:content="foaf:name" />
+                </li>
+            </ul>
+        </body>
+    </html>
+
+If ``<bob>`` is used as the context node, the ``foaf:knows(foaf:name)`` 
+expression will select two nodes: ``<alice>`` and ``<carol>``, in that order. 
+The ``<li>`` element will therefore be rendered twice, the first time with its 
+context node set to ``<alice>``, the second time set to ``<carol>``. The 
+resulting XML would be:
+
+.. code-block:: xml
+
+    <html xmlns="http://www.w3.org/1999/xhtml">
+        <body>
+            <h1>Bob’s buddies</h1>
+            <ul>
+                <li><a href="alice">Alice</a></li>
+                <li><a href="carol">Carol</a></li>
+            </ul>
+        </body>
+    </html>
+
+``rdf:for`` can also be given as an XML element, with its selector expression 
+in an attribute named ``each``. This will be rendered in the same way, except 
+that the entire ``rdf:for`` element is stripped out. In the example above, 
+``<li rdf:for="foaf:knows(foaf:name)">...</li>`` is equivalent to ``<rdf:for 
+each="foaf:knows(foaf:name)"><li>...</li></rdf:for>``.
+
+Because of the potential for ambiguity, it is illegal to combine ``rdf:for`` 
+with other directives on the same element.
+
+Concatenation with ``rdf:join``
+-------------------------------
+
+The ``rdf:join`` element behaves in the same way as the ``rdf:for`` element, 
+but it also accepts a ``separator`` attribute, which specifies a string to be 
+inserted between each repetition.
+
+For example, here is a briefer version of the template above:
+
+.. code-block:: xml
+
+    <html xmlns="http://www.w3.org/1999/xhtml"
+          xmlns:rdf="http://code.miskinhill.com.au/rdftemplate/">
+        <body>
+            <p>${foaf:name}’s buddies:
+            <rdf:join each="foaf:knows(foaf:name)" separator=", ">
+                <a href="#uri" rdf:content="foaf:name" />
+            </rdf:join>
+            </p>
+        </body>
+    </html>
+
+Conditionals with ``rdf:if``
+----------------------------
+
+The ``rdf:if`` attribute will cause an element and its subtree to be included 
+in the resulting document only if the selector expression evaluates to *one or 
+more* items. Use a :ref:`predicate <predicates>` in the selector expression to 
+express complex conditions. For example:
+
+.. code-block:: xml
+
+    <html xmlns="http://www.w3.org/1999/xhtml"
+          xmlns:rdf="http://code.miskinhill.com.au/rdftemplate/">
+        <body>
+            <p rdf:if="dc:identifier[uri-prefix='urn:issn:']">
+                ISSN: ${dc:identifier#uri-slice(9)}
+            </p>
+        </body>
+    </html>
+
+When rendering this template, the ``<p>`` element will only be included if 
+there is some object of the ``dc:identifier`` property which satisfies the 
+``uri-prefix='urn:issn:'`` predicate.
+
+There is also an element form of ``rdf:if``. Use the ``test`` attribute to 
+specify the selector expression to test against, or the ``not`` attribute to 
+apply an inverse test.
+
+A pair of ``rdf:if`` elements can be used to make a choice between two 
+alternatives. For example:
+
+.. code-block:: xml
+
+    <html xmlns="http://www.w3.org/1999/xhtml"
+          xmlns:rdf="http://code.miskinhill.com.au/rdftemplate/">
+        <body>
+            <p>
+                <rdf:if test="ex:thumbnail"><img src="${ex:thumbnail#uri}" /></rdf:if>
+                <rdf:if not="ex:thumbnail">No thumbnail available :-(</rdf:if>
+            </p>
+        </body>
+    </html>
+
+Rendering templates
+-------------------
+
+.. java:class:: au.id.djc.rdftemplate.TemplateInterpolator
+
+   Use this class to render templates. Instances of this class can safely be 
+   shared across threads (for example, as singleton beans in Spring).
+
+   .. java:method:: TemplateInterpolator(au.id.djc.rdftemplate.selector.SelectorFactory selectorFactory)
+
+      The given :java:class:`SelectorFactory 
+      <au.id.djc.rdftemplate.selector.SelectorFactory>` will be used to 
+      evaluate selector expressions when rendering templates.
+
+   .. java:method:: java.lang.String interpolate(java.io.Reader reader, com.hp.hpl.jena.rdf.model.RDFNode node)
+
+      Reads a template from the given :java:class:`Reader <java.io.Reader>`, 
+      and renders it using the given node as context. The resulting XML 
+      document is returned.
+
+      A number of overrides of this method also exist for advanced use cases. 
+      Refer to the `Javadoc for TemplateInterpolator 
+      <http://code.djc.id.au/rdftemplate/javadoc/latest/au/id/djc/rdftemplate/TemplateInterpolator.html>`_ 
+      for more details.
diff --git a/src/site/site.xml b/src/site/site.xml
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/DECORATION/1.0.0"
-        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-        xsi:schemaLocation="http://maven.apache.org/DECORATION/1.0.0 http://maven.apache.org/xsd/decoration-1.0.0.xsd">
-    <body>
-        <menu ref="reports" />
-    </body>
-</project>