DokuWiki

It's better when it's simple

User Tools

Site Tools


plugin:docbook

Docbook plugin

Compatible with DokuWiki

No compatibility info given!

plugin Renders Docbook code as XHTML using XSLT

Last updated on
2006-04-12
Provides
Syntax

Tagged with code, formatting

plugin

This plugin renders a Docbook block transforming it to XHTML.

The transformation from Docbook to XHTML is made using XSL stylesheets, so this is a slow process. To do the transformation, xsltproc is used.

No PHP XSL functions were used because of my own needs (a server with xsltproc but without XSLT extension for PHP, and no root access).

Please note that this plugin is only a little work made to cover my own needs. This is also my first DokuWiki plugin, and the first time I use PHP, so… feel free to improve it :-) I'm sure it needs a lot of improvements ;-) And, sadly, I don't have the necessary time to do it (in fact… I should have been doing the project that I made this plugin for instead of doing the plugin… :-P)

Requirements

Syntax

<docbook>
    Docbook block
</docbook>

Entities referencing system resources can't be used. So you can't do (well, you can, but you won't get anything) things like a book element referencing its chapters as explained in Physical Divisions: Breaking a Document into Physical Chunks. However, you can create chapters in docbook blocks and they'll show as XHTML. The only problem is that they won't get included in the book element, thus not being showed as XHTML in that docbook block.

A workaround for this could be simply doing things like explained in the link, but, instead of adding &chap1; &chap2; and so on to book element, include a link after the closing </docbook> element to the pages with each chapter (provided you're using one page for each chapter, of course).

<docbook>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
<!ENTITY chap1 SYSTEM "chap1.docbook">
<!ENTITY chap2 SYSTEM "chap2.docbook">
]>
<book>
    <title>My First Book</title>
</book>
</docbook>
[[chap1]]
[[chap2]]

Installation

To install the plugin:

  1. Create a new directory dokuwiki/lib/plugins/docbook i.e. the subdirectory docbook in DokuWiki's plugin directory.
  2. Copy the syntax.php below to a file called syntax.php, and the xhtmlCleaner.xsl below to a file called xhtmlCleaner.xsl, both in the newly created directory.
  3. The new directory and the new files must be readable by the web-server

The plugin is now installed.

Settings

The plugin has two configuration settings. They're changed in the plugin script file, syntax.php, in the “docbook settings” section:

  • $xsltproc — the executable for xsltproc. If a path to the executable is used, it must be absolute. Default = 'xsltproc'
  • $docbookXsl — the absolute path to the XSL to apply to docbook blocks.
    Default = '/usr/share/sgml/docbook/xsl-stylesheets-1.69.1/xhtml/docbook.xsl'

Details

The plugin consists of two files: the plugin script (syntax.php) and a XSL file (xhtmlCleaner.xsl) to get only body element's children from a complete XHTML document

syntax.php

<?php
 
/**
 * Docbook-Plugin: Renders docbook blocks transforming them to XHTML
 *
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
 * @author     Daniel Calviño Sánchez <danxuliu@gmail.com>
 */
 
if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'inc/plugins/');
require_once(DOKU_PLUGIN.'syntax.php');
 
 
// -----------------------[ docbook settings ]------------------------------------
global $xsltproc, $docbookXsl;
 
/**
 * The executable for xsltproc. If a path to the executable is used, it must be absolute.
 */
$xsltproc = 'xsltproc';
 
/**
 * The absolute path to the XSL to apply to docbook blocks.
 */
$docbookXsl = '/usr/share/sgml/docbook/xsl-stylesheets-1.69.1/xhtml/docbook.xsl';
 
// ------------------------------------------------------------------------------------
 
/**
 * Syntax plugin for docbook support.
 *
 * The text enclosed between <docbook> and </docbook> tags is treated as a block of docbook text.
 * Docbook blocks are transformed in XHTML using XSL stylesheets to be rendered as XHTML.
 */
class syntax_plugin_docbook extends DokuWiki_Syntax_Plugin {
 
    /**
     * General Info
     *
     * Returns an associative array with some info about the plugin
     */
    function getInfo(){
        return array(
            'author' => 'Daniel Calviño Sánchez',
            'email'  => 'danxuliu@gmail.com',
            'date'   => '2006-04-12',
            'name'   => 'Docbook Plugin',
            'desc'   => 'Allows Docbook markup and renders it as XHTML',
            'url'    => 'http://www.dokuwiki.org/plugin:docbook',
        );
    }
 
    /**
     * Sets syntax type as protected.
     */
    function getType(){
        return 'protected';
    }
 
    /**
     * Paragraph Type
     *
     * Set as 'block': Open paragraphs need to be closed before plugin output
     *
     * @see Doku_Handler_Block
     */
    function getPType(){
        return 'block';
    }
 
    /**
     * Where to sort in?
     */
    function getSort(){
        return 200;
    }
 
    /**
     * Connect pattern to lexer
     */
    function connectTo($mode) {
        $this->Lexer->addEntryPattern('<docbook>',$mode,'plugin_docbook');
    }
 
    function postConnect() {
      $this->Lexer->addExitPattern('</docbook>','plugin_docbook');
    }
 
    /**
     * Handler to prepare matched data for the rendering process
     *
     * @param   $match   string    The text matched by the patterns
     * @param   $state   int       The lexer state for the match
     * @param   $pos     int       The character position of the matched text
     * @param   $handler ref       Reference to the Doku_Handler object
     * @return  array              Return an array with all data you want to use in render
     */
    function handle($match, $state, $pos, &$handler){
        switch ($state) {
            case DOKU_LEXER_ENTER:
            case DOKU_LEXER_EXIT:
                return array($state, '');
                break;
            case DOKU_LEXER_UNMATCHED:
                return array($state, $match);
                break;
        }
 
        return array();
    }
 
    /**
     * Handles the actual output creation.
     *
     * @param   $format   string   output format to being Rendered
     * @param   $renderer ref      reference to the current renderer object
     * @param   $data     array    data created by handler()
     * @return  boolean            rendered correctly?
     */
    function render($mode, &$renderer, $data) {
        if($mode == 'xhtml'){
            list($state, $match) = $data;
            switch ($state) {
              case DOKU_LEXER_ENTER :
                  $renderer->doc .= "\n<!-- Begins docbook block -->\n";
                  break;
              case DOKU_LEXER_UNMATCHED :
                  $renderer->doc .= $this->transformDocbookInXhtml($match);
                  break;
              case DOKU_LEXER_EXIT :
                  $renderer->doc .= "\n<!-- Ends docbook block -->\n";
                  break;
            }
 
            return true;
        }
        return false;
    }
 
    /**
     * Applies the stylesheet defined in settings to the docbook block to get a XHTML document,
     * gets body element's children removing the xmlns declaration for XHTML and returns
     * the resulting string.
     *
     * Uses xsltproc program executed in an external shell to do the XSL transformations.
     * It also creates some cache files with the docbook block and the XHTML document
     * made when applying the XSLT to the docbook.
     *
     * @param   $docbookBlock   The docbook block to be transformed
     * @return  string          The transformed XHTML code
     */
    function transformDocbookInXhtml($docbookBlock) {
        global $xsltproc, $docbookXsl, $ID;
 
        $tmpDocbookFile  = getCacheName('tmpDocbookFile'.$ID.$_SERVER['HTTP_HOST'].$_SERVER['SERVER_PORT'],'.docbook');
        $tmpXhtmlFile  = getCacheName('tmpXhtmlFile'.$ID.$_SERVER['HTTP_HOST'].$_SERVER['SERVER_PORT'],'.html');
 
        //Docbook block must be saved so it can be transformed with xsltproc
        io_saveFile($tmpDocbookFile,$docbookBlock);
 
        //XHTML transformed document must also be saved because the same reason
        exec("$xsltproc -o $tmpXhtmlFile $docbookXsl $tmpDocbookFile 2>&1", $errors);
 
        if ($errors) {
            return $this->getXhtmlForXsltErrors($errors,$tmpDocbookFile);
        }
 
        //Gets body element's children. No errors should happen here.
        $returnXhtml = shell_exec("$xsltproc " . DOKU_PLUGIN . "/docbook/xhtmlCleaner.xsl $tmpXhtmlFile");
 
        //Removes xmlns declaration for xhtml in generated elements
        $returnXhtml = str_replace(" xmlns=\"http://www.w3.org/1999/xhtml\"", "", $returnXhtml);
        return $returnXhtml;
    }
 
    /**
     * Returns an error message containing all the error lines in the errors array in a XHTML "pre" element,
     * on line for each array's element. The name of the temporal file being processed is replaced in the
     * outputted message with "docbook block".
     *
     * @param	$errors		An array containing the outputted error lines
     * @param	$tmpFile	The name of the temporal file that the transformation was applied to
     * @return 	string		The XHTML code with the error message
     */
    function getXhtmlForXsltErrors($errors, $tmpFile) {
        $returnXhtml .= '<div class="error">';
        $returnXhtml .= "<p>An error occured when transforming docbook block:</p>\n";
 
        $returnXhtml .= "<pre>";
        for ($i = 0; $i < count($errors); $i++) {
            $errors[$i] = str_replace($tmpFile,'docbook block',$errors[$i]);
            $errors[$i] = htmlentities($errors[$i],ENT_COMPAT,'UTF-8');
            $returnXhtml .= $errors[$i]."\n";
        }
        $returnXhtml .= "</pre>\n</div>";
 
        return $returnXhtml;
    }
}
 
//Setup VIM: ex: et ts=4 enc=utf-8 :

xhtmlCleaner.xsl

<?xml version="1.0" encoding="utf-8"?>
 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xhtml="http://www.w3.org/1999/xhtml">
 
	<xsl:output method="xml" encoding="utf-8" indent="yes" omit-xml-declaration="yes" standalone="no"/>
 
	<!--
		All the child elements of the body element are copied.
		html elements, header elements and header's children are ignored
	-->
	<xsl:template match="/">
		<xsl:copy-of select="xhtml:html/xhtml:body/*"/>
	</xsl:template>
 
</xsl:stylesheet>

TODO

At this moment, I have no time to develop nothing else in this plugin. However, here are some ideas that could be interesting to add to the plugin, so if someone wants to make them… :-):

  • Process entities referencing external resources such as &chap1; so they're replaced with a link to the wiki page containing the referenced chapter. Or maybe including the chapter itself as the entity should do.
  • Use XSLT PHP extension or xsltproc, selectable in the configuration.
  • At this moment, cache files are used to create the temporary files, but their content isn't reused. Maybe they should be pure temporary files and be destroyed once they are no longer needed.

Discussion

plugin/docbook.txt · Last modified: 2009/10/07 14:34 by laynee