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:
| A | src/doc/sphinx/_static/default.css | | | 88 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/doc/sphinx/_templates/layout.html | | | 70 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/doc/sphinx/_templates/localtoc.html | | | 6 | ++++++ |
| A | src/doc/sphinx/_templates/searchbox.html | | | 12 | ++++++++++++ |
| A | src/doc/sphinx/conf.py | | | 175 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/doc/sphinx/example-graph.rst.inc | | | 20 | ++++++++++++++++++++ |
| A | src/doc/sphinx/index.rst | | | 57 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/doc/sphinx/selector.rst | | | 296 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/doc/sphinx/spring.rst | | | 43 | +++++++++++++++++++++++++++++++++++++++++++ |
| A | src/doc/sphinx/xml-template.rst | | | 269 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| D | src/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> »
+ {%- 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>