blob: d41b37ae8ca4a4398bf97ed3e354095f2c1ff910 [file] [log] [blame]
<?php
/**
* File containing the ezcDocumentDocbookToHtmlConverter class.
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package Document
* @version //autogen//
* @copyright Copyright (C) 2005-2010 eZ Systems AS. All rights reserved.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
*/
/**
* Converter for docbook to XHtml with a PHP callback based mechanism, for fast
* and easy PHP based extensible transformations.
*
* This converter does not support the full docbook standard, but only a subset
* commonly used in the document component. If you need to transform documents
* using the full docbook you might prefer to use the
* ezcDocumentDocbookToHtmlXsltConverter with the default stylesheet from
* Welsh.
*
* @package Document
* @version //autogen//
*/
class ezcDocumentDocbookToHtmlConverter extends ezcDocumentElementVisitorConverter
{
/**
* Reference to the HTML header section
*
* @var DOMElement
*/
protected $head;
/**
* Array for footnotes aggregated during the processing of the document.
* Will be rendered at the end of the HTML document.
*
* @var array
*/
protected $footnotes = array();
/**
* Autoincrementing number for footnotes.
*
* @var int
*/
protected $footnoteNumber = 0;
/**
* Construct converter
*
* Construct converter from XSLT file, which is used for the actual
*
* @param ezcDocumentDocbookToHtmlConverterOptions $options
* @return void
*/
public function __construct( ezcDocumentDocbookToHtmlConverterOptions $options = null )
{
parent::__construct(
$options === null ?
new ezcDocumentDocbookToHtmlConverterOptions() :
$options
);
// Initlize common element handlers
$this->visitorElementHandler = array(
'docbook' => array(
'article' => $mapper = new ezcDocumentDocbookToHtmlMappingHandler(),
'book' => $mapper,
'sect1info' => $header = new ezcDocumentDocbookToHtmlHeadHandler(),
'sect2info' => $header,
'sect3info' => $header,
'sect4info' => $header,
'sect5info' => $header,
'sectioninfo' => $header,
'sect1' => $section = new ezcDocumentDocbookToHtmlSectionHandler(),
'sect2' => $section,
'sect3' => $section,
'sect4' => $section,
'sect5' => $section,
'section' => $section,
'title' => $section,
'para' => new ezcDocumentDocbookToHtmlParagraphHandler(),
'emphasis' => new ezcDocumentDocbookToHtmlEmphasisHandler(),
'literal' => $mapper,
'ulink' => new ezcDocumentDocbookToHtmlExternalLinkHandler(),
'link' => new ezcDocumentDocbookToHtmlInternalLinkHandler(),
'anchor' => new ezcDocumentDocbookToHtmlAnchorHandler(),
'inlinemediaobject' => $media = new ezcDocumentDocbookToHtmlMediaObjectHandler(),
'mediaobject' => $media,
'blockquote' => new ezcDocumentDocbookToHtmlBlockquoteHandler(),
'itemizedlist' => $mapper,
'orderedlist' => $mapper,
'listitem' => $mapper,
'note' => $special = new ezcDocumentDocbookToHtmlSpecialParagraphHandler(),
'tip' => $special,
'warning' => $special,
'important' => $special,
'caution' => $special,
'literallayout' => new ezcDocumentDocbookToHtmlLiteralLayoutHandler(),
'footnote' => new ezcDocumentDocbookToHtmlFootnoteHandler(),
'comment' => new ezcDocumentDocbookToHtmlCommentHandler(),
'beginpage' => $mapper,
'variablelist' => $mapper,
'varlistentry' => new ezcDocumentDocbookToHtmlDefinitionListEntryHandler(),
'entry' => new ezcDocumentDocbookToHtmlTableCellHandler(),
'table' => $mapper,
'tbody' => $mapper,
'thead' => $mapper,
'row' => $mapper,
'tgroup' => $ignore = new ezcDocumentDocbookToHtmlIgnoreHandler(),
)
);
}
/**
* Initialize destination document
*
* Initialize the structure which the destination document could be build
* with. This may be an initial DOMDocument with some default elements, or
* a string, or something else.
*
* @return mixed
*/
protected function initializeDocument()
{
$imp = new DOMImplementation();
$dtd = $imp->createDocumentType( 'html', '-//W3C//DTD XHTML 1.0 Transitional//EN', 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd' );
$html = $imp->createDocument( 'http://www.w3.org/1999/xhtml', '', $dtd );
$html->formatOutput = true;
$root = $html->createElementNs( 'http://www.w3.org/1999/xhtml', 'html' );
$html->appendChild( $root );
$this->head = $html->createElement( 'head' );
$root->appendChild( $this->head );
// Append generator
$generator = $html->createElement( 'meta' );
$generator->setAttribute( 'name', 'generator' );
$generator->setAttribute( 'content', 'eZ Components; http://ezcomponents.org' );
$this->head->appendChild( $generator );
// Set content type and encoding
$type = $html->createElement( 'meta' );
$type->setAttribute( 'http-equiv', 'Content-Type' );
$type->setAttribute( 'content', 'text/html; charset=utf-8' );
$this->head->appendChild( $type );
$this->addStylesheets( $this->head );
return $root;
}
/**
* Create document from structure
*
* Build a ezcDocumentDocument object from the structure created during the
* visiting process.
*
* @param mixed $content
* @return ezcDocumentDocument
*/
protected function createDocument( $content )
{
$document = $content->ownerDocument;
$this->appendFootnotes( $content );
// Ensure a title is set in the document header, as this is required by
// XHtml
$xpath = new DOMXPath( $document );
$title = $xpath->query( '/*[local-name() = "html"]/*[local-name() = "head"]/*[local-name() = "title"]' );
if ( $title->length < 1 )
{
$title = $document->createElement( 'title', 'Empty document' );
$this->head->appendChild( $title );
}
$html = new ezcDocumentXhtml();
$html->setDomDocument( $document );
return $html;
}
/**
* Visit text node.
*
* Visit a text node in the source document and transform it to the
* destination result
*
* @param DOMText $node
* @param mixed $root
* @return mixed
*/
protected function visitText( DOMText $node, $root )
{
if ( trim( $wholeText = $node->data ) !== '' )
{
$text = new DOMText( $wholeText );
$root->appendChild( $text );
}
return $root;
}
/**
* Add stylesheets to header
*
* @param DOMElement $head
* @return void
*/
protected function addStylesheets( DOMElement $head )
{
if ( $this->options->styleSheets !== null )
{
foreach ( $this->options->styleSheets as $styleSheet )
{
$link = $head->ownerDocument->createElement( 'link' );
$link->setAttribute( 'rel', 'Stylesheet' );
$link->setAttribute( 'type', 'text/css' );
$link->setAttribute( 'href', htmlspecialchars( $styleSheet ) );
$head->appendChild( $link );
}
}
else
{
$style = $head->ownerDocument->createElement( 'style' );
$style->setAttribute( 'type', 'text/css' );
$head->appendChild( $style );
$cdata = $head->ownerDocument->createCDATASection( $this->options->styleSheet );
$style->appendChild( $cdata );
}
}
/**
* Append footnotes
*
* Append the footnotes to the end of the document. The footnotes are
* embedded directly in the text in docbook, aggregated during the
* processing of the document, and displayed at the bottom of the HTML
* document.
*
* @param DOMElement $root
* @return void
*/
protected function appendFootnotes( DOMElement $root )
{
if ( !count( $this->footnotes ) )
{
// Do not do anything, if there aren't any footnotes.
return;
}
$body = $root->getElementsByTagName( 'body' )->item( 0 );
$footnoteContainer = $root->ownerDocument->createElement( 'ul' );
$footnoteContainer->setAttribute( 'class', 'footnotes' );
$body->appendChild( $footnoteContainer );
foreach ( $this->footnotes as $nr => $element )
{
$li = $root->ownerDocument->createElement( 'li' );
$footnoteContainer->appendChild( $li );
$reference = $root->ownerDocument->createElement( 'a', $nr );
$reference->setAttribute( 'name', 'footnote_' . $nr );
$li->appendChild( $reference );
// Visit actual footnote contents and append to the footnote.
$li = $this->visitChildren( $element, $li );
}
}
/**
* Append footnote
*
* Append a footnote to the document, which then will be visited at the end
* of the document processing. Returns a numeric identifier for the
* footnote.
*
* @param DOMElement $node
* @return int
*/
public function appendFootnote( DOMElement $node )
{
$this->footnotes[++$this->footnoteNumber] = $node;
return $this->footnoteNumber;
}
}
?>