summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Garnacho <carlosg@gnome.org>2015-06-29 01:10:57 +0200
committerCarlos Garnacho <carlosg@gnome.org>2015-06-30 20:35:10 +0200
commit60354f20b49f910095ee1e207d6f44a88ad6e6cc (patch)
treefa666efae15c59d7f4d7d15a0ec97685a5434fce
parent79589d67d3aa6084e633e2a3919c4e6d80a2512f (diff)
downloadtracker-60354f20b49f910095ee1e207d6f44a88ad6e6cc.tar.gz
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.
-rw-r--r--docs/ontologies/mfo/explanation.xml9
-rw-r--r--docs/ontologies/mlo/explanation.xml9
-rw-r--r--docs/ontologies/nie/explanation.xml9
-rw-r--r--docs/ontologies/nmm/explanation.xml28
-rw-r--r--docs/ontologies/nmo/explanation.xml20
-rw-r--r--docs/reference/ontology/Makefile.am48
-rw-r--r--docs/reference/ontology/ontology-docs.sgml87
-rw-r--r--docs/tools/Makefile.am23
-rwxr-xr-xdocs/tools/gen-doc.sh35
-rw-r--r--docs/tools/ttl2sgml.c16
-rw-r--r--docs/tools/ttl_loader.c100
-rw-r--r--docs/tools/ttl_loader.h1
-rw-r--r--docs/tools/ttl_model.h1
-rw-r--r--docs/tools/ttl_sgml.c225
-rw-r--r--docs/tools/ttl_sgml.h1
-rw-r--r--docs/tools/ttlresource2sgml.c820
16 files changed, 1024 insertions, 408 deletions
diff --git a/docs/ontologies/mfo/explanation.xml b/docs/ontologies/mfo/explanation.xml
index d97d7c99f..d78aff3e1 100644
--- a/docs/ontologies/mfo/explanation.xml
+++ b/docs/ontologies/mfo/explanation.xml
@@ -18,13 +18,4 @@
<title>Special remarks</title>
<para>In some feeds, like <ulink url="http://video.search.yahoo.com/mrss">"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>
</sect2>
-
- <refsect2 id="mfo-graphical-overview">
- <figure id="mfo-ontology-graph">
- <title>Graphical Overview</title>
- <graphic fileref="feeds-overview.png" format="PNG"></graphic>
- </figure>
- <para>Notation defined <link linkend="ontology-notation">in this page</link></para>
- </refsect2>
-
</section>
diff --git a/docs/ontologies/mlo/explanation.xml b/docs/ontologies/mlo/explanation.xml
index 7e419f8c0..8296bc640 100644
--- a/docs/ontologies/mlo/explanation.xml
+++ b/docs/ontologies/mlo/explanation.xml
@@ -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>
-
-
- <refsect2 id="mlo-graphical-overview">
- <figure id="mlo-ontology-graph">
- <title>Graphical Overview</title>
- <graphic fileref="location-overview.png" format="PNG"></graphic>
- </figure>
- <para>Notation defined <link linkend="ontology-notation">in this page</link></para>
- </refsect2>
</section>
diff --git a/docs/ontologies/nie/explanation.xml b/docs/ontologies/nie/explanation.xml
index 1ee15fd19..b0d9ebd7a 100644
--- a/docs/ontologies/nie/explanation.xml
+++ b/docs/ontologies/nie/explanation.xml
@@ -148,15 +148,6 @@ its album).
</refsect2>
-
- <refsect2 id="nie-graphical-overview">
- <figure id="nie-ontology-graph">
- <title>Graphical Overview</title>
- <graphic fileref="overview.png" format="PNG"></graphic>
- </figure>
- <para>Notation defined <link linkend="ontology-notation">in this page</link></para>
- </refsect2>
-
<refsect2 id="nie-related-information">
<title>Related information</title>
diff --git a/docs/ontologies/nmm/explanation.xml b/docs/ontologies/nmm/explanation.xml
index e55d81016..0da24c25e 100644
--- a/docs/ontologies/nmm/explanation.xml
+++ b/docs/ontologies/nmm/explanation.xml
@@ -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>
-</figure>
</sect2>
<sect2>
- <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>
-</figure>
-
-</sect2>
-
-
-<sect2>
<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>
-</figure>
-
</sect2>
-</section> \ No newline at end of file
+</section>
diff --git a/docs/ontologies/nmo/explanation.xml b/docs/ontologies/nmo/explanation.xml
index bc47cdbec..9c4dd7028 100644
--- a/docs/ontologies/nmo/explanation.xml
+++ b/docs/ontologies/nmo/explanation.xml
@@ -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>
</orderedlist>
-
- <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>
- </figure>
-
</sect2>
<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="http://live.gnome.org/Tracker/Documentation/Examples/SPARQL/Email">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>
- </figure>
-
- </sect2>
-
- <sect2 id="nmo-accounts-representation">
- <title>Email accounts</title>
- <para>Explain here MailAccount and MailFolder</para>
- <!-- FIXME complete -->
</sect2>
<sect2 id="nmo-sms-domain">
diff --git a/docs/reference/ontology/Makefile.am b/docs/reference/ontology/Makefile.am
index 3a818e87d..4e451c46d 100644
--- a/docs/reference/ontology/Makefile.am
+++ b/docs/reference/ontology/Makefile.am
@@ -35,40 +35,13 @@ ONTOLOGY_EXPLANATIONS = \
$(top_srcdir)/docs/ontologies/nco/explanation.xml \
$(top_srcdir)/docs/ontologies/nmo/explanation.xml
-# The XMLs to generate from the Ontology info
-# NOTE:
-#
-# - nid3 is not used by Nepomuk
-# - nrl is internal, not public
-#
-ONTOLOGY_INFOS_XML = \
- 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 \
- fts-properties.xml
-
# Generation of the ontology XML files.
gen-doc.stamp: $(ONTOLOGY_EXPLANATIONS)
- $(top_srcdir)/docs/tools/gen-doc.sh $(top_builddir)/docs/tools/ttl2sgml $(top_srcdir)/src/ontologies $(top_srcdir)/docs/ontologies .
+ mkdir xml
+ $(top_srcdir)/docs/tools/gen-doc.sh $(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
MKHTML_OPTIONS=--path="$(abs_builddir)"
-# Images to copy into HTML directory
-HTML_IMAGES = \
- $(ONTOLOGY_DIAGRAMS_PNG) \
- ontology.png
-
# 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 = \
- $(ONTOLOGY_INFOS_XML) \
- $(HTML_IMAGES) \
version.xml
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
EXTRA_DIST += \
- gen-doc.stamp \
version.xml.in \
$(ONTOLOGY_DIAGRAMS) \
$(ONTOLOGY_EXPLANATIONS)
-# PNGs and XMLs generated are removed only in maintainer-clean
-MAINTAINERCLEANFILES = \
- $(HTML_IMAGES) \
- $(ONTOLOGY_INFOS_XML) \
+CLEANFILES += \
gen-doc.stamp
diff --git a/docs/reference/ontology/ontology-docs.sgml b/docs/reference/ontology/ontology-docs.sgml
index 0d1959ae6..47de795da 100644
--- a/docs/reference/ontology/ontology-docs.sgml
+++ b/docs/reference/ontology/ontology-docs.sgml
@@ -3,27 +3,6 @@
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
<!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">
<bookinfo>
@@ -37,7 +16,7 @@
</releaseinfo>
</bookinfo>
- <part id="ontology">
+ <part id="overview">
<title>Overview</title>
<partintro>
<para>
@@ -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="http://live.gnome.org/Tracker/Documentation/">Documentation wiki</ulink> page in GNOME.
</para>
</partintro>
-
- &xsd-ontology;
- &rdf-ontology;
- <!-- &nrl-ontology; - Internal -->
- &dc-ontology;
- &nie-ontology;
- &nao-ontology;
- &nfo-ontology;
- &nco-ontology;
- &nmo-ontology;
- &ncal-ontology;
- &scal-ontology;
- <!-- &nid3-ontology; - Not using -->
- &nmm-ontology;
- &mto-ontology;
- &mlo-ontology;
- &mfo-ontology;
- &mtp-ontology;
- &slo-ontology;
- &tracker-ontology;
- &maemo-ontology;
- &fts-properties;
- </part>
-
- <part id="ontology-notation-description">
- <title>Notation</title>
- <partintro>
- Notation used in the diagrams describing each ontology.
- </partintro>
- <figure id="ontology-notation">
- <title>Notation for ontology description</title>
- <graphic fileref="notation.png" format="PNG"></graphic>
- </figure>
</part>
-
- <part id="ontology-graphs">
- <title>The big picture</title>
- <partintro>
- This is a graph that shows how different classes in the ontology are related:
- </partintro>
- <figure id="ontology-graph">
- <title>Ontology classes and their relations</title>
- <graphic fileref="ontology.png" format="PNG"></graphic>
- </figure>
+ <part id="ontology">
+ <title>Ontology</title>
+ <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" />
</part>
</book>
diff --git a/docs/tools/Makefile.am b/docs/tools/Makefile.am
index b9ac01ed2..0949b94af 100644
--- a/docs/tools/Makefile.am
+++ b/docs/tools/Makefile.am
@@ -1,4 +1,4 @@
-noinst_PROGRAMS = ontology-graph ttl2sgml
+noinst_PROGRAMS = ontology-graph ttl2sgml ttlresource2sgml
AM_CPPFLAGS = \
$(BUILD_CFLAGS) \
@@ -17,15 +17,22 @@ LDADD = \
ontology_graph_SOURCES = \
ontology-graph.c
-ttl2sgml_SOURCES = \
- ttl2sgml.c \
- ttl_loader.h \
+TTL_LOADER_FILES = \
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 \
- ttl_sgml.c
+ qname.c \
+ qname.h
+
+ttl2sgml_SOURCES = \
+ $(TTL_LOADER_FILES) \
+ ttl2sgml.c
+
+ttlresource2sgml_SOURCES = \
+ $(TTL_LOADER_FILES) \
+ ttlresource2sgml.c
EXTRA_DIST = gen-doc.sh
diff --git a/docs/tools/gen-doc.sh b/docs/tools/gen-doc.sh
index 3893a3707..3405988c7 100755
--- a/docs/tools/gen-doc.sh
+++ b/docs/tools/gen-doc.sh
@@ -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;
fi
TTL2SGML=$1
-ONTOLOGIES_DATA_DIR=$2
-ONTOLOGIES_INFO_DIR=$3
-BUILD_DIR=$4
+TTLRES2SGML=$2
+ONTOLOGIES_DATA_DIR=$3
+ONTOLOGIES_INFO_DIR=$4
+BUILD_DIR=$5
-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'/>
-
- <thead>
- <tr>
- <td>Property</td>
- <td>Weigth</td>
- </tr>
- </thead>
-
-<tbody>" > $BUILD_DIR/fts-properties.xml
+echo "Building class documentation..."
+$TTLRES2SGML -d $ONTOLOGIES_DATA_DIR -o $BUILD_DIR
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
PREFIX=${TMPNAME#*-}
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
done
-echo "</tbody></table></chapter>" >> $BUILD_DIR/fts-properties.xml
-
echo "Done"
diff --git a/docs/tools/ttl2sgml.c b/docs/tools/ttl2sgml.c
index c796739de..5da1194b1 100644
--- a/docs/tools/ttl2sgml.c
+++ b/docs/tools/ttl2sgml.c
@@ -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)",
NULL
},
- { "fts", 'f', 0, G_OPTION_ARG_FILENAME, &fts_properties_file,
- "Output file listing the full text indexed properties",
- NULL
- },
{ "explanation", 'e', 0, G_OPTION_ARG_FILENAME, &explanation_file,
"Verbosy explanation file in HTML format to include in the webpage",
NULL
@@ -59,7 +54,6 @@ main (gint argc, gchar **argv)
gchar *ttl_file = NULL;
gchar *dirname = NULL;
FILE *f = 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;
}
diff --git a/docs/tools/ttl_loader.c b/docs/tools/ttl_loader.c
index 55e07c26c..089c6229d 100644
--- a/docs/tools/ttl_loader.c
+++ b/docs/tools/ttl_loader.c
@@ -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_NOTIFY TRACKER_NS "notify"
#define TRACKER_FTS_INDEXED TRACKER_NS "fulltextIndexed"
#define TRACKER_FTS_WEIGHT TRACKER_NS "weight"
+#define TRACKER_PREFIX TRACKER_NS "prefix"
#define NAO_DEPRECATED "http://www.semanticdesktop.org/ontologies/2007/08/15/nao#deprecated"
@@ -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,
g_str_equal,
@@ -344,6 +353,9 @@ ttl_loader_load_ontology (const gchar *ttl_file)
g_str_equal,
g_free,
(GDestroyNotify)ttl_model_property_free);
+ ontology->prefixes = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ 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,
+ G_FILE_ATTRIBUTE_STANDARD_NAME,
+ G_FILE_QUERY_INFO_NONE,
+ NULL, NULL);
+
+ 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,
+ g_str_equal,
+ g_free,
+ (GDestroyNotify)ttl_model_class_free);
+
+ ontology->properties = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ (GDestroyNotify)ttl_model_property_free);
+ ontology->prefixes = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ 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);
+ break;
+ }
+ }
+
+ 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);
}
diff --git a/docs/tools/ttl_loader.h b/docs/tools/ttl_loader.h
index 72fcb1e12..0edeb021b 100644
--- a/docs/tools/ttl_loader.h
+++ b/docs/tools/ttl_loader.h
@@ -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);
diff --git a/docs/tools/ttl_model.h b/docs/tools/ttl_model.h
index 219c60720..efb369f8e 100644
--- a/docs/tools/ttl_model.h
+++ b/docs/tools/ttl_model.h
@@ -67,6 +67,7 @@ typedef struct {
typedef struct {
GHashTable *classes;
GHashTable *properties;
+ GHashTable *prefixes;
} Ontology;
diff --git a/docs/tools/ttl_sgml.c b/docs/tools/ttl_sgml.c
index e71230907..df6fc4f5d 100644
--- a/docs/tools/ttl_sgml.c
+++ b/docs/tools/ttl_sgml.c
@@ -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"
+ " \"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd\" [\n");
+ g_fprintf (f, "<!ENTITY %% local.common.attrib \"xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'\">\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);
- }
+ delim++;
- 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");
-
- if (def->notify || def->deprecated) {
- g_fprintf (f, "<note>\n");
- g_fprintf (f, "<title>Note:</title>\n");
- if (def->notify) {
- g_fprintf (f, "<para>This class notifies about changes</para>\n");
- }
- if (def->deprecated) {
- g_fprintf (f, "<para>This class is deprecated</para>\n");
- }
- g_fprintf (f, "</note>\n");
- }
-
- g_fprintf (f, "</refsect2>\n\n");
-
- g_free (name);
+ return g_strndup (name, delim - name);
}
-static void
-print_ontology_property (gpointer key, gpointer value, gpointer user_data)
+static gchar *
+name_to_shortname (Ontology *ontology,
+ const gchar *name,
+ const gchar *separator)
{
- OntologyProperty *def = (OntologyProperty *) value;
- gchar *name, *id;
- FILE *f = (FILE *) user_data;
+ gchar *prefix, *short_prefix;
+ const gchar *suffix;
- g_return_if_fail (f != NULL);
+ if (!separator)
+ separator = ":";
- name = qname_to_shortname (def->propertyname);
- id = shortname_to_id (name);
+ prefix = name_get_prefix (ontology, name);
- g_fprintf (f, "<refsect2 id='%s'>\n", id);
- g_free (id);
+ if (!prefix)
+ return g_strdup (name);
- g_fprintf (f, "<title>%s</title>\n", name);
- g_free (name);
-
- if (def->description) {
- g_fprintf (f, "<para>%s</para>\n", def->description);
- }
+ short_prefix = g_hash_table_lookup (ontology->prefixes, prefix);
+ if (!short_prefix) {
+ g_free (prefix);
+ return g_strdup (name);
+ }
- g_fprintf (f, "<variablelist>\n");
-
- print_variablelist_entry_list (f, "Type", def->type);
- print_variablelist_entry_list (f, "Domain", def->domain);
- print_variablelist_entry_list (f, "Range", def->range);
- print_variablelist_entry_list (f, "Superproperties", def->superproperties);
- print_variablelist_entry_list (f, "Subproperties", def->subproperties);
-
- if (def->max_cardinality) {
- print_variablelist_entry (f, "Cardinality", def->max_cardinality);
- }
-
- if (def->fulltextIndexed) {
- print_variablelist_entry (f, "Text indexed",
- "This property is indexed, so it can provide results on text search");
- }
-
- g_fprintf (f, "</variablelist>\n");
-
- if (def->deprecated) {
- g_fprintf (f, "<note>\n");
- g_fprintf (f, "<title>Note:</title>\n");
- g_fprintf (f, "<para>This property is deprecated</para>\n");
- g_fprintf (f, "</note>\n");
- }
+ suffix = &name[strlen (prefix)];
+ g_free (prefix);
- g_fprintf (f, "</refsect2>\n\n");
+ return g_strconcat (short_prefix, separator, suffix, NULL);
}
static void
-print_fts_properties (gpointer key, gpointer value, gpointer user_data)
+print_ontology_class (Ontology *ontology,
+ OntologyClass *def,
+ FILE *f)
{
- OntologyProperty *def = (OntologyProperty *) value;
gchar *name, *id;
- FILE *fts = (FILE *) user_data;
-
- g_return_if_fail (fts != NULL);
- if (!def->fulltextIndexed) {
- return;
- }
-
- name = qname_to_shortname (def->propertyname);
- id = shortname_to_id (name);
- g_fprintf (fts, "<tr>\n");
- g_fprintf (fts, " <td>\n");
- print_reference (def->propertyname, fts);
- g_fprintf (fts, " </td>\n");
- g_fprintf (fts, " <td>%s</td>\n", (def->weight ? def->weight : "0"));
- g_fprintf (fts, "</tr>\n");
+ g_return_if_fail (f != NULL);
- g_free (id);
+ name = name_to_shortname (ontology, def->classname, NULL);
+ id = name_to_shortname (ontology, def->classname, "-");
+ g_fprintf (f, "<xi:include href='%s.xml'/>\n", id);
+ g_free (id);
+ g_free (name);
}
void
ttl_sgml_print (OntologyDescription *description,
Ontology *ontology,
FILE *f,
- FILE *fts,
const gchar *explanation_file)
{
+ GHashTableIter iter;
gchar *upper_name;
+ OntologyClass *def;
upper_name = g_ascii_strup (description->localPrefix, -1);
@@ -349,19 +229,14 @@ ttl_sgml_print (OntologyDescription *description,
g_fprintf (f, "<section id='%s-classes'>\n", description->localPrefix);
g_fprintf (f, "<title>%s Ontology Classes</title>\n", upper_name);
- g_hash_table_foreach (ontology->classes, print_ontology_class, f);
- g_fprintf (f, "</section>\n");
+ g_hash_table_iter_init (&iter, ontology->classes);
- g_fprintf (f, "<section id='%s-properties'>\n", description->localPrefix);
- g_fprintf (f, "<title>%s Ontology Properties</title>\n", upper_name);
- g_hash_table_foreach (ontology->properties, print_ontology_property, f);
- g_fprintf (f, "</section>\n");
+ while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &def)) {
+ print_ontology_class (ontology, def, f);
+ }
+ g_fprintf (f, "</section>\n");
print_sgml_footer (f);
g_free (upper_name);
-
- if (fts) {
- g_hash_table_foreach (ontology->properties, print_fts_properties, fts);
- }
}
diff --git a/docs/tools/ttl_sgml.h b/docs/tools/ttl_sgml.h
index 54edf1136..3cf7a31ee 100644
--- a/docs/tools/ttl_sgml.h
+++ b/docs/tools/ttl_sgml.h
@@ -29,7 +29,6 @@ G_BEGIN_DECLS
void ttl_sgml_print (OntologyDescription *description,
Ontology *ontology,
FILE *output,
- FILE *class_location,
const gchar *explanation_file);
diff --git a/docs/tools/ttlresource2sgml.c b/docs/tools/ttlresource2sgml.c
new file mode 100644
index 000000000..38386b19f
--- /dev/null
+++ b/docs/tools/ttlresource2sgml.c
@@ -0,0 +1,820 @@
+/*
+ * Copyright (C) 2015, Carlos Garnacho
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * Authors: Carlos Garnacho <carlosg@gnome.org>
+ */
+
+#include <string.h>
+#include <glib-object.h>
+#include <glib/gprintf.h>
+#include <gio/gio.h>
+#include "ttl_loader.h"
+#include "ttl_model.h"
+#include "ttl_sgml.h"
+
+static gchar *ontology_dir = NULL;
+static gchar *output_dir = NULL;
+
+#define TRACKER_ONTOLOGY_CLASS "http://www.tracker-project.org/ontologies/tracker#Ontology"
+
+static GOptionEntry entries[] = {
+ { "ontology-dir", 'd', 0, G_OPTION_ARG_FILENAME, &ontology_dir,
+ "Ontology directory",
+ NULL
+ },
+ { "output-dir", 'o', 0, G_OPTION_ARG_FILENAME, &output_dir,
+ "File to write the output (default stdout)",
+ NULL
+ },
+ { NULL }
+};
+
+static gchar *
+name_get_prefix (Ontology *ontology,
+ const gchar *name)
+{
+ const gchar *delim;
+
+ delim = g_strrstr (name, "#");
+
+ if (!delim)
+ delim = g_strrstr (name, "/");
+
+ if (!delim)
+ return NULL;
+
+ delim++;
+
+ return g_strndup (name, delim - name);
+}
+
+static gchar *
+name_to_shortname (Ontology *ontology,
+ const gchar *name,
+ const gchar *separator)
+{
+ gchar *prefix, *short_prefix;
+ const gchar *suffix;
+
+ if (!separator)
+ separator = ":";
+
+ prefix = name_get_prefix (ontology, name);
+
+ if (!prefix)
+ return g_strdup (name);
+
+ short_prefix = g_hash_table_lookup (ontology->prefixes, prefix);
+
+ if (!short_prefix) {
+ g_free (prefix);
+ return g_strdup (name);
+ }
+
+ suffix = &name[strlen (prefix)];
+ g_free (prefix);
+
+ return g_strconcat (short_prefix, separator, suffix, NULL);
+}
+
+static void
+class_get_parent_hierarchy (Ontology *ontology,
+ OntologyClass *klass,
+ GList **list)
+{
+ GList *l;
+
+ /* Ensure we only got the same class there once */
+ *list = g_list_remove (*list, klass->classname);
+ *list = g_list_prepend (*list, klass->classname);
+
+ for (l = klass->superclasses; l; l = l->next) {
+ OntologyClass *parent_class;
+
+ parent_class = g_hash_table_lookup (ontology->classes, l->data);
+ class_get_parent_hierarchy (ontology, parent_class, list);
+ }
+}
+
+static GList *
+class_get_hierarchy (Ontology *ontology,
+ OntologyClass *klass)
+{
+ GList *hierarchy = NULL, *l;
+
+ /* Order is: parents, this class, and children. Guaranteed
+ * to be in an order where all parents are before a child.
+ * We first prepend all children, and then find out the
+ * upwards hierarchy recursively.
+ */
+ for (l = klass->subclasses; l; l = l->next) {
+ hierarchy = g_list_prepend (hierarchy, l->data);
+ }
+
+ class_get_parent_hierarchy (ontology, klass, &hierarchy);
+
+ return hierarchy;
+}
+
+static void
+print_sgml_header (FILE *f,
+ OntologyClass *klass,
+ Ontology *ontology)
+{
+ gchar *id, *shortname;
+
+ id = name_to_shortname (ontology, klass->classname, "-");
+ shortname = name_to_shortname (ontology, klass->classname, NULL);
+
+ g_fprintf (f, "<?xml version='1.0' encoding='UTF-8'?>\n");
+ g_fprintf (f, "<refentry id='%s'>\n", id);
+
+ g_fprintf (f, "<refmeta><refentrytitle>%s</refentrytitle></refmeta>", shortname);
+ g_fprintf (f, "<refnamediv><refname>%s</refname></refnamediv>", shortname);
+
+ g_fprintf (f, "<refsect1 id='%s.description'>", id);
+
+ if (klass->description) {
+ g_fprintf (f, "<title>Description</title>\n");
+ g_fprintf (f, "<para>%s</para>\n", klass->description);
+ }
+
+ if (klass->deprecated)
+ g_fprintf (f, "<note><para>This class is deprecated.</para></note>\n");
+
+ if (klass->notify)
+ g_fprintf (f, "<note><para>This class emits notifications about changes, and can "
+ "be tracked through the <literal>GraphUpdated</literal> DBus signal.</para></note>\n");
+
+ g_fprintf (f, "</refsect1>");
+
+ g_free (shortname);
+ g_free (id);
+}
+
+static void
+print_sgml_footer (FILE *f)
+{
+ g_fprintf (f, "</refentry>\n");
+}
+
+static void
+print_predefined_instances (FILE *f,
+ OntologyClass *klass,
+ Ontology *ontology)
+{
+ gchar *shortname, *id;
+ GList *l;
+
+ if (!klass->instances)
+ return;
+
+ shortname = name_to_shortname (ontology, klass->classname, NULL);
+ id = name_to_shortname (ontology, klass->classname, "-");
+
+ g_fprintf (f, "<refsect1 id='%s.predefined-instances'>", id);
+ g_fprintf (f, "<title>Predefined instances</title><para>");
+ g_fprintf (f, "%s has the following predefined instances: ", shortname);
+ g_fprintf (f, "<itemizedlist>\n");
+
+ g_free (shortname);
+ g_free (id);
+
+ for (l = klass->instances; l; l = l->next) {
+ shortname = name_to_shortname (ontology, l->data, NULL);
+ id = name_to_shortname (ontology, l->data, "-");
+
+ g_fprintf (f, "<listitem><para>");
+ g_fprintf (f, "<link linkend=\"%s\">%s</link>", id, shortname);
+ g_fprintf (f, "</para></listitem>\n");
+ g_free (shortname);
+ g_free (id);
+ }
+
+ g_fprintf (f, "</itemizedlist></para></refsect1>\n");
+}
+
+static void
+print_fts_properties (FILE *f,
+ OntologyClass *klass,
+ Ontology *ontology)
+{
+ gchar *shortname, *id;
+ GList *l, *fts_props = NULL;
+
+ for (l = klass->in_domain_of; l; l = l->next) {
+ OntologyProperty *prop;
+
+ prop = g_hash_table_lookup (ontology->properties, l->data);
+
+ if (prop->fulltextIndexed)
+ fts_props = g_list_prepend (fts_props, prop);
+ }
+
+ if (!fts_props)
+ return;
+
+ shortname = name_to_shortname (ontology, klass->classname, NULL);
+ id = name_to_shortname (ontology, klass->classname, "-");
+
+ g_fprintf (f, "<refsect1 id='%s.fts-properties'>", id);
+ g_fprintf (f, "<title>Full-text-indexed properties</title><para>");
+ g_fprintf (f, "%s has the following full-text-indexed properties: ", shortname);
+ g_fprintf (f, "<itemizedlist>\n");
+
+ for (l = fts_props; l; l = l->next) {
+ gchar *prop_shortname, *prop_id;
+ OntologyProperty *prop = l->data;
+
+ prop_shortname = name_to_shortname (ontology, prop->propertyname, NULL);
+ prop_id = name_to_shortname (ontology, prop->propertyname, "-");
+
+ g_fprintf (f, "<listitem><para>");
+ g_fprintf (f, "<link linkend=\"%s.%s\">%s</link>", id, prop_id, prop_shortname);
+ g_fprintf (f, "</para></listitem>\n");
+ g_free (prop_shortname);
+ g_free (prop_id);
+ }
+
+ g_fprintf (f, "</itemizedlist></para></refsect1>\n");
+ g_free (shortname);
+ g_free (id);
+}
+
+typedef struct {
+ GString *str;
+ gint visible_len;
+} HierarchyString;
+
+typedef struct {
+ OntologyClass *class;
+ GList *hierarchy;
+ GHashTable *resolved_children;
+ GHashTable *resolved_parents;
+ GHashTable *placed;
+ GPtrArray *strings;
+} HierarchyContext;
+
+static HierarchyString *
+hierarchy_string_new (void)
+{
+ HierarchyString *str;
+
+ str = g_new0 (HierarchyString, 1);
+ str->str = g_string_new ("");
+
+ return str;
+}
+
+static void
+hierarchy_string_free (HierarchyString *str)
+{
+ g_string_free (str->str, TRUE);
+ g_free (str);
+}
+
+static void
+hierarchy_string_append (HierarchyString *str,
+ const gchar *substr)
+{
+ g_string_append (str->str, substr);
+ str->visible_len += g_utf8_strlen (substr, -1);
+}
+
+static void
+hierarchy_string_append_link (HierarchyString *str,
+ const gchar *substr,
+ const gchar *link,
+ gboolean bold)
+{
+ if (bold)
+ g_string_append_printf (str->str, "<emphasis><link linkend=\"%s\">%s</link></emphasis>",
+ link, substr);
+ else
+ g_string_append_printf (str->str, "<link linkend=\"%s\">%s</link>", link, substr);
+
+ str->visible_len += g_utf8_strlen (substr, -1);
+}
+
+static GList *
+list_filter (GList *original,
+ GList *valid)
+{
+ GList *l, *filtered = NULL;
+
+ for (l = original; l; l = l->next) {
+ if (!g_list_find_custom (valid, l->data,
+ (GCompareFunc) g_strcmp0))
+ continue;
+
+ filtered = g_list_prepend (filtered, l->data);
+ }
+
+ return filtered;
+}
+
+static HierarchyContext *
+hierarchy_context_new (OntologyClass *klass,
+ Ontology *ontology)
+{
+ HierarchyContext *context;
+ GList *l;
+
+ context = g_new0 (HierarchyContext, 1);
+ context->class = klass;
+ context->hierarchy = class_get_hierarchy (ontology, klass);
+ context->placed = g_hash_table_new (g_str_hash, g_str_equal);
+ context->resolved_parents = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ NULL,
+ (GDestroyNotify) g_list_free);
+ context->resolved_children = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ NULL,
+ (GDestroyNotify) g_list_free);
+ context->strings = g_ptr_array_new_with_free_func ((GDestroyNotify) hierarchy_string_free);
+
+ for (l = context->hierarchy; l; l = l->next) {
+ OntologyClass *cl = g_hash_table_lookup (ontology->classes, l->data);
+
+ g_hash_table_insert (context->resolved_parents,
+ cl->classname,
+ list_filter (cl->superclasses,
+ context->hierarchy));
+ g_hash_table_insert (context->resolved_children,
+ cl->classname,
+ list_filter (cl->subclasses,
+ context->hierarchy));
+
+ g_ptr_array_add (context->strings, hierarchy_string_new ());
+ }
+
+ return context;
+}
+
+static void
+hierarchy_context_free (HierarchyContext *context)
+{
+ g_ptr_array_unref (context->strings);
+ g_hash_table_unref (context->placed);
+ g_hash_table_unref (context->resolved_parents);
+ g_hash_table_unref (context->resolved_children);
+ g_free (context);
+}
+
+static GList *
+hierarchy_context_get_single_parented_children (HierarchyContext *context,
+ OntologyClass *klass,
+ Ontology *ontology)
+{
+ GList *filtered = NULL, *children, *l;
+
+ children = g_hash_table_lookup (context->resolved_children,
+ klass->classname);
+
+ for (l = children; l; l = l->next) {
+ GList *parents;
+
+ parents = g_hash_table_lookup (context->resolved_parents, l->data);
+
+ if (g_list_length (parents) == 1)
+ filtered = g_list_prepend (filtered, l->data);
+ }
+
+ return filtered;
+}
+
+static void
+fill_padding (HierarchyString *str,
+ gint max_len,
+ gchar *substr)
+{
+ gint padding = max_len - str->visible_len;
+
+ if (padding <= 0)
+ return;
+
+ while (padding > 0) {
+ hierarchy_string_append (str, substr);
+ padding--;
+ }
+}
+
+static gboolean
+check_parents_placed (GList *parents,
+ GHashTable *ht)
+{
+ GList *l;
+
+ for (l = parents; l; l = l->next) {
+ if (!g_hash_table_lookup (ht, l->data))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+hierarchy_context_resolve_class (HierarchyContext *context,
+ OntologyClass *klass,
+ Ontology *ontology)
+{
+ GList *l = g_list_find_custom (context->hierarchy, klass->classname,
+ (GCompareFunc) g_strcmp0);
+ guint pos = g_list_position (context->hierarchy, l);
+ GList *children, *parents;
+ gchar *shortname, *link;
+ HierarchyString *str;
+ gboolean is_child;
+
+ if (pos < 0)
+ return;
+
+ shortname = name_to_shortname (ontology, klass->classname, NULL);
+ link = name_to_shortname (ontology, klass->classname, "-");
+ parents = g_hash_table_lookup (context->resolved_parents,
+ klass->classname);
+
+ if (g_list_length (parents) > 1) {
+ gboolean first_pending = TRUE;
+ gint i, max_len = 0;
+
+ /* This class has more than one parent in the current graph,
+ * those paint the lines on the right side.
+ */
+
+ /* Step 1: Find the longest string */
+ first_pending = TRUE;
+ for (i = 0, l = context->hierarchy; i < pos && l; i++, l = l->next) {
+ is_child = g_list_find_custom (klass->superclasses, l->data,
+ (GCompareFunc) g_strcmp0) != NULL;
+ if (!is_child && first_pending)
+ continue;
+
+ str = g_ptr_array_index (context->strings, i);
+ max_len = MAX (max_len, str->visible_len);
+ }
+
+ /* Step 2: append the line art, we must fill in some padding if
+ * necessary.
+ */
+ first_pending = TRUE;
+ for (i = 0, l = context->hierarchy; i < pos && l; i++, l = l->next) {
+ is_child = g_list_find_custom (klass->superclasses, l->data,
+ (GCompareFunc) g_strcmp0) != NULL;
+
+ if (!is_child && first_pending)
+ continue;
+
+ str = g_ptr_array_index (context->strings, i);
+
+ fill_padding (str, max_len, is_child ? "─" : " ");
+
+ if (first_pending) {
+ hierarchy_string_append (str, "──┐");
+ first_pending = FALSE;
+ } else if (is_child) {
+ hierarchy_string_append (str, "──┤");
+ } else {
+ hierarchy_string_append (str, " │");
+ }
+ }
+
+ /* Step 3: Finally, print the current class */
+ str = g_ptr_array_index (context->strings, pos);
+ fill_padding (str, max_len - 1, " ");
+
+ hierarchy_string_append (str, " └── ");
+ hierarchy_string_append_link (str, shortname, link, klass == context->class);
+ hierarchy_string_append (str, " ");
+ } else {
+ /* The current class has only 1 parent, lineart for those is
+ * displayed on the left side.
+ */
+
+ /* Step 1: Print the current class */
+ str = g_ptr_array_index (context->strings, pos);
+ hierarchy_string_append_link (str, shortname, link, klass == context->class);
+ hierarchy_string_append (str, " ");
+
+ /* Step 2: Modify all strings downwards, adding the lineart
+ * necessary for all children of this class.
+ */
+ children = hierarchy_context_get_single_parented_children (context, klass, ontology);
+ l = l->next;
+ pos++;
+
+ for (; l; l = l->next, pos++) {
+ guint len = g_list_length (children);
+ GList *cur;
+
+ str = g_ptr_array_index (context->strings, pos);
+ cur = g_list_find_custom (children, l->data,
+ (GCompareFunc) g_strcmp0);
+ is_child = (cur != NULL);
+
+ if (is_child) {
+ if (len > 1)
+ hierarchy_string_append (str, "├── ");
+ else if (len == 1)
+ hierarchy_string_append (str, "╰── ");
+
+ children = g_list_delete_link (children, cur);
+ g_hash_table_insert (context->placed,
+ l->data, GINT_TO_POINTER (TRUE));
+ } else {
+ if (len > 0)
+ hierarchy_string_append (str, "│ ");
+ else if (len == 0 &&
+ !g_hash_table_lookup (context->placed, l->data)) {
+ GList *cl_parents;
+
+ cl_parents = g_hash_table_lookup (context->resolved_parents, l->data);
+
+ if (g_list_length (cl_parents) == 1 ||
+ !check_parents_placed (cl_parents, context->placed)) {
+ hierarchy_string_append (str, " ");
+ }
+ }
+ }
+ }
+ }
+
+ g_free (shortname);
+ g_free (link);
+}
+
+static GPtrArray *
+class_get_parent_hierarchy_strings (OntologyClass *klass,
+ Ontology *ontology)
+{
+ HierarchyContext *context;
+ GList *c;
+ GPtrArray *strings;
+
+ context = hierarchy_context_new (klass, ontology);
+
+ for (c = context->hierarchy; c; c = c->next) {
+ OntologyClass *cl = g_hash_table_lookup (ontology->classes, c->data);
+ hierarchy_context_resolve_class (context, cl, ontology);
+ }
+
+ strings = g_ptr_array_ref (context->strings);
+ hierarchy_context_free (context);
+
+ return strings;
+}
+
+static void
+print_class_hierarchy (FILE *f,
+ OntologyClass *klass,
+ Ontology *ontology)
+{
+ GPtrArray *strings;
+ gchar *id;
+ gint i;
+
+ strings = class_get_parent_hierarchy_strings (klass, ontology);
+
+ if (!strings)
+ return;
+
+ id = name_to_shortname (ontology, klass->classname, "-");
+
+ g_fprintf (f, "<refsect1 id='%s.hierarchy'>", id);
+ g_fprintf (f, "<title>Class hierarchy</title>");
+ g_fprintf (f, "<screen>");
+
+ g_free (id);
+
+ for (i = 0; i < strings->len; i++) {
+ HierarchyString *str = g_ptr_array_index (strings, i);
+ g_fprintf (f, " %s\n", str->str->str);
+ }
+
+ g_fprintf (f, "</screen></refsect1>\n");
+ g_ptr_array_unref (strings);
+}
+
+static void
+print_properties (FILE *f,
+ OntologyClass *klass,
+ Ontology *ontology)
+{
+ gchar *id, *prop_id, *shortname, *type_name, *type_class_id;
+ GList *l;
+
+ if (!klass->in_domain_of)
+ return;
+
+ id = name_to_shortname (ontology, klass->classname, "-");
+ g_fprintf (f, "<refsect1 id='%s.properties'>", id);
+ g_fprintf (f, "<title>Properties</title>");
+
+ for (l = klass->in_domain_of; l; l = l->next) {
+ OntologyProperty *prop;
+
+ prop = g_hash_table_lookup (ontology->properties, l->data);
+
+ prop_id = name_to_shortname (ontology, prop->propertyname, "-");
+ shortname = name_to_shortname (ontology, prop->propertyname, NULL);
+ type_name = name_to_shortname (ontology, prop->range->data, NULL);
+ type_class_id = name_to_shortname (ontology, prop->range->data, "-");
+
+ g_fprintf (f, "<refsect2 id='%s.%s'>", id, prop_id);
+ g_fprintf (f, "<title>The <literal>“%s”</literal> property</title>", shortname);
+ g_fprintf (f, "<programlisting>“%s”"
+ " <link linkend=\"%s\">%s</link>"
+ "</programlisting>",
+ shortname, type_class_id, type_name);
+
+ if (prop->description) {
+ g_fprintf (f, "<para>%s</para>", prop->description);
+ }
+
+ if (prop->max_cardinality) {
+ g_fprintf (f, "<para>Number of possible elements per resource (Cardinality): %s</para>",
+ prop->max_cardinality);
+ } else {
+ g_fprintf (f, "<para>Number of possible elements per resource (Cardinality): Unlimited</para>");
+ }
+
+ if (prop->fulltextIndexed) {
+ g_fprintf (f, "<note><para>This property is full-text-indexed, and can be looked up through <literal>fts:match</literal>.</para></note>\n");
+ }
+
+ if (prop->deprecated) {
+ g_fprintf (f, "<note><para>This property is deprecated.</para></note>\n");
+ }
+
+ if (prop->superproperties) {
+ GList *l;
+
+ g_fprintf (f, "<note><para>This property supersedes the following properties from this or parent classes:</para>\n");
+ g_fprintf (f, "<itemizedlist>\n");
+
+ for (l = prop->superproperties; l; l = l->next) {
+ gchar *class_shortname, *shortname, *class_id, *superprop_id;
+ OntologyProperty *superprop;
+ OntologyClass *cl;
+
+ superprop = g_hash_table_lookup (ontology->properties, l->data);
+ cl = g_hash_table_lookup (ontology->classes, superprop->domain->data);
+
+ shortname = name_to_shortname (ontology, superprop->propertyname, NULL);
+ class_shortname = name_to_shortname (ontology, cl->classname, NULL);
+ superprop_id = name_to_shortname (ontology, superprop->propertyname, "-");
+ class_id = name_to_shortname (ontology, cl->classname, "-");
+
+ g_fprintf (f, "<listitem><para>");
+ g_fprintf (f, "<link linkend=\"%s.%s\"><literal>“%s”</literal> from the <literal>%s</literal> class</link>",
+ class_id, superprop_id,
+ shortname, class_shortname);
+ g_fprintf (f, "</para></listitem>\n");
+
+ g_free (class_id);
+ g_free (superprop_id);
+ g_free (class_shortname);
+ g_free (shortname);
+ }
+
+ g_fprintf (f, "</itemizedlist></note>\n");
+ }
+
+ g_fprintf (f, "</refsect2>\n");
+
+ g_free (type_class_id);
+ g_free (type_name);
+ g_free (shortname);
+ g_free (prop_id);
+ }
+
+ g_fprintf (f, "</refsect1>");
+ g_free (id);
+}
+
+static void
+print_see_also (FILE *f,
+ OntologyClass *klass,
+ Ontology *ontology)
+{
+ const gchar *short_prefix;
+ gchar *prefix, *id, *upper;
+
+ prefix = name_get_prefix (ontology, klass->classname);
+
+ if (!prefix)
+ return;
+
+ if (!g_str_has_prefix (prefix, "http"))
+ return;
+
+ short_prefix = g_hash_table_lookup (ontology->prefixes, prefix);
+
+ if (!short_prefix) {
+ g_free (prefix);
+ return;
+ }
+
+ id = name_to_shortname (ontology, klass->classname, "-");
+ g_fprintf (f, "<refsect1 id='%s.see-also'>", id);
+ g_fprintf (f, "<title>See also</title>");
+ g_free (id);
+
+ upper = g_ascii_strup (short_prefix, -1);
+
+ g_fprintf (f, "<para>The upstream documentation for the <ulink url='%s'>%s ontology</ulink>.</para>",
+ prefix, upper);
+
+ g_fprintf (f, "</refsect1>\n");
+
+ g_free (prefix);
+ g_free (upper);
+}
+
+static void
+generate_class_docs (OntologyClass *klass,
+ Ontology *ontology,
+ FILE *f)
+{
+ print_sgml_header (f, klass, ontology);
+ print_class_hierarchy (f, klass, ontology);
+ print_predefined_instances (f, klass, ontology);
+ print_fts_properties (f, klass, ontology);
+ print_properties (f, klass, ontology);
+ print_see_also (f, klass, ontology);
+ print_sgml_footer (f);
+}
+
+static void
+generate_ontology_class_docs (Ontology *ontology,
+ const gchar *output_dir)
+{
+ GHashTableIter iter;
+ OntologyClass *klass;
+ FILE *f;
+
+ g_hash_table_iter_init (&iter, ontology->classes);
+
+ while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &klass)) {
+ gchar *shortname, *class_filename, *output_file;
+
+ shortname = name_to_shortname (ontology, klass->classname, "-");
+ class_filename = g_strdup_printf ("%s.xml", shortname);
+ output_file = g_build_filename (output_dir, class_filename, NULL);
+
+ f = fopen (output_file, "w");
+ g_free (class_filename);
+ g_free (output_file);
+ g_free (shortname);
+
+ generate_class_docs (klass, ontology, f);
+ fclose (f);
+ }
+}
+
+int
+main (int argc, char *argv[])
+{
+ GOptionContext *context;
+ Ontology *ontology;
+
+ context = g_option_context_new ("- Generates ontology docs");
+
+ g_option_context_add_main_entries (context, entries, NULL);
+ g_option_context_parse (context, &argc, &argv, NULL);
+
+ if (!ontology_dir || !output_dir) {
+ gchar *help;
+
+ g_printerr ("%s\n\n",
+ "Ontology and output dirs are mandatory");
+
+ help = g_option_context_get_help (context, TRUE, NULL);
+ g_option_context_free (context);
+ g_printerr ("%s", help);
+ g_free (help);
+
+ return -1;
+ }
+
+ ontology = ttl_loader_load_ontology_dir (ontology_dir);
+ generate_ontology_class_docs (ontology, output_dir);
+
+ return 0;
+}