[tracker] docs: Rework ontology docs generation entirely



commit 60354f20b49f910095ee1e207d6f44a88ad6e6cc
Author: Carlos Garnacho <carlosg gnome org>
Date:   Mon Jun 29 01:10:57 2015 +0200

    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.

 docs/ontologies/mfo/explanation.xml        |    9 -
 docs/ontologies/mlo/explanation.xml        |    9 -
 docs/ontologies/nie/explanation.xml        |    9 -
 docs/ontologies/nmm/explanation.xml        |   28 +-
 docs/ontologies/nmo/explanation.xml        |   20 -
 docs/reference/ontology/Makefile.am        |   48 +--
 docs/reference/ontology/ontology-docs.sgml |   87 +---
 docs/tools/Makefile.am                     |   23 +-
 docs/tools/gen-doc.sh                      |   35 +-
 docs/tools/ttl2sgml.c                      |   16 +-
 docs/tools/ttl_loader.c                    |  100 ++++
 docs/tools/ttl_loader.h                    |    1 +
 docs/tools/ttl_model.h                     |    1 +
 docs/tools/ttl_sgml.c                      |  225 ++------
 docs/tools/ttl_sgml.h                      |    1 -
 docs/tools/ttlresource2sgml.c              |  820 ++++++++++++++++++++++++++++
 16 files changed, 1024 insertions(+), 408 deletions(-)
---
diff --git a/docs/ontologies/mfo/explanation.xml b/docs/ontologies/mfo/explanation.xml
index d97d7c9..d78aff3 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 7e419f8..8296bc6 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 1ee15fd..b0d9ebd 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 e55d810..0da24c2 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 bc47cdb..9c4dd70 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 3a818e8..4e451c4 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 0d1959a..47de795 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 b9ac01e..0949b94 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 3893a37..3405988 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 c796739..5da1194 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 55e07c2..089c622 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 72fcb1e..0edeb02 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 219c607..efb369f 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 e712309..df6fc4f 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 54edf11..3cf7a31 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 0000000..38386b1
--- /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;
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]