1 /*
2  * Copyright (C) 2009, Nokia <ivan.frade@nokia.com>
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  */
19 
20 #include <glib/gprintf.h>
21 
22 #include "ttl_xml.h"
23 #include "ttlresource2xml.h"
24 
25 typedef struct {
26 	Ontology *ontology;
27 	OntologyDescription *description;
28 	FILE *output;
29 } CallbackInfo;
30 
31 
32 static void
print_itemized_list(FILE * f,GList * list)33 print_itemized_list (FILE *f, GList *list)
34 {
35 	GList *it;
36 
37 	g_fprintf (f, "<itemizedlist>\n");
38 	for (it = list; it != NULL; it = it->next) {
39 		g_fprintf (f, "<listitem>%s</listitem>\n", (gchar *)it->data);
40 	}
41 	g_fprintf (f, "</itemizedlist>\n");
42 }
43 
44 static void
print_people_list(FILE * f,const gchar * role,GList * list)45 print_people_list (FILE *f,
46                    const gchar *role,
47                    GList *list)
48 {
49         if (!list) {
50                 return;
51         }
52 
53         g_fprintf (f, "<varlistentry>\n");
54         g_fprintf (f, "  <term>%s</term>\n", role);
55         g_fprintf (f, "  <listitem>\n");
56         print_itemized_list (f, list);
57         g_fprintf (f, "  </listitem>\n");
58         g_fprintf (f, "</varlistentry>\n");
59 }
60 
61 static void
print_link_as_varlistentry(FILE * f,const gchar * term,const gchar * link_text,const gchar * link)62 print_link_as_varlistentry (FILE *f,
63                             const gchar *term,
64                             const gchar *link_text,
65                             const gchar *link)
66 {
67         g_fprintf (f, "  <varlistentry>\n");
68         g_fprintf (f,"    <term>%s</term>\n", term);
69 	if (link) {
70                 g_fprintf (f,
71                            " <listitem><para><ulink url=\"%s\">%s</ulink></para></listitem>\n",
72 		           link, link_text);
73 	} else {
74 		g_fprintf (f, " <listitem><para>Not available</para></listitem>\n");
75 	}
76         g_fprintf (f, "  </varlistentry>\n");
77 }
78 
79 #if 0
80 static void
81 print_deprecated_message (FILE *f)
82 {
83         g_fprintf (f, "<note>\n");
84         g_fprintf (f, "<title>Note:</title>\n");
85         g_fprintf (f, "<para>This item is deprecated</para>\n");
86         g_fprintf (f, "</note>\n");
87 }
88 #endif
89 
90 static void
print_xml_header(FILE * f,OntologyDescription * desc)91 print_xml_header (FILE *f, OntologyDescription *desc)
92 {
93 	g_fprintf (f, "<?xml version='1.0' encoding='UTF-8'?>\n");
94 	g_fprintf (f, "<!DOCTYPE book PUBLIC \"-//OASIS//DTD DocBook XML V4.5//EN\"\n"
95 	           "        \"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd\" [\n");
96 	g_fprintf (f, "<!ENTITY %% local.common.attrib \"xmlns:xi  CDATA  #FIXED 'http://www.w3.org/2003/XInclude'\">\n");
97 	g_fprintf (f, "]>");
98 
99 	g_fprintf (f, "<refentry id='%s' xmlns:xi=\"http://www.w3.org/2003/XInclude\">\n", desc->localPrefix);
100 	g_fprintf (f, "<refmeta>\n");
101 	g_fprintf (f, "  <refentrytitle>%s</refentrytitle>\n", desc->title);
102 	g_fprintf (f, "</refmeta>\n");
103 	g_fprintf (f, "<refnamediv>\n");
104 	g_fprintf (f, "<refname>%s</refname>", desc->title);
105 	g_fprintf (f, "<refpurpose>%s</refpurpose>", desc->description);
106 	g_fprintf (f, "</refnamediv>\n");
107 }
108 
109 static void
print_xml_footer(FILE * f,OntologyDescription * desc)110 print_xml_footer (FILE *f, OntologyDescription *desc)
111 {
112 	g_fprintf (f, "<refsect1>\n");
113 	g_fprintf (f, "<title>Credits and Copyright</title>\n");
114 	print_people_list (f, "Authors:", desc->authors);
115 	print_people_list (f, "Editors:", desc->editors);
116 	print_people_list (f, "Contributors:", desc->contributors);
117 
118 	print_link_as_varlistentry (f, "Upstream:", "Upstream version", desc->upstream);
119 	print_link_as_varlistentry (f, "ChangeLog:", "Tracker changes", desc->gitlog);
120 
121 	if (desc->copyright) {
122 		g_fprintf (f, "<varlistentry>\n");
123 		g_fprintf (f, "  <term>Copyright:</term>\n");
124 		g_fprintf (f, "  <listitem>\n");
125 		g_fprintf (f, "<para>%s</para>\n", desc->copyright);
126 		g_fprintf (f, "  </listitem>\n");
127 		g_fprintf (f, "</varlistentry>\n");
128     }
129 
130 	g_fprintf (f, "</refsect1>\n");
131 	g_fprintf (f, "</refentry>\n");
132 }
133 
compare_class(gconstpointer a,gconstpointer b)134 static gint compare_class (gconstpointer a,
135                            gconstpointer b)
136 {
137 	return strcmp (((OntologyClass *)a)->classname, ((OntologyClass *)b)->classname);
138 }
139 
140 /* By default we list properties under their respective class.
141  *
142  * Ontologies can contain properties whose class is in a different
143  * ontology, and we treat these specially as 'extra properties'.
144  *
145  * This functions returns a hash table mapping class name to the
146  * extra properties provided for that class.
147  */
148 static GHashTable *
get_extra_properties(GList * classes,GList * properties)149 get_extra_properties (GList *classes,
150                       GList *properties)
151 {
152 	GList *l, *c;
153 	GHashTable *extra_properties;
154 	GHashTableIter iter;
155 	gchar *classname;
156 	GList *properties_for_class;
157 
158 	extra_properties = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
159 
160 	for (l = properties; l; l = l->next) {
161 		OntologyProperty *prop = l->data;
162 		gboolean has_domain_in_this_ontology = FALSE;
163 
164 		for (c = classes; c; c = c->next) {
165 			OntologyClass *klass;
166 
167 			klass = c->data;
168 			if (g_list_find_custom (prop->domain, klass->classname, (GCompareFunc)strcmp)) {
169 				has_domain_in_this_ontology = TRUE;
170 				break;
171 			}
172 		}
173 
174 		if (!has_domain_in_this_ontology) {
175 			for (c = prop->domain; c; c = c->next) {
176 				const gchar *classname;
177 				GList *list;
178 
179 				classname = c->data;
180 				list = g_hash_table_lookup (extra_properties, classname);
181 				list = g_list_append (list, prop->propertyname);
182 				g_hash_table_insert (extra_properties, g_strdup (classname), list);
183 			}
184 		}
185 	}
186 
187 	g_hash_table_iter_init (&iter, extra_properties);
188 	while (g_hash_table_iter_next (&iter, (gpointer *)&classname, (gpointer *)&properties_for_class)) {
189 		properties_for_class = g_list_sort (properties_for_class, (GCompareFunc) strcmp);
190 		g_hash_table_iter_replace (&iter, properties_for_class);
191 	}
192 
193 	return extra_properties;
194 }
195 
196 static void
print_synopsis(FILE * f,OntologyDescription * desc)197 print_synopsis (FILE                 *f,
198                 OntologyDescription *desc)
199 {
200 	g_fprintf (f, "<refsynopsisdiv>\n");
201 	g_fprintf (f, "<synopsis>\n");
202 	g_fprintf (f, "@prefix %s: &lt;%s&gt;\n", desc->localPrefix, desc->baseUrl);
203 	g_fprintf (f, "</synopsis>\n");
204 	g_fprintf (f, "</refsynopsisdiv>\n");
205 }
206 
207 static void
print_toc_classes(FILE * f,Ontology * ontology,const char * id,GList * classes)208 print_toc_classes (FILE       *f,
209                    Ontology   *ontology,
210                    const char *id,
211                    GList      *classes)
212 {
213 	GList *l;
214 
215 	if (!classes)
216 		return;
217 
218 	g_fprintf (f, "<refsect1 id=\"%s.classes\">", id);
219 	g_fprintf (f, "<title>Classes</title>");
220 
221 	for (l = classes; l; l = l->next) {
222 		OntologyClass *klass;
223 		g_autofree char *basename = NULL, *id = NULL;
224 
225 		klass = l->data;
226 		basename = ttl_model_name_to_basename (ontology, klass->classname);
227 		id = ttl_model_name_to_shortname (ontology, klass->classname, "-");
228 
229 		if (l != classes) {
230 			g_fprintf (f, ", ");
231 		}
232 		g_fprintf (f, "<link linkend=\"%s\">%s</link>", id, basename);
233 	}
234 
235 	g_fprintf (f, "</refsect1>");
236 }
237 
238 static void
print_toc_extra_properties(FILE * f,Ontology * ontology,const char * id,GHashTable * extra_properties)239 print_toc_extra_properties (FILE       *f,
240                             Ontology   *ontology,
241                             const char *id,
242                             GHashTable *extra_properties)
243 {
244 	GList *props_for_class, *c, *l;
245 	g_autoptr(GList) classes = NULL;
246 	gboolean print_comma = FALSE;
247 
248 	if (g_hash_table_size (extra_properties) == 0)
249 		return;
250 
251 	g_fprintf (f, "<refsect1 id=\"%s.extra_properties\">", id);
252 	g_fprintf (f, "<title>Additional Properties</title>");
253 
254 	classes = g_hash_table_get_keys (extra_properties);
255 	classes = g_list_sort (classes, (GCompareFunc)strcmp);
256 	for (c = classes; c; c = c->next) {
257 		gchar *classname;
258 
259 		classname = c->data;
260 		props_for_class = g_hash_table_lookup (extra_properties, classname);
261 		for (l = props_for_class; l; l = l->next) {
262 			OntologyProperty *prop;
263 			g_autofree char *basename = NULL, *prop_id = NULL;
264 
265 			prop = g_hash_table_lookup (ontology->properties, l->data);
266 
267 			basename = ttl_model_name_to_basename (ontology, prop->propertyname);
268 			prop_id = ttl_model_name_to_shortname (ontology, prop->propertyname, "-");
269 
270 			if (print_comma) {
271 				g_fprintf (f, ", ");
272 			} else {
273 				print_comma = TRUE;
274 			}
275 
276 			g_fprintf (f, "<link linkend=\"%s\">%s</link>", prop_id, basename);
277 		}
278 	}
279 
280 	g_fprintf (f, "</refsect1>");
281 }
282 
283 /* Generate docbook XML document for one ontology. */
284 void
ttl_xml_print(OntologyDescription * description,Ontology * ontology,GFile * file,const gchar * description_dir)285 ttl_xml_print (OntologyDescription *description,
286                Ontology            *ontology,
287                GFile               *file,
288                const gchar         *description_dir)
289 {
290 	gchar *upper_name, *path, *introduction, *basename;
291 	g_autoptr(GList) classes = NULL, properties = NULL, extra_classes = NULL;
292 	g_autoptr(GHashTable) extra_properties = NULL;
293 	GList *l;
294 	FILE *f;
295 
296 	path = g_file_get_path (file);
297 	f = fopen (path, "w");
298 	g_assert (f != NULL);
299 	g_free (path);
300 
301 	upper_name = g_ascii_strup (description->localPrefix, -1);
302 	classes = g_list_sort (g_hash_table_get_values (ontology->classes), compare_class);
303 	properties = g_hash_table_get_values (ontology->properties);
304 
305 	extra_properties = get_extra_properties (classes, properties);
306 
307 	print_xml_header (f, description);
308 
309 	print_synopsis (f, description);
310 	print_toc_classes (f, ontology, description->localPrefix, classes);
311 	print_toc_extra_properties (f, ontology, description->localPrefix, extra_properties);
312 
313 	basename = g_strdup_printf ("%s-introduction.xml", description->localPrefix);
314 	introduction = g_build_filename (description_dir, basename, NULL);
315 	g_free (basename);
316 
317 	if (g_file_test (introduction, G_FILE_TEST_EXISTS)) {
318 		g_fprintf (f, "<xi:include href='%s'><xi:fallback/></xi:include>",
319 		           introduction);
320 	}
321 
322 	if (classes != NULL) {
323     	g_fprintf (f, "<refsect1 id='%s-classes'>\n", description->localPrefix);
324 		g_fprintf (f, "<title>Class Details</title>\n");
325 
326 		for (l = classes; l; l = l->next) {
327 			print_ontology_class (ontology, l->data, f);
328 		}
329 
330 		g_fprintf (f, "</refsect1>\n");
331 	}
332 
333 	if (g_hash_table_size (extra_properties) > 0) {
334 		g_fprintf (f, "<refsect1 id='%s-extra-properties'>\n", description->localPrefix);
335 		g_fprintf (f, "<title>Property Details</title>\n");
336 
337 		extra_classes = g_hash_table_get_keys (extra_properties);
338 		extra_classes = g_list_sort (extra_classes, (GCompareFunc)strcmp);
339 		for (l = extra_classes; l; l = l->next) {
340 			gchar *classname;
341 			GList *properties_for_class;
342 
343 			classname = l->data;
344 
345 			properties_for_class = g_hash_table_lookup (extra_properties, classname);
346 			if (properties_for_class) {
347 				print_ontology_extra_properties (ontology, description->localPrefix, classname, properties_for_class, f);
348 			}
349 		}
350 
351 		g_fprintf (f, "</refsect1>\n");
352 	}
353 
354 	print_xml_footer (f, description);
355 
356 	g_free (upper_name);
357 	g_free (introduction);
358 	fclose (f);
359 }
360