Table of Contents
Docbook plugin
Compatible with DokuWiki
No compatibility info given!
The missing download url means that this extension cannot be installed via the Extension Manager. Please see Publishing a Plugin on dokuwiki.org. Recommended are public repository hosts like GitHub, GitLab or Bitbucket.
This extension has not been updated in over 2 years. It may no longer be maintained or supported and may have compatibility issues.
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… )
Requirements
- xsltproc: the XSLT processor used
- Docbook Stylesheets for XHTML: to transform Docbook documents in XHTML documents
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
Search and install the plugin using the Extension Manager.
Alternatively, refer to Plugins on how to install plugins manually. To install the plugin:
- Create a new directory
dokuwiki/lib/plugins/docbook
i.e. the subdirectorydocbook
in DokuWiki's plugin directory. - Copy the syntax.php below to a file called
syntax.php
, and the xhtmlCleaner.xsl below to a file calledxhtmlCleaner.xsl
, both in the newly created directory. - 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
- 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.