1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * Copyright (C) 2003-2009 Shaun McCance <shaunm@gnome.org>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public
16 * License along with this program; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
20 * Author: Shaun McCance <shaunm@gnome.org>
28 #include <glib/gi18n.h>
30 #include <libxml/parser.h>
31 #include <libxml/parserInternals.h>
32 #include <libxml/xinclude.h>
34 #include "yelp-docbook-document.h"
35 #include "yelp-error.h"
36 #include "yelp-settings.h"
37 #include "yelp-transform.h"
38 #include "yelp-debug.h"
40 #define STYLESHEET DATADIR"/yelp/xslt/db2html.xsl"
43 DOCBOOK_STATE_BLANK
, /* Brand new, run transform as needed */
44 DOCBOOK_STATE_PARSING
, /* Parsing/transforming document, please wait */
45 DOCBOOK_STATE_PARSED
, /* All done, if we ain't got it, it ain't here */
46 DOCBOOK_STATE_STOP
/* Stop everything now, object to be disposed */
54 static void yelp_docbook_document_class_init (YelpDocbookDocumentClass
*klass
);
55 static void yelp_docbook_document_init (YelpDocbookDocument
*docbook
);
56 static void yelp_docbook_document_dispose (GObject
*object
);
57 static void yelp_docbook_document_finalize (GObject
*object
);
59 static gboolean
docbook_request_page (YelpDocument
*document
,
61 GCancellable
*cancellable
,
62 YelpDocumentCallback callback
,
65 static void docbook_process (YelpDocbookDocument
*docbook
);
66 static void docbook_disconnect (YelpDocbookDocument
*docbook
);
68 static void docbook_walk (YelpDocbookDocument
*docbook
);
69 static gboolean
docbook_walk_chunkQ (YelpDocbookDocument
*docbook
);
70 static gboolean
docbook_walk_divisionQ (YelpDocbookDocument
*docbook
);
71 static gchar
* docbook_walk_get_title (YelpDocbookDocument
*docbook
);
73 static void transform_chunk_ready (YelpTransform
*transform
,
75 YelpDocbookDocument
*docbook
);
76 static void transform_finished (YelpTransform
*transform
,
77 YelpDocbookDocument
*docbook
);
78 static void transform_error (YelpTransform
*transform
,
79 YelpDocbookDocument
*docbook
);
80 static void transform_finalized (YelpDocbookDocument
*docbook
,
85 /* static gpointer docbook_get_sections (YelpDocument *document); */
88 G_DEFINE_TYPE (YelpDocbookDocument
, yelp_docbook_document
, YELP_TYPE_DOCUMENT
);
89 #define GET_PRIV(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), YELP_TYPE_DOCBOOK_DOCUMENT, YelpDocbookDocumentPrivate))
91 typedef struct _YelpDocbookDocumentPrivate YelpDocbookDocumentPrivate
;
92 struct _YelpDocbookDocumentPrivate
{
100 gboolean process_running
;
101 gboolean transform_running
;
103 YelpTransform
*transform
;
109 GtkTreeModel
*sections
;
110 GtkTreeIter
*sections_iter
; /* On the stack, do not free */
121 /******************************************************************************/
124 yelp_docbook_document_class_init (YelpDocbookDocumentClass
*klass
)
126 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
127 YelpDocumentClass
*document_class
= YELP_DOCUMENT_CLASS (klass
);
129 object_class
->dispose
= yelp_docbook_document_dispose
;
130 object_class
->finalize
= yelp_docbook_document_finalize
;
132 document_class
->request_page
= docbook_request_page
;
133 /*document_class->get_sections = docbook_get_sections;*/
135 g_type_class_add_private (klass
, sizeof (YelpDocbookDocumentPrivate
));
139 yelp_docbook_document_init (YelpDocbookDocument
*docbook
)
141 YelpDocbookDocumentPrivate
*priv
= GET_PRIV (docbook
);
143 priv
->sections
= NULL
;
145 priv
->state
= DOCBOOK_STATE_BLANK
;
147 priv
->mutex
= g_mutex_new ();
151 yelp_docbook_document_dispose (GObject
*object
)
153 YelpDocbookDocumentPrivate
*priv
= GET_PRIV (object
);
156 g_object_unref (priv
->uri
);
160 if (priv
->sections
) {
161 g_object_unref (priv
->sections
);
162 priv
->sections
= NULL
;
165 G_OBJECT_CLASS (yelp_docbook_document_parent_class
)->dispose (object
);
169 yelp_docbook_document_finalize (GObject
*object
)
171 YelpDocbookDocumentPrivate
*priv
= GET_PRIV (object
);
174 xmlFreeDoc (priv
->xmldoc
);
176 g_free (priv
->cur_page_id
);
177 g_free (priv
->cur_prev_id
);
178 g_free (priv
->root_id
);
180 g_mutex_free (priv
->mutex
);
182 G_OBJECT_CLASS (yelp_docbook_document_parent_class
)->finalize (object
);
185 /******************************************************************************/
188 yelp_docbook_document_new (YelpUri
*uri
)
190 YelpDocbookDocument
*docbook
;
191 YelpDocbookDocumentPrivate
*priv
;
193 g_return_val_if_fail (uri
!= NULL
, NULL
);
195 docbook
= (YelpDocbookDocument
*) g_object_new (YELP_TYPE_DOCBOOK_DOCUMENT
, NULL
);
196 priv
= GET_PRIV (docbook
);
198 priv
->uri
= g_object_ref (uri
);
200 yelp_document_set_page_id (YELP_DOCUMENT (docbook
), "//about", "//about");
203 GTK_TREE_MODEL (gtk_tree_store_new (2, G_TYPE_STRING
, G_TYPE_STRING
));
205 return (YelpDocument
*) docbook
;
208 /******************************************************************************/
210 /** YelpDocument **************************************************************/
212 /* static gpointer */
213 /* docbook_get_sections (YelpDocument *document) */
215 /* YelpDocbook *db = (YelpDocbook *) document; */
217 /* return (gpointer) (db->priv->sections); */
221 docbook_request_page (YelpDocument
*document
,
222 const gchar
*page_id
,
223 GCancellable
*cancellable
,
224 YelpDocumentCallback callback
,
227 YelpDocbookDocumentPrivate
*priv
= GET_PRIV (document
);
232 debug_print (DB_FUNCTION
, "entering\n");
233 debug_print (DB_ARG
, " page_id=\"%s\"\n", page_id
);
239 YELP_DOCUMENT_CLASS (yelp_docbook_document_parent_class
)->request_page (document
,
248 g_mutex_lock (priv
->mutex
);
250 switch (priv
->state
) {
251 case DOCBOOK_STATE_BLANK
:
252 priv
->state
= DOCBOOK_STATE_PARSING
;
253 priv
->process_running
= TRUE
;
254 g_object_ref (document
);
255 priv
->thread
= g_thread_create ((GThreadFunc
) docbook_process
,
256 document
, FALSE
, NULL
);
258 case DOCBOOK_STATE_PARSING
:
260 case DOCBOOK_STATE_PARSED
:
261 case DOCBOOK_STATE_STOP
:
262 docuri
= yelp_uri_get_document_uri (priv
->uri
);
263 error
= g_error_new (YELP_ERROR
, YELP_ERROR_NOT_FOUND
,
264 _("The page ā%sā was not found in the document ā%sā."),
267 yelp_document_signal (document
, page_id
,
268 YELP_DOCUMENT_SIGNAL_ERROR
,
270 g_error_free (error
);
274 g_mutex_unlock (priv
->mutex
);
277 /******************************************************************************/
280 docbook_process (YelpDocbookDocument
*docbook
)
282 YelpDocbookDocumentPrivate
*priv
= GET_PRIV (docbook
);
283 YelpDocument
*document
= YELP_DOCUMENT (docbook
);
285 gchar
*filepath
= NULL
;
286 xmlDocPtr xmldoc
= NULL
;
288 xmlParserCtxtPtr parserCtxt
= NULL
;
291 gchar
**params
= NULL
;
293 debug_print (DB_FUNCTION
, "entering\n");
295 file
= yelp_uri_get_file (priv
->uri
);
297 error
= g_error_new (YELP_ERROR
, YELP_ERROR_NOT_FOUND
,
298 _("The file does not exist."));
299 yelp_document_error_pending (document
, error
);
300 g_error_free (error
);
304 filepath
= g_file_get_path (file
);
305 g_object_unref (file
);
306 if (!g_file_test (filepath
, G_FILE_TEST_IS_REGULAR
)) {
307 error
= g_error_new (YELP_ERROR
, YELP_ERROR_NOT_FOUND
,
308 _("The file ā%sā does not exist."),
310 yelp_document_error_pending (document
, error
);
311 g_error_free (error
);
315 parserCtxt
= xmlNewParserCtxt ();
316 xmldoc
= xmlCtxtReadFile (parserCtxt
,
318 XML_PARSE_DTDLOAD
| XML_PARSE_NOCDATA
|
319 XML_PARSE_NOENT
| XML_PARSE_NONET
);
321 if (xmldoc
== NULL
) {
322 error
= g_error_new (YELP_ERROR
, YELP_ERROR_PROCESSING
,
323 _("The file ā%sā could not be parsed because it is"
324 " not a well-formed XML document."),
326 yelp_document_error_pending (document
, error
);
327 g_error_free (error
);
331 if (xmlXIncludeProcessFlags (xmldoc
,
332 XML_PARSE_DTDLOAD
| XML_PARSE_NOCDATA
|
333 XML_PARSE_NOENT
| XML_PARSE_NONET
)
335 error
= g_error_new (YELP_ERROR
, YELP_ERROR_PROCESSING
,
336 _("The file ā%sā could not be parsed because"
337 " one or more of its included files is not"
338 " a well-formed XML document."),
340 yelp_document_error_pending (document
, error
);
341 g_error_free (error
);
345 g_mutex_lock (priv
->mutex
);
346 if (!xmlStrcmp (xmlDocGetRootElement (xmldoc
)->name
, BAD_CAST
"book"))
351 priv
->xmldoc
= xmldoc
;
352 priv
->xmlcur
= xmlDocGetRootElement (xmldoc
);
354 id
= xmlGetProp (priv
->xmlcur
, BAD_CAST
"id");
356 id
= xmlGetNsProp (priv
->xmlcur
, XML_XML_NAMESPACE
, BAD_CAST
"id");
359 priv
->root_id
= g_strdup (id
);
360 yelp_document_set_page_id (document
, NULL
, (gchar
*) id
);
361 yelp_document_set_page_id (document
, "//index", (gchar
*) id
);
362 yelp_document_set_prev_id (document
, (gchar
*) id
, "//about");
363 yelp_document_set_next_id (document
, "//about", (gchar
*) id
);
366 priv
->root_id
= g_strdup ("//index");
367 yelp_document_set_page_id (document
, NULL
, "//index");
368 yelp_document_set_prev_id (document
, "//index", "//about");
369 yelp_document_set_next_id (document
, "//about", "//index");
370 /* add the id attribute to the root element with value "index"
371 * so when we try to load the document later, it doesn't fail */
372 if (priv
->xmlcur
->ns
)
373 xmlNewNsProp (priv
->xmlcur
,
374 xmlNewNs (priv
->xmlcur
, XML_XML_NAMESPACE
, BAD_CAST
"xml"),
375 BAD_CAST
"id", BAD_CAST
"//index");
377 xmlNewProp (priv
->xmlcur
, BAD_CAST
"id", BAD_CAST
"//index");
379 yelp_document_set_root_id (document
, priv
->root_id
, priv
->root_id
);
380 yelp_document_set_root_id (document
, "//about", priv
->root_id
);
381 g_mutex_unlock (priv
->mutex
);
383 g_mutex_lock (priv
->mutex
);
384 if (priv
->state
== DOCBOOK_STATE_STOP
) {
385 g_mutex_unlock (priv
->mutex
);
388 g_mutex_unlock (priv
->mutex
);
390 docbook_walk (docbook
);
392 g_mutex_lock (priv
->mutex
);
393 if (priv
->state
== DOCBOOK_STATE_STOP
) {
394 g_mutex_unlock (priv
->mutex
);
398 priv
->transform
= yelp_transform_new (STYLESHEET
);
400 g_signal_connect (priv
->transform
, "chunk-ready",
401 (GCallback
) transform_chunk_ready
,
404 g_signal_connect (priv
->transform
, "finished",
405 (GCallback
) transform_finished
,
408 g_signal_connect (priv
->transform
, "error",
409 (GCallback
) transform_error
,
412 params
= yelp_settings_get_all_params (yelp_settings_get_default (), 2, ¶ms_i
);
413 params
[params_i
++] = g_strdup ("db.chunk.max_depth");
414 params
[params_i
++] = g_strdup_printf ("%i", priv
->max_depth
);
415 params
[params_i
] = NULL
;
417 priv
->transform_running
= TRUE
;
418 yelp_transform_start (priv
->transform
,
421 (const gchar
* const *) params
);
423 g_mutex_unlock (priv
->mutex
);
430 xmlFreeParserCtxt (parserCtxt
);
432 priv
->process_running
= FALSE
;
433 g_object_unref (docbook
);
437 docbook_disconnect (YelpDocbookDocument
*docbook
)
439 YelpDocbookDocumentPrivate
*priv
= GET_PRIV (docbook
);
440 if (priv
->chunk_ready
) {
441 g_signal_handler_disconnect (priv
->transform
, priv
->chunk_ready
);
442 priv
->chunk_ready
= 0;
444 if (priv
->finished
) {
445 g_signal_handler_disconnect (priv
->transform
, priv
->finished
);
449 g_signal_handler_disconnect (priv
->transform
, priv
->error
);
452 yelp_transform_cancel (priv
->transform
);
453 g_object_unref (priv
->transform
);
454 priv
->transform
= NULL
;
455 priv
->transform_running
= FALSE
;
458 /******************************************************************************/
461 docbook_walk (YelpDocbookDocument
*docbook
)
463 static gint autoid
= 0;
466 xmlChar
*title
= NULL
;
467 gchar
*old_page_id
= NULL
;
468 xmlNodePtr cur
, old_cur
;
470 GtkTreeIter
*old_iter
= NULL
;
472 YelpDocbookDocumentPrivate
*priv
= GET_PRIV (docbook
);
473 YelpDocument
*document
= YELP_DOCUMENT (docbook
);
475 debug_print (DB_FUNCTION
, "entering\n");
476 debug_print (DB_DEBUG
, " priv->xmlcur->name: %s\n", priv
->xmlcur
->name
);
478 /* Check for the db.chunk.max_depth PI and set max chunk depth */
479 if (priv
->cur_depth
== 0)
480 for (cur
= priv
->xmlcur
; cur
; cur
= cur
->prev
)
481 if (cur
->type
== XML_PI_NODE
)
482 if (!xmlStrcmp (cur
->name
, (const xmlChar
*) "db.chunk.max_depth")) {
483 gint max
= atoi ((gchar
*) cur
->content
);
485 priv
->max_depth
= max
;
489 id
= xmlGetProp (priv
->xmlcur
, BAD_CAST
"id");
491 id
= xmlGetNsProp (priv
->xmlcur
, XML_XML_NAMESPACE
, BAD_CAST
"id");
493 if (docbook_walk_divisionQ (docbook
) && !id
) {
494 /* If id attribute is not present, autogenerate a
495 * unique value, and insert it into the in-memory tree */
496 g_snprintf (autoidstr
, 20, "//autoid-%d", ++autoid
);
497 if (priv
->xmlcur
->ns
) {
498 xmlNewNsProp (priv
->xmlcur
,
499 xmlNewNs (priv
->xmlcur
, XML_XML_NAMESPACE
, BAD_CAST
"xml"),
500 BAD_CAST
"id", BAD_CAST autoidstr
);
501 id
= xmlGetNsProp (priv
->xmlcur
, XML_XML_NAMESPACE
, BAD_CAST
"id");
504 xmlNewProp (priv
->xmlcur
, BAD_CAST
"id", BAD_CAST autoidstr
);
505 id
= xmlGetProp (priv
->xmlcur
, BAD_CAST
"id");
509 if (docbook_walk_chunkQ (docbook
)) {
510 title
= BAD_CAST
docbook_walk_get_title (docbook
);
512 debug_print (DB_DEBUG
, " id: \"%s\"\n", id
);
513 debug_print (DB_DEBUG
, " title: \"%s\"\n", title
);
515 yelp_document_set_page_title (document
, (gchar
*) id
, (gchar
*) title
);
517 gdk_threads_enter ();
518 gtk_tree_store_append (GTK_TREE_STORE (priv
->sections
),
520 priv
->sections_iter
);
521 gtk_tree_store_set (GTK_TREE_STORE (priv
->sections
),
523 DOCBOOK_COLUMN_ID
, id
,
524 DOCBOOK_COLUMN_TITLE
, title
,
526 gdk_threads_leave ();
528 if (priv
->cur_prev_id
) {
529 yelp_document_set_prev_id (document
, (gchar
*) id
, priv
->cur_prev_id
);
530 yelp_document_set_next_id (document
, priv
->cur_prev_id
, (gchar
*) id
);
531 g_free (priv
->cur_prev_id
);
533 priv
->cur_prev_id
= g_strdup ((gchar
*) id
);
535 if (priv
->cur_page_id
)
536 yelp_document_set_up_id (document
, (gchar
*) id
, priv
->cur_page_id
);
537 old_page_id
= priv
->cur_page_id
;
538 priv
->cur_page_id
= g_strdup ((gchar
*) id
);
540 old_iter
= priv
->sections_iter
;
541 if (priv
->xmlcur
->parent
->type
!= XML_DOCUMENT_NODE
)
542 priv
->sections_iter
= &iter
;
545 old_cur
= priv
->xmlcur
;
548 yelp_document_set_root_id (document
, (gchar
*) id
, priv
->root_id
);
549 yelp_document_set_page_id (document
, (gchar
*) id
, priv
->cur_page_id
);
552 chunkQ
= docbook_walk_chunkQ (docbook
);
554 yelp_document_signal (YELP_DOCUMENT (docbook
),
556 YELP_DOCUMENT_SIGNAL_INFO
,
559 for (cur
= priv
->xmlcur
->children
; cur
; cur
= cur
->next
) {
560 if (cur
->type
== XML_ELEMENT_NODE
) {
562 docbook_walk (docbook
);
566 priv
->xmlcur
= old_cur
;
569 priv
->sections_iter
= old_iter
;
570 g_free (priv
->cur_page_id
);
571 priv
->cur_page_id
= old_page_id
;
574 if (priv
->cur_depth
== 0) {
575 g_free (priv
->cur_prev_id
);
576 priv
->cur_prev_id
= NULL
;
578 g_free (priv
->cur_page_id
);
579 priv
->cur_page_id
= NULL
;
589 docbook_walk_chunkQ (YelpDocbookDocument
*docbook
)
591 YelpDocbookDocumentPrivate
*priv
= GET_PRIV (docbook
);
592 if (priv
->cur_depth
<= priv
->max_depth
)
593 return docbook_walk_divisionQ (docbook
);
599 docbook_walk_divisionQ (YelpDocbookDocument
*docbook
)
601 YelpDocbookDocumentPrivate
*priv
= GET_PRIV (docbook
);
602 xmlNodePtr node
= priv
->xmlcur
;
603 return (!xmlStrcmp (node
->name
, (const xmlChar
*) "appendix") ||
604 !xmlStrcmp (node
->name
, (const xmlChar
*) "article") ||
605 !xmlStrcmp (node
->name
, (const xmlChar
*) "book") ||
606 !xmlStrcmp (node
->name
, (const xmlChar
*) "bibliography") ||
607 !xmlStrcmp (node
->name
, (const xmlChar
*) "chapter") ||
608 !xmlStrcmp (node
->name
, (const xmlChar
*) "colophon") ||
609 !xmlStrcmp (node
->name
, (const xmlChar
*) "glossary") ||
610 !xmlStrcmp (node
->name
, (const xmlChar
*) "index") ||
611 !xmlStrcmp (node
->name
, (const xmlChar
*) "part") ||
612 !xmlStrcmp (node
->name
, (const xmlChar
*) "preface") ||
613 !xmlStrcmp (node
->name
, (const xmlChar
*) "reference") ||
614 !xmlStrcmp (node
->name
, (const xmlChar
*) "refentry") ||
615 !xmlStrcmp (node
->name
, (const xmlChar
*) "refsect1") ||
616 !xmlStrcmp (node
->name
, (const xmlChar
*) "refsect2") ||
617 !xmlStrcmp (node
->name
, (const xmlChar
*) "refsect3") ||
618 !xmlStrcmp (node
->name
, (const xmlChar
*) "refsection") ||
619 !xmlStrcmp (node
->name
, (const xmlChar
*) "sect1") ||
620 !xmlStrcmp (node
->name
, (const xmlChar
*) "sect2") ||
621 !xmlStrcmp (node
->name
, (const xmlChar
*) "sect3") ||
622 !xmlStrcmp (node
->name
, (const xmlChar
*) "sect4") ||
623 !xmlStrcmp (node
->name
, (const xmlChar
*) "sect5") ||
624 !xmlStrcmp (node
->name
, (const xmlChar
*) "section") ||
625 !xmlStrcmp (node
->name
, (const xmlChar
*) "set") ||
626 !xmlStrcmp (node
->name
, (const xmlChar
*) "setindex") ||
627 !xmlStrcmp (node
->name
, (const xmlChar
*) "simplesect") );
631 docbook_walk_get_title (YelpDocbookDocument
*docbook
)
633 YelpDocbookDocumentPrivate
*priv
= GET_PRIV (docbook
);
634 gchar
*infoname
= NULL
;
635 xmlNodePtr child
= NULL
;
636 xmlNodePtr title
= NULL
;
637 xmlNodePtr title_tmp
= NULL
;
639 if (!xmlStrcmp (priv
->xmlcur
->name
, BAD_CAST
"refentry")) {
640 /* The title for a refentry element can come from the following:
641 * refmeta/refentrytitle
642 * refentryinfo/title[abbrev]
644 * We take the first one we find.
646 for (child
= priv
->xmlcur
->children
; child
; child
= child
->next
) {
647 if (!xmlStrcmp (child
->name
, BAD_CAST
"refmeta")) {
648 for (title
= child
->children
; title
; title
= title
->next
) {
649 if (!xmlStrcmp (title
->name
, BAD_CAST
"refentrytitle"))
655 else if (!xmlStrcmp (child
->name
, BAD_CAST
"refentryinfo")) {
656 for (title
= child
->children
; title
; title
= title
->next
) {
657 if (!xmlStrcmp (title
->name
, BAD_CAST
"titleabbrev"))
659 else if (!xmlStrcmp (title
->name
, BAD_CAST
"title"))
664 else if (title_tmp
) {
669 else if (!xmlStrcmp (child
->name
, BAD_CAST
"refnamediv")) {
670 for (title
= child
->children
; title
; title
= title
->next
) {
671 if (!xmlStrcmp (title
->name
, BAD_CAST
"refname"))
673 else if (!xmlStrcmp (title
->name
, BAD_CAST
"refpurpose")) {
681 else if (!xmlStrncmp (child
->name
, BAD_CAST
"refsect", 7))
686 /* The title for other elements appears in the following:
688 * *info/title[abbrev]
689 * blockinfo/title[abbrev]
690 * objectinfo/title[abbrev]
691 * We take them in that order.
693 xmlNodePtr infos
[3] = {NULL
, NULL
, NULL
};
696 infoname
= g_strdup_printf ("%sinfo", priv
->xmlcur
->name
);
698 for (child
= priv
->xmlcur
->children
; child
; child
= child
->next
) {
699 if (!xmlStrcmp (child
->name
, BAD_CAST
"titleabbrev")) {
703 else if (!xmlStrcmp (child
->name
, BAD_CAST
"title"))
705 else if (!xmlStrcmp (child
->name
, BAD_CAST
"info"))
707 else if (!xmlStrcmp (child
->name
, BAD_CAST infoname
))
709 else if (!xmlStrcmp (child
->name
, BAD_CAST
"blockinfo"))
711 else if (!xmlStrcmp (child
->name
, BAD_CAST
"objectinfo"))
720 for (i
= 0; i
< 3; i
++) {
723 for (title
= child
->children
; title
; title
= title
->next
) {
724 if (!xmlStrcmp (title
->name
, BAD_CAST
"titleabbrev"))
726 else if (!xmlStrcmp (title
->name
, BAD_CAST
"title"))
741 return (gchar
*) xmlNodeGetContent (title
);
743 return g_strdup (_("Unknown"));
746 /******************************************************************************/
749 transform_chunk_ready (YelpTransform
*transform
,
751 YelpDocbookDocument
*docbook
)
753 YelpDocbookDocumentPrivate
*priv
= GET_PRIV (docbook
);
756 debug_print (DB_FUNCTION
, "entering\n");
757 g_assert (transform
== priv
->transform
);
759 if (priv
->state
== DOCBOOK_STATE_STOP
) {
760 docbook_disconnect (docbook
);
764 content
= yelp_transform_take_chunk (transform
, chunk_id
);
765 yelp_document_give_contents (YELP_DOCUMENT (docbook
),
768 "application/xhtml+xml");
770 yelp_document_signal (YELP_DOCUMENT (docbook
),
772 YELP_DOCUMENT_SIGNAL_CONTENTS
,
777 transform_finished (YelpTransform
*transform
,
778 YelpDocbookDocument
*docbook
)
780 YelpDocbookDocumentPrivate
*priv
= GET_PRIV (docbook
);
784 debug_print (DB_FUNCTION
, "entering\n");
785 g_assert (transform
== priv
->transform
);
787 if (priv
->state
== DOCBOOK_STATE_STOP
) {
788 docbook_disconnect (docbook
);
792 docbook_disconnect (docbook
);
794 /* We want to free priv->xmldoc, but we can't free it before transform
795 is finalized. Otherwise, we could crash when YelpTransform frees
796 its libxslt resources.
798 g_object_weak_ref ((GObject
*) transform
,
799 (GWeakNotify
) transform_finalized
,
802 docuri
= yelp_uri_get_document_uri (priv
->uri
);
803 error
= g_error_new (YELP_ERROR
, YELP_ERROR_NOT_FOUND
,
804 _("The requested page was not found in the document ā%sā."),
807 yelp_document_error_pending ((YelpDocument
*) docbook
, error
);
808 g_error_free (error
);
812 transform_error (YelpTransform
*transform
,
813 YelpDocbookDocument
*docbook
)
815 YelpDocbookDocumentPrivate
*priv
= GET_PRIV (docbook
);
818 debug_print (DB_FUNCTION
, "entering\n");
819 g_assert (transform
== priv
->transform
);
821 if (priv
->state
== DOCBOOK_STATE_STOP
) {
822 docbook_disconnect (docbook
);
826 error
= yelp_transform_get_error (transform
);
827 yelp_document_error_pending ((YelpDocument
*) docbook
, error
);
828 g_error_free (error
);
830 docbook_disconnect (docbook
);
834 transform_finalized (YelpDocbookDocument
*docbook
,
837 YelpDocbookDocumentPrivate
*priv
= GET_PRIV (docbook
);
839 debug_print (DB_FUNCTION
, "entering\n");
842 xmlFreeDoc (priv
->xmldoc
);