Commit 60354f20 authored by Carlos Garnacho's avatar Carlos Garnacho

docs: Rework ontology docs generation entirely

Ontology docs weren't in a much good shape, besides many ontologies
being seriously underdocumented (something which should improve
separately), the generated docs were little more than a data dump,
and the diagrams shown were broken, confusing, or both. This all
amounts to quite counter-productive developer docs.

So the ontology docs have been refurbished, the per-ontology
descriptions are still useful, but have been stripped of all images,
and the docs overall are now completely class-centric, per
rdfs:Resource subclass we now get:

- Ascii diagram of its local hierarchy, up to all its ancestors and
  down to all its direct children.
- All properties that affect the specific class. This is notably
  more intuitive now as there's properties defined on one ontology
  that are in the domain of classes in another ontology, something
  which you couldn't get at a glance in the previous docs
- It clearly states which properties supersede which superproperties,
  which again makes it easier if those apply for the class at hand.

The result feels quite neater, and will indeed be more resembling
to other gtk-doc generated API docs.
parent 79589d67
......@@ -18,13 +18,4 @@
<title>Special remarks</title>
<para>In some feeds, like <ulink url="">"Yahoo Media RSS</ulink>, there can be multiple enclosures together in a group, representing the same resource in different formats, qualities, resolutions, etc. Until further notify, the group will be represented using <link linkend="nie-identifier">nie:identifier</link> property . To mark the default enclosure of the group, there is a <link linkend="mfo-groupDefault">mfo-groupDefault</link> property</para>
<refsect2 id="mfo-graphical-overview">
<figure id="mfo-ontology-graph">
<title>Graphical Overview</title>
<graphic fileref="feeds-overview.png" format="PNG"></graphic>
<para>Notation defined <link linkend="ontology-notation">in this page</link></para>
......@@ -55,13 +55,4 @@
<para><link linkend="mlo-LandmarkCategory">mlo:LandmarkCategory</link> has a property <link linkend="mlo-isRemovable">mlo:isRemovable</link> to mark is the category is predefined and shouldn't be deleted by the applications. Tracker (and probably other backends) doesn't enforce applications to respect this value, but consider it a gentleman agreement.</para>
<refsect2 id="mlo-graphical-overview">
<figure id="mlo-ontology-graph">
<title>Graphical Overview</title>
<graphic fileref="location-overview.png" format="PNG"></graphic>
<para>Notation defined <link linkend="ontology-notation">in this page</link></para>
......@@ -148,15 +148,6 @@ its album).
<refsect2 id="nie-graphical-overview">
<figure id="nie-ontology-graph">
<title>Graphical Overview</title>
<graphic fileref="overview.png" format="PNG"></graphic>
<para>Notation defined <link linkend="ontology-notation">in this page</link></para>
<refsect2 id="nie-related-information">
<title>Related information</title>
......@@ -16,39 +16,13 @@
<para>The core of images in NMM ontology is the class <link linkend="nmm-Photo">nmm:Photo.</link> It is (through a long hierarchy) a <link linkend="nie-InformationElement">nie:InformationElement</link>, an interpretation of some bytes. It has properties to store the basic information (camera, metering mode, white balance, flash), and inherits from <link linkend="nfo-Image">nfo:Image</link> orientation (<link linkend="nfo-orientation">nfo:orientation</link>) and resolution (<link linkend="nfo-verticalResolution">nfo:verticalResolution</link> and <link linkend="nfo-horizontalResolution">nfo:horizontalResolution</link>).</para>
<para>Note that for tags, nie:keywords (from nie:InformationElement) can be used, or the <link linkend="nao-ontology">NAO</link> ontology.</para>
<figure id="nmm-image-graph">
<title>Graphical Overview (images domain)</title>
<graphic fileref="images-overview.png" format="PNG"></graphic>
<para>Notation defined <link linkend="ontology-notation">in this page</link></para>
<title>Music domain</title>
<!-- Dont forget to mention the wa... uPnP -->
<figure id="nmm-music-graph">
<title>Graphical Overview (music domain)</title>
<graphic fileref="music-overview.png" format="PNG"></graphic>
<para>Notation defined <link linkend="ontology-notation">in this page</link></para>
<title>Radio domain</title>
<para>NMM includes classes and properties to represent analog and digital radio stations. There is a class <link linkend="nmm-RadioStation">nmm:RadioStation</link> on the <link linkend="nie-InformationElement">nie:InformationElement</link> side of the ontology, representing what the user sees about that station (genre via PTY codes, icon, plus title inherited from nie:InformationElement)</para>
<para>A <link linkend="nmm-RadioStation">nmm:RadioStation</link> can have one or more <link linkend="nmm-carrier">nmm:carrier</link> properties representing the different frequencies (or links when it is digitial) it can be tuned. This property links the station with <link linkend="nfo-MediaStream">nfo:MediaStream</link>, but usually it will point to one of the subclasses: <link linkend="nmm-DigitalRadio">nmm:DigitalRadio</link> (if digital) or <link linkend="nmm-AnalogRadio">nmm:AnalogRadio</link> (if analog). An analog station has properties as modulation and frequency, while the digial station has streaming bitrate, encoding or protocol.</para>
<para>Note that nfo:MediaStream refers to a flux of bytes/data, and it is on the <link linkend="nie-DataObject">nie:DataObject</link> side of the ontology</para>
<figure id="nmm-radio-graph">
<title>Graphical Overview (radio domain)</title>
<graphic fileref="radio-overview.png" format="PNG"></graphic>
<para>Notation defined <link linkend="ontology-notation">in this page</link></para>
\ No newline at end of file
......@@ -19,13 +19,6 @@
<listitem><para> <link linkend="nmo-isSent">nmo:isSent</link> should be used to indicate the direction of the message. This helps with the performance of queries to build a conversation view.</para></listitem>
<listitem><para> Even when there is a <link linkend="nmo-MessageHeader">nmo:MessageHeader</link> class that can store any arbitrary pair of key-values, its use must be as limited as possible. It is there to store the specific headers in the messages (mainly email) that cannot be completely represented in the ontology. Handle those headers in queries is a performance bottleneck that should be avoided in general.</para></listitem>
<figure id="nmo-message-graph">
<title>Graphical Overview (Message class)</title>
<graphic fileref="message-class-overview.png" format="PNG"></graphic>
<para>Notation defined <link linkend="ontology-notation">in this page</link></para>
<sect2 id="nmo-conversation-representation">
......@@ -42,19 +35,6 @@
<para>The ontology represents completely that email tree. The Envelope, root node or more external representation of the Email is the basic <link linkend="nmo-Email">nmo:Email</link> class, subclass of Message. Every node in the tree is always a <link linkend="nmo-MimePart">nmo:MimePart</link> with the required properties to decode the content (mimetype, encoding, boundaries). When the node is internal, then it is also instance of <link linkend="nmo-MultiPart">nmo:MultiPart</link> so it can use the <link linkend="nie-hasPart">nie:hasPart</link> property to link other nodes. The leaf nodes can be instances of specific content classes (besides <link linkend="nmo-MimePart">nmo:MimePart</link>). For example, an MP3 embedded in an Email, will be represented as an instance nmo:MimePart <emphasis>and</emphasis> <link linkend="nmm-MusicPiece">nmm:MusicPiece</link>. </para>
<para>For more detailed (and highly technical) explanation of the email representation in general and this example in concrete, please check <ulink url="">this wiki page</ulink></para>
<figure id="nmo-message-graph">
<title>Graphical Overview (Email related classes)</title>
<graphic fileref="email-mimeparts-overview.png" format="PNG"></graphic>
<para>Notation defined <link linkend="ontology-notation">in this page</link></para>
<sect2 id="nmo-accounts-representation">
<title>Email accounts</title>
<para>Explain here MailAccount and MailFolder</para>
<!-- FIXME complete -->
<sect2 id="nmo-sms-domain">
......@@ -35,40 +35,13 @@ ONTOLOGY_EXPLANATIONS = \
$(top_srcdir)/docs/ontologies/nco/explanation.xml \
# The XMLs to generate from the Ontology info
# - nid3 is not used by Nepomuk
# - nrl is internal, not public
xsd-ontology.xml \
rdf-ontology.xml \
dc-ontology.xml \
nie-ontology.xml \
nao-ontology.xml \
nfo-ontology.xml \
nco-ontology.xml \
nmo-ontology.xml \
ncal-ontology.xml \
scal-ontology.xml \
nmm-ontology.xml \
mto-ontology.xml \
mlo-ontology.xml \
mfo-ontology.xml \
mtp-ontology.xml \
slo-ontology.xml \
tracker-ontology.xml \
maemo-ontology.xml \
# Generation of the ontology XML files.
$(top_srcdir)/docs/tools/ $(top_builddir)/docs/tools/ttl2sgml $(top_srcdir)/src/ontologies $(top_srcdir)/docs/ontologies .
mkdir xml
$(top_srcdir)/docs/tools/ $(top_builddir)/docs/tools/ttl2sgml $(top_builddir)/docs/tools/ttlresource2sgml $(top_srcdir)/src/ontologies $(top_srcdir)/docs/ontologies xml/
$(AM_V_GEN) touch $@
# Make the final XML files depend on the stamp
$(ONTOLOGY_INFOS_XML): gen-doc.stamp
version.xml: gen-doc.stamp
# The name of the module.
DOC_MODULE = ontology
......@@ -85,17 +58,8 @@ MKDB_OPTIONS = --sgml-mode --output-format=xml
# Extra options to supply to gtkdoc-mkhtml
# Images to copy into HTML directory
# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE)
# Note that PNG files are also added in content_files so that
# the documentation is not built before the PNGs.
content_files = \
expand_content_files =
......@@ -109,13 +73,9 @@ include $(top_srcdir)/gtk-doc.make
# Note that HTML_FILES and content_files are already included
# by gtk-doc
gen-doc.stamp \ \
# PNGs and XMLs generated are removed only in maintainer-clean
......@@ -3,27 +3,6 @@
"" [
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED ''">
<!ENTITY version SYSTEM "version.xml">
<!ENTITY xsd-ontology SYSTEM "xsd-ontology.xml">
<!ENTITY rdf-ontology SYSTEM "rdf-ontology.xml">
<!--<!ENTITY nrl-ontology SYSTEM "nrl-ontology.xml"> - Internal -->
<!ENTITY dc-ontology SYSTEM "dc-ontology.xml">
<!ENTITY nie-ontology SYSTEM "nie-ontology.xml">
<!ENTITY nao-ontology SYSTEM "nao-ontology.xml">
<!ENTITY nfo-ontology SYSTEM "nfo-ontology.xml">
<!ENTITY nco-ontology SYSTEM "nco-ontology.xml">
<!ENTITY nmo-ontology SYSTEM "nmo-ontology.xml">
<!ENTITY ncal-ontology SYSTEM "ncal-ontology.xml">
<!ENTITY scal-ontology SYSTEM "scal-ontology.xml">
<!--<!ENTITY nid3-ontology SYSTEM "nid3-ontology.xml"> - Not using -->
<!ENTITY nmm-ontology SYSTEM "nmm-ontology.xml">
<!ENTITY mto-ontology SYSTEM "mto-ontology.xml">
<!ENTITY mlo-ontology SYSTEM "mlo-ontology.xml">
<!ENTITY mfo-ontology SYSTEM "mfo-ontology.xml">
<!ENTITY mtp-ontology SYSTEM "mtp-ontology.xml">
<!ENTITY slo-ontology SYSTEM "slo-ontology.xml">
<!ENTITY tracker-ontology SYSTEM "tracker-ontology.xml">
<!ENTITY maemo-ontology SYSTEM "maemo-ontology.xml">
<!ENTITY fts-properties SYSTEM "fts-properties.xml">
<book id="index">
......@@ -37,7 +16,7 @@
<part id="ontology">
<part id="overview">
......@@ -56,50 +35,28 @@
This is just documentation about the ontologies. For more information about Tracker technical details and implementation, please refer to the Tracker <ulink url="">Documentation wiki</ulink> page in GNOME.
<!-- &nrl-ontology; - Internal -->
<!-- &nid3-ontology; - Not using -->
<part id="ontology-notation-description">
Notation used in the diagrams describing each ontology.
<figure id="ontology-notation">
<title>Notation for ontology description</title>
<graphic fileref="notation.png" format="PNG"></graphic>
<part id="ontology-graphs">
<title>The big picture</title>
This is a graph that shows how different classes in the ontology are related:
<figure id="ontology-graph">
<title>Ontology classes and their relations</title>
<graphic fileref="ontology.png" format="PNG"></graphic>
<part id="ontology">
<xi:include href="xml/xsd-ontology.xml" />
<xi:include href="xml/rdf-ontology.xml" />
<xi:include href="xml/dc-ontology.xml" />
<xi:include href="xml/nie-ontology.xml" />
<xi:include href="xml/nao-ontology.xml" />
<xi:include href="xml/nfo-ontology.xml" />
<xi:include href="xml/nco-ontology.xml" />
<xi:include href="xml/nmo-ontology.xml" />
<xi:include href="xml/ncal-ontology.xml" />
<xi:include href="xml/scal-ontology.xml" />
<xi:include href="xml/nmm-ontology.xml" />
<xi:include href="xml/mto-ontology.xml" />
<xi:include href="xml/mlo-ontology.xml" />
<xi:include href="xml/mfo-ontology.xml" />
<xi:include href="xml/mtp-ontology.xml" />
<xi:include href="xml/slo-ontology.xml" />
<xi:include href="xml/tracker-ontology.xml" />
<xi:include href="xml/maemo-ontology.xml" />
<xi:include href="xml/libosinfo-ontology.xml" />
noinst_PROGRAMS = ontology-graph ttl2sgml
noinst_PROGRAMS = ontology-graph ttl2sgml ttlresource2sgml
......@@ -17,15 +17,22 @@ LDADD = \
ontology_graph_SOURCES = \
ttl2sgml_SOURCES = \
ttl2sgml.c \
ttl_loader.h \
ttl_loader.c \
ttl_model.h \
ttl_loader.h \
ttl_model.c \
qname.h \
qname.c \
ttl_model.h \
ttl_sgml.c \
ttl_sgml.h \
qname.c \
ttl2sgml_SOURCES = \
ttlresource2sgml_SOURCES = \
......@@ -19,35 +19,20 @@
# 02110-1301, USA.
if [ $# -lt 4 ]; then
if [ $# -lt 5 ]; then
echo "Insufficient arguments provided"
echo "Usage: $0 <ttl2sgml> <ontology-data-dir> <ontology-info-dir> <build-dir>"
echo "Usage: $0 <ttl2sgml> <ttlres2sgml> <ontology-data-dir> <ontology-info-dir> <build-dir>"
exit 1;
echo "Building ontology documentation..."
echo "- Preparing file full text index properties (fts-properties.xml)"
echo "<?xml version='1.0' encoding='UTF-8'?>
<chapter id='fts-properties'>
<title>Full-text indexed properties in the ontology</title>
<table frame='all'>
<colspec colname='Property'/>
<colspec colname='Weigth'/>
<tbody>" > $BUILD_DIR/fts-properties.xml
echo "Building class documentation..."
for f in `find $ONTOLOGIES_DATA_DIR -name "*.description"` ; do
# ../../src/ontologies/XX-aaa.description -> PREFIX=aaa
......@@ -55,10 +40,8 @@ for f in `find $ONTOLOGIES_DATA_DIR -name "*.description"` ; do
echo "- Generating $PREFIX documentation"
$TTL2SGML -d $f -o $BUILD_DIR/$PREFIX-ontology.xml -f $BUILD_DIR/fts-properties.xml \
$TTL2SGML -d $f -o $BUILD_DIR/$PREFIX-ontology.xml \
-e $ONTOLOGIES_INFO_DIR/$PREFIX/explanation.xml
echo "</tbody></table></chapter>" >> $BUILD_DIR/fts-properties.xml
echo "Done"
......@@ -27,7 +27,6 @@
static gchar *desc_file = NULL;
static gchar *output_file = NULL;
static gchar *fts_properties_file = NULL;
static gchar *explanation_file = NULL;
static GOptionEntry entries[] = {
......@@ -39,10 +38,6 @@ static GOptionEntry entries[] = {
"File to write the output (default stdout)",
{ "fts", 'f', 0, G_OPTION_ARG_FILENAME, &fts_properties_file,
"Output file listing the full text indexed properties",
{ "explanation", 'e', 0, G_OPTION_ARG_FILENAME, &explanation_file,
"Verbosy explanation file in HTML format to include in the webpage",
......@@ -59,7 +54,6 @@ main (gint argc, gchar **argv)
gchar *ttl_file = NULL;
gchar *dirname = NULL;
FILE *fts = NULL;
/* Translators: this messagge will apper immediately after the */
/* usage string - Usage: COMMAND [OPTION]... <THIS_MESSAGE> */
......@@ -91,10 +85,6 @@ main (gint argc, gchar **argv)
g_assert (f != NULL);
if (fts_properties_file) {
fts = fopen (fts_properties_file, "a");
description = ttl_loader_load_description (desc_file);
dirname = g_path_get_dirname (desc_file);
......@@ -106,7 +96,7 @@ main (gint argc, gchar **argv)
g_free (ttl_file);
g_free (dirname);
ttl_sgml_print (description, ontology, f, fts, explanation_file);
ttl_sgml_print (description, ontology, f, explanation_file);
ttl_loader_free_ontology (ontology);
ttl_loader_free_description (description);
......@@ -115,9 +105,5 @@ main (gint argc, gchar **argv)
fclose (f);
if (fts) {
fclose (fts);
return 0;
......@@ -19,6 +19,7 @@
#include "ttl_loader.h"
#include <glib/gstdio.h>
#include <gio/gio.h>
#include <libtracker-data/tracker-sparql-query.h>
......@@ -40,6 +41,7 @@
#define TRACKER_FTS_INDEXED TRACKER_NS "fulltextIndexed"
......@@ -165,6 +167,12 @@ load_in_memory (Ontology *ontology,
prop->weight = g_strdup (turtle_object);
} else if (!g_strcmp0 (turtle_predicate, TRACKER_PREFIX)) {
/* A tracker:prefix on a tracker:Namespace */
g_hash_table_insert (ontology->prefixes,
g_strdup (turtle_subject),
g_strdup (turtle_object));
} else if (!g_strcmp0 (turtle_predicate, RDFS_COMMENT)) {
OntologyClass *klass;
OntologyProperty *prop;
......@@ -334,6 +342,7 @@ ttl_loader_load_ontology (const gchar *ttl_file)
Ontology *ontology;
g_print ("Loading ontology... %s\n", ttl_file);
ontology = g_new0 (Ontology, 1);
ontology->classes = g_hash_table_new_full (g_str_hash,
......@@ -344,6 +353,9 @@ ttl_loader_load_ontology (const gchar *ttl_file)
ontology->prefixes = g_hash_table_new_full (g_str_hash,
g_free, g_free);
if (ttl_file) {
TrackerTurtleReader *reader;
......@@ -371,6 +383,93 @@ ttl_loader_load_ontology (const gchar *ttl_file)
return ontology;
static GList *
get_ontology_files (GFile *dir)
GFileEnumerator *enumerator;
GFileInfo *info;
GList *files;
const gchar *name;
enumerator = g_file_enumerate_children (dir,
if (!enumerator) {
return NULL;
files = NULL;
while ((info = g_file_enumerator_next_file (enumerator, NULL, NULL)) != NULL) {
name = g_file_info_get_name (info);
if (g_str_has_suffix (name, ".ontology")) {
files = g_list_insert_sorted (files, g_strdup (name),
(GCompareFunc) g_strcmp0);
g_object_unref (info);
g_object_unref (enumerator);
return files;
Ontology *
ttl_loader_load_ontology_dir (const gchar *ttl_dir)
GFile *dir = g_file_new_for_path (ttl_dir);
Ontology *ontology;
GList *files, *f;
ontology = g_new0 (Ontology, 1);
ontology->classes = g_hash_table_new_full (g_str_hash,
ontology->properties = g_hash_table_new_full (g_str_hash,
ontology->prefixes = g_hash_table_new_full (g_str_hash,
g_free, g_free);
files = get_ontology_files (dir);
g_object_unref (dir);
for (f = files; f; f = f->next) {
TrackerTurtleReader *reader;
GError *error = NULL;
gchar *ttl_file;
ttl_file = g_build_filename (ttl_dir, f->data, NULL);
reader = tracker_turtle_reader_new (ttl_file, NULL);
g_free (ttl_file);
while (error == NULL && tracker_turtle_reader_next (reader, &error)) {
load_in_memory (ontology,
tracker_turtle_reader_get_subject (reader),
tracker_turtle_reader_get_predicate (reader),
tracker_turtle_reader_get_object (reader));
g_object_unref (reader);
if (error) {
g_message ("Turtle parser error: %s", error->message);
g_error_free (error);
return ontology;
OntologyDescription *
ttl_loader_load_description (const gchar *filename)
......@@ -406,6 +505,7 @@ ttl_loader_free_ontology (Ontology *ontology)
g_hash_table_destroy (ontology->classes);
g_hash_table_destroy (ontology->properties);
g_hash_table_destroy (ontology->prefixes);
g_free (ontology);
......@@ -29,6 +29,7 @@ void ttl_loader_init (void);
void ttl_loader_shutdown (void);
Ontology * ttl_loader_load_ontology (const gchar *filename);
Ontology * ttl_loader_load_ontology_dir(const gchar *dir);
OntologyDescription * ttl_loader_load_description (const gchar *filename);
void ttl_loader_free_ontology (Ontology *ontology);
......@@ -67,6 +67,7 @@ typedef struct {
typedef struct {
GHashTable *classes;
GHashTable *properties;
GHashTable *prefixes;
} Ontology;
......@@ -81,66 +81,6 @@ print_link_as_varlistentry (FILE *f,
g_fprintf (f, " </varlistentry>\n");
static gchar *
shortname_to_id (const gchar *name)
gchar *id, *p;
id = g_strdup (name);
p = strchr (id, ':');
if (p) {
*p = '-';
return id;
static void
print_reference (gpointer item, gpointer user_data)
gchar *shortname, *id;
FILE *f = (FILE *)user_data;
shortname = qname_to_shortname ((gchar *) item);
id = shortname_to_id (shortname);
g_fprintf (f,"<link linkend='%s'>%s</link>, ", id , shortname);
g_free (shortname);
g_free (id);
static void
print_variablelist_entry (FILE *f,
const gchar *param,
const gchar *value)
g_fprintf (f, "<varlistentry>\n");
g_fprintf (f, "<term><parameter>%s</parameter>&#160;:</term>\n", param);
g_fprintf (f, "<listitem><simpara>%s</simpara></listitem>\n", (value) ? value : "--");
g_fprintf (f, "</varlistentry>\n");
static void
print_variablelist_entry_list (FILE *f,
const gchar *param,
GList *list)
g_fprintf (f, "<varlistentry>\n");
g_fprintf (f, "<term><parameter>%s</parameter>&#160;:</term>\n", param);
g_fprintf (f, "<listitem><simpara>");
if (list) {
g_list_foreach (list, print_reference, f);
} else {
g_fprintf (f, "--");
g_fprintf (f, "</simpara></listitem>\n");
g_fprintf (f, "</varlistentry>\n");
#if 0
static void
print_deprecated_message (FILE *f)
......@@ -158,6 +98,10 @@ print_sgml_header (FILE *f, OntologyDescription *desc)
gchar *upper_name;
g_fprintf (f, "<?xml version='1.0' encoding='UTF-8'?>\n");
g_fprintf (f, "<!DOCTYPE book PUBLIC \"-//OASIS//DTD DocBook XML V4.1.2//EN\"\n"
" \"\" [\n");
g_fprintf (f, "<!ENTITY %% local.common.attrib \"xmlns:xi CDATA #FIXED ''\">\n");
g_fprintf (f, "]>");
g_fprintf (f, "<chapter id='%s-ontology'>\n", desc->localPrefix);
......@@ -200,144 +144,80 @@ print_sgml_footer (FILE *f)
g_fprintf (f,"</chapter>\n");
static void
print_ontology_class (gpointer key, gpointer value, gpointer user_data)
static gchar *
name_get_prefix (Ontology *ontology,
const gchar *name)
OntologyClass *def = (OntologyClass *)value;
gchar *name, *id;
FILE *f = (FILE *)user_data;
const gchar *delim;
g_return_if_fail (f != NULL);
name = qname_to_shortname (def->classname);
delim = g_strrstr (name, "#");
id = shortname_to_id (name);
g_fprintf (f, "<refsect2 id='%s'>\n", id);
if (!delim)
delim = g_strrstr (name, "/");
g_free (id);
if (!delim)
return NULL;
g_fprintf (f, "<title>%s</title>\n", name);
if (def->description) {
g_fprintf (f, "<para>%s</para>\n", def->description);
g_fprintf (f, "<variablelist>\n");
print_variablelist_entry_list (f, "Superclasses", def->superclasses);
print_variablelist_entry_list (f, "Subclasses", def->subclasses);
print_variablelist_entry_list (f, "In domain of", def->in_domain_of);
print_variablelist_entry_list (f, "In range of", def->in_range_of);
if (def->instances) {
print_variablelist_entry_list (f, "Predefined instances", def->instances);
g_fprintf (f, "</variablelist>\n");