wez Tue May 25 07:33:48 2004 EDT
Added files:
/livedocs livedoc_funcs.php pregenerate.php xml_classes5.php
Modified files:
/livedocs configure.in livedoc.php mkindex.php
/livedocs/themes/default html_format.php
Log:
Big commit; will be a little unclear what has changed.
- Split the functions out from livedoc.php and into livedoc_funcs.php
- Added PHP 5 version of xml_classes5.php; assignment using the reference
operator leaks massive amounts of memory and will not be fixed.
- Added pregenerate.php which should be run using PHP 5 (see above!) only to
generate the entire manual as individual html pages.
- Some minor corrections to Ilia's perf tweaks
- Smarter entity handling
Discovery:
do_nav() is way too slow; don't attempt to pregenerate anything until it is
tuned, unless you are a gentoo user with CPU to burn.
http://cvs.php.net/diff.php/livedocs/configure.in?r1=1.25&r2=1.26&ty=u
Index: livedocs/configure.in
diff -u livedocs/configure.in:1.25 livedocs/configure.in:1.26
--- livedocs/configure.in:1.25 Tue May 4 21:37:04 2004
+++ livedocs/configure.in Tue May 25 07:33:48 2004
@@ -1,5 +1,5 @@
## A configure script
-## $Id: configure.in,v 1.25 2004/05/05 01:37:04 wez Exp $
+## $Id: configure.in,v 1.26 2004/05/25 11:33:48 wez Exp $
AC_PREREQ(2.13)
AC_INIT(livedoc.php)
@@ -138,6 +138,7 @@
cp common.php config.php .htaccess $OUTPUTDIR
rm -f .htaccess
$lncmd $LIVEDOCS/livedoc.php $OUTPUTDIR/index.php
+ $lncmd $LIVEDOCS/livedoc_funcs.php $OUTPUTDIR/livedoc_funcs.php
$lncmd $LIVEDOCS/error.php $OUTPUTDIR/error.php
$lncmd $LIVEDOCS/style_mapping.php $OUTPUTDIR/style_mapping.php
$lncmd $LIVEDOCS/xml_classes.php $OUTPUTDIR/xml_classes.php
@@ -148,13 +149,12 @@
echo ""
echo "You have configured livedocs so that links are relative to
http://yourserver$WEBBASE"
echo "$OUTPUTDIR is assumed to be the dir that is displayed by your webserver for
that URL"
-fi
-
-dnl Generate config.nice (primitive, but saves some brain power)
-echo "#!/bin/sh" > config.nice
-echo "./configure $*" >> config.nice
-chmod +x config.nice
+ dnl Generate config.nice (primitive, but saves some brain power)
+ echo "#!/bin/sh" > config.nice
+ echo "./configure $*" >> config.nice
+ chmod +x config.nice
+fi
dnl vim:et:sw=2:ts=2
http://cvs.php.net/diff.php/livedocs/livedoc.php?r1=1.106&r2=1.107&ty=u
Index: livedocs/livedoc.php
diff -u livedocs/livedoc.php:1.106 livedocs/livedoc.php:1.107
--- livedocs/livedoc.php:1.106 Mon May 24 16:59:28 2004
+++ livedocs/livedoc.php Tue May 25 07:33:48 2004
@@ -18,15 +18,10 @@
// | Generate an HTML version of a phpdoc/docbook page on the fly |
// +----------------------------------------------------------------------+
//
-// $Id: livedoc.php,v 1.106 2004/05/24 20:59:28 iliaa Exp $
+// $Id: livedoc.php,v 1.107 2004/05/25 11:33:48 wez Exp $
define('LIVEDOC_SOURCE', dirname(__FILE__));
-include LIVEDOC_SOURCE . '/common.php';
-include LIVEDOC_SOURCE . '/xml_classes.php';
-include LIVEDOC_SOURCE . '/style_mapping.php';
-include LIVEDOC_SOURCE . '/handlers.php';
-include LIVEDOC_SOURCE . '/themes/' . THEME_NAME . '/html_format.php';
-
+include LIVEDOC_SOURCE . '/livedoc_funcs.php';
$date = gmdate('Y-m-d H:i:s') . ' GMT';
if (isset($_GET['i'])) {
@@ -56,27 +51,35 @@
* Aliases and XML -> style mapping
* Please keep the arrays sorted by keys
*/
-$aliases = array(
- // For Smarty
- 'smarty.for.programmers' => 'smarty.constants',
- 'smarty.for.designers' => 'language.basic.syntax',
- 'api.functions' => 'handle_appendixes_funcref',
- 'language.custom.functions' => 'handle_appendixes_funcref',
- 'language.basic.syntax' => 'handle_appendixes_funcref',
- 'language.variables' => 'handle_appendixes_funcref',
- // For PHPdoc
- 'api' => 'streams',
- 'appendixes' => 'handle_appendixes_funcref',
- 'faq' => 'faq.general',
- 'features' => 'features.http-auth',
- 'funcref' => 'handle_appendixes_funcref',
- 'getting-started' => 'introduction',
- 'installation' => 'install.general',
- 'langref' => 'language.basic-syntax',
- 'manual' => 'handle_contents',
- 'security' => 'security.index',
- 'indexes' => 'handle_index'
-);
+
+if (BUILD_TYPE == 'smarty') {
+ $aliases = array(
+ // For Smarty
+ 'smarty.for.programmers' => 'smarty.constants',
+ 'smarty.for.designers' => 'language.basic.syntax',
+ 'api.functions' => 'handle_appendixes_funcref',
+ 'language.custom.functions' => 'handle_appendixes_funcref',
+ 'language.basic.syntax' => 'handle_appendixes_funcref',
+ 'language.variables' => 'handle_appendixes_funcref',
+ );
+} elseif (BUILD_TYPE == 'phpdoc') {
+ $aliases = array(
+ // For PHPdoc
+ 'api' => 'streams',
+ 'appendixes' => 'handle_appendixes_funcref',
+ 'faq' => 'faq.general',
+ 'features' => 'features.http-auth',
+ 'funcref' => 'handle_appendixes_funcref',
+ 'getting-started' => 'introduction',
+ 'installation' => 'install.general',
+ 'langref' => 'language.basic-syntax',
+ 'manual' => 'handle_contents',
+ 'security' => 'security.index',
+ 'indexes' => 'handle_index'
+ );
+} else {
+ $aliases = array();
+}
/*****************************************************************************
* Handle some special pages in a special way with special code
@@ -158,393 +161,6 @@
fwrite($f, $contents);
fclose($f);
echo $contents;
-}
-
-return;
-
-/*****************************************************************************
- * Helper functions for navigation
- */
-function do_nav($idx, $fb_idx, $lang, $current_page, &$nav, &$children)
-{
-
- $nav = "<table class='nav' border='0' cellpadding='0' cellspacing='0'
width='150'>";
-
- /* Get the fileinfo for the reference */
- $tr = sqlite_array_query($idx, "SELECT title, filename, idents.fileid,
files.dirid from idents, files where id='$current_page' and
idents.fileid=files.fileid", SQLITE_NUM);
- if (!$tr) {
- $tr = sqlite_array_query($fb_idx, "SELECT title, filename,
idents.fileid, files.dirid from idents, files where id='$current_page' and
idents.fileid=files.fileid", SQLITE_NUM);
- }
- list($title, $filename, $fileid, $dirid) = $tr;
-
- /* Get parent ID and child IDs */
- /* - first we get the first three parts of the path */
- if (($r = sqlite_single_query($idx, "SELECT path FROM toc WHERE docbook_id =
'$current_page' LIMIT 1", SQLITE_NUM))) {
- $path = explode(",", $r);
- foreach ($path as $item) {
- $nav .= do_nav_line($item, 'up', $current_page, $lang, $dummy);
- }
- $last_item = $item;
- } else {
- $nav .= do_nav_line('manual', 'up', $current_page, $lang, $dummy);
- $last_item = 'manual';
- }
-
- /* With $last_item we're going to show all brothers */
- $r = (array) sqlite_single_query($idx, "SELECT docbook_id FROM toc WHERE
parent_docbook_id = '$last_item' ORDER BY id");
- foreach ($r as $val) {
- $nav .= do_nav_line($val, 'down', $current_page, $lang, $dummy);
- }
-
- $children = array();
- /* And finally all children, but only if $current_page != $last_item
- * because showing the same thing twice makes no sense */
- $r = (array) sqlite_single_query($idx, "SELECT docbook_id FROM toc WHERE
parent_docbook_id = '$current_page' AND parent_docbook_id <> 'manual' ORDER BY id");
- foreach ($r as $val) {
- $nav .= do_nav_line($val, 'downdown', $current_page, $lang, $title);
- $children[$val] = $title;
- }
-
- $nav .= "</table>\n";
- return $tr;
-}
-
-
-function generate_url_for_id($lang, $ref)
-{
- static $cache = array();
-
- if (isset($cache[$lang][$ref])) {
- return $cache[$lang][$ref];
- }
-
- /* first determine the file in which the node can be found */
- $fileid = null;
- $firstid = $ref;
-
- $saferef = sqlite_escape_string($ref);
-
- if (($fileid = sqlite_single_query($GLOBALS['idx'], "SELECT fileid from idents
where id='$saferef'"))) {
- $idx = $GLOBALS['idx'];
- } else if (isset($GLOBALS['fb_idx']) && ($fileid =
sqlite_single_query($GLOBALS['fb_idx'], "SELECT fileid from idents where
id='$saferef'"))) {
- $idx = $GLOBALS['fb_idx'];
- }
-
- if (!$fileid) { /* determine the first node within that file */
- $firstid = sqlite_single_query($idx, "SELECT id from idents where
fileid='$fileid' LIMIT 1");
- }
-
- if ($firstid != $ref) {
- $hash = "#$ref";
- } else {
- $hash = "";
- }
-
- if ($firstid == 'manual') {
- $firstid = $ref;
- $hash = '';
- }
-
- if (FORCE_DYNAMIC) {
- $url = "{$_SERVER['PHP_SELF']}?l=$lang&q=$firstid$hash";
- } else {
- $url = WEBBASE . "$lang/$firstid.html$hash";
- }
-
- $cache[$lang][$ref] = $url;
- return $url;
-}
-
-function do_nav_line($item, $class, $current_page, $lang, &$fulltitle) {
- global $current_page_title;
-
- $nolink = FALSE;
-
- $title = lookup_title($item);
- $fulltitle = $title;
- if (strlen($title) > 25) {
- $ftitle = " title='$title'";
- $title = substr($title, 0, 22). '...';
- } else {
- $ftitle = "";
- if (!$title) {
- $title = $item . ' [?]';
- $nolink = TRUE;
- }
- }
-
- if ($item == $current_page) {
- $current_page_title = $title;
- $title = "<b>$title</b>";
- }
- $title = str_replace(' ', ' ', $title);
-
- if ($nolink) {
- return "<tr><td class='$class'>$title</td></tr>\n";
- } else {
- $url = generate_url_for_id($lang, $item);
- return "<tr><td class='$class'><a $ftitle class='$class'
href='$url'>$title</a></td></tr>\n";
- }
-}
-
-/*****************************************************************************
- * Search & Replace entities
- */
-function bind_entities($data) {
-
- global $idx;
- $sanity = 0;
-
- while (($ent_count = preg_match_all('/&([a-zA-Z0-9.-]+);/sm', $data,
$matches)) && $sanity++ < 5) {
- /* now collect their values */
- $ents = implode("','", array_unique($matches[1]));
- $r = sqlite_array_query($idx, "SELECT entid, value from ents where
entid in ('" . $ents . "')", SQLITE_NUM);
- if ($r) {
- $src = $dst = array();
- foreach ($r as $v) {
- $src[] = '&' . $v[0] . ';';
- $dst[] = $v[1];
- }
- /* substitute */
- $data = str_replace($src, $dst, $data);
- } else {
- /* no matching entities, no point in looping further */
- break;
- }
- }
-
- return $data;
-}
-
-
-/*****************************************************************************
- * Helper functions for transformation
- */
-function &load_xml_doc($filename, $included = false, $fallback_filename = '',
$return_rev = 0)
-{
- global $file_revision, $idx, $lang;
-
- $replace = array();
- $search = array('æ', '©', 'é', 'è', 'à',
'ï', 'ö', 'ä', 'Ä',
- 'ô', 'ê', 'û', 'î', 'â', 'ë',
'ç', 'ù');
- foreach ($search as $item) {
- $replace[] = html_entity_decode($item);
- }
-
- $lang_rev = 0;
-
- $data = @file_get_contents($filename);
- if (strlen($data) == 0 && strlen($fallback_filename)) {
- $data = @file_get_contents($fallback_filename);
-
- if (strlen($data) == 0) {
- $data = "<warning>permissions problem for
$filename?</warning>";
- }
-
- } elseif ($lang != 'en' && preg_match('/<!-- EN-Revision: \d+\.(\d+)/', $data,
$matches)) {
- $lang_rev = $matches[1];
- }
-
- /* get file revision */
- if (empty($file_revision) && preg_match('/\$' . 'Revision: [^$]+ \$/', $data,
$matches)) {
- $file_revision .= $matches[0];
- }
-
- /* strip comments */
- $data = preg_replace('@<!--\s+.*\s-->@Usm', '', $data);
-
- /* Replace entities */
- $data = bind_entities($data);
-
- /* catch any undefined entities */
- if ($included) {
- if (basename($filename) == 'functions.xml') {
- $data =
preg_replace('/&([a-zA-Z0-9-]+)\.([a-zA-Z0-9.-]+);/sme',
'make_function_link("\\1.\\2");', $data);
- } else {
- $data =
preg_replace('/&([a-zA-Z0-9-]+)\.([a-zA-Z0-9.-]+);/sme', 'make_xref("\\1.\\2");',
$data);
- }
- if (!$data || $data{1} != '?') {
- $data = '<div>' . $data . '</div>';
- } else {
- $data = preg_replace('@(<\\?xml.*\\?>)@U', '\\1<div>', $data)
. '</div>';
- }
- } else {
- $data = preg_replace('/&([a-zA-Z0-9-]+)\.([a-zA-Z0-9.-]+);/sm',
'<phpdoc_include ref="\\1.\\2"/>', $data);
- }
-
- $data = str_replace($search, $replace, $data);
-
- $page = new DocBookToHTML($data);
-
-
- if ($return_rev) {
- return array($page, $lang_rev);
- } else {
- return $page;
- }
-}
-
-function format_user_notes($id)
-{
- $notes = sqlite_array_query($GLOBALS['NOTESDB'], "SELECT id, xwhen, who, note
from notes where sect='$id' order by xwhen desc");
- if (count($notes) == 0)
- return '';
-
- $inner = <<<HTML
-<div class="usernotes">
- <span class="title">User Contributed Notes</span>
-HTML;
-
- foreach ($notes as $note) {
- $date = date("d-M-Y h:i", $note['xwhen']);
-
- $node = new stdClass;
- $node->content = $note['note'];
- $node->attributes['role'] = 'php';
- $the_note = format_listing($node);
-
- $inner .= <<<HTML
-<div class="usernote">
- <div class="noteheader">
- <span class="user">$note[who]</span><br />
- <span class="when">$date</span>
- </div>
- $the_note
-</div>
-HTML;
- }
-
- return $inner . "</div>";
-}
-
-function lookup_title($nodeid)
-{
- static $ids = array();
-
- /* Define your own title mappings here: */
- static $special = array ('indexes' => 'FunctionIndex');
-
- /* we're going to do some tricky stuff here for languages,
- * by using entities as much as possible */
- if (isset($special[$nodeid])) {
- /* Check for the entity value */
- if (($r = sqlite_single_query($GLOBALS['idx'], "SELECT entid FROM ents
WHERE entid = '$special[$nodeid]'"))) {
- return $r;
- } else { /* It's not an entity, let's just return it then */
- return $special[$nodeid];
- }
- }
-
- /* See if the title lookup is in the cache already */
- if (isset($ids[$nodeid])) {
- return $ids[$nodeid];
- }
-
- /* It's not, so we try to resolve it from the DB */
- $safeid = sqlite_escape_string($nodeid);
- if (($ids[$nodeid] = sqlite_single_query($GLOBALS['idx'], "SELECT title from
idents where id='$safeid'"))) {
- return $ids[$nodeid];
- } else if (isset($GLOBALS['fb_idx']) && ($ids[$nodeid] =
sqlite_single_query($GLOBALS['fb_idx'], "SELECT title from idents where
id='$safeid'"))) {
- return $ids[$nodeid];
- }
- return null;
-}
-
-/* transform an entity name of the form "reference.XXXX.functions.ID"
- * and generate a link to its node using its title */
-function make_function_link($ref)
-{
- $parts = explode('.', $ref);
-
- $stag = 'function';
- $etag = 'function';
-
- switch (count($parts)) {
- case 4:
- $id = 'function.' . $parts[3];
- $func_name = lookup_title($id);
- break;
-
- case 5:
- if ($parts[3] == 'class') {
- $id = 'class.' . $parts[4];
- $func_name = str_replace('-', '_', $parts[4]);
- $stag = "xref linkend=\"$id\"";
- $etag = "xref";
- break;
- }
- /* fall through */
-
- default:
- /* some weird node type we don't understand */
- $id = $ref;
- $func_name = 'Unknown ??';
- }
-
- if ($parts[3] == 'class') {
- $title = ' - ' . lookup_title($id) . ' class';
- } else {
- $title = ' - ' . bind_entities(sqlite_single_query($GLOBALS['idx'],
"SELECT descr from toc where docbook_id='$id'"));
- }
-
- return "<div class=\"function_link\"><$stag>$func_name</$etag>$title</div>";
-}
-
-function make_xref($ref)
-{
- $parts = explode('.', $ref);
- if ($parts[0] == 'reference' && $parts[2] == 'functions') {
- $id = 'function.'. $parts[3];
- }
- $title = lookup_title($id);
- if (!$title) {
- $title = $id. ' [?]';
- }
- return "<xref linkend=\"$id\">$title</xref>";
-}
-
-function do_contents($id, $level)
-{
- global $lang;
-
- if (($r = sqlite_array_query($GLOBALS['idx'], "SELECT id, docbook_id FROM toc
WHERE parent_id = ".$id, SQLITE_NUM))) {
- foreach($r as $row) {
- $ret .= "<li>";
-
- if (!($title = lookup_title($row[1]))) {
- $ret .= $row[1]. ' [?]';
- } else {
- $ret .= "<a href='".generate_url_for_id($lang,
$row[1])."'>".$title."</a>";
- }
-
- if (($level < 2 && strcmp($row[1], 'ref')) || $level < 1) {
- $ret .= do_contents($row[0], $level + 1);
- }
- $ret .= "</li>\n";
- }
-
- return "<ul>" . $ret . "</ul>\n";
- }
-
- return '';
-}
-
-function handle_include($node)
-{
- $filename = BASE . strtr($node->attributes['ref'], '.', '/') . '.xml';
- $fallback_filename = FALLBACK_BASE . strtr($node->attributes['ref'], '.', '/')
. '.xml';
-
- $doc = load_xml_doc($filename, true, $fallback_filename);
- return $doc->transform($GLOBALS['map']);
-}
-
-// Handle the case where a requested node id was not found
-function handle_missing_index()
-{
- global $current_page, $lang;
-
- header('Location: ' . WEBBASE . 'search.php?q=' . urlencode($current_page) .
'&l=' . $lang);
- exit;
}
?>
http://cvs.php.net/diff.php/livedocs/mkindex.php?r1=1.34&r2=1.35&ty=u
Index: livedocs/mkindex.php
diff -u livedocs/mkindex.php:1.34 livedocs/mkindex.php:1.35
--- livedocs/mkindex.php:1.34 Mon May 24 08:18:48 2004
+++ livedocs/mkindex.php Tue May 25 07:33:48 2004
@@ -19,7 +19,7 @@
// | construct an index |
// +----------------------------------------------------------------------+
//
-// $Id: mkindex.php,v 1.34 2004/05/24 12:18:48 wez Exp $
+// $Id: mkindex.php,v 1.35 2004/05/25 11:33:48 wez Exp $
/* just to be on the safe side */
@@ -212,7 +212,7 @@
if (!isset($replacements[$matches[1][$i]])) {
$id = sqlite_escape_string($matches[1][$i]);
$value = sqlite_escape_string($matches[2][$i]);
- $strsql = "INSERT INTO ents VALUES ('$id',
'$value')";
+ $strsql = "INSERT INTO ents VALUES ('$id',
'$value', 0)";
@sqlite_query($idx, $strsql);
// echo $strsql . "\n"; // for debuging
@@ -220,6 +220,34 @@
}
}
}
+
+ $x =
preg_match_all('/<!ENTITY\s+([a-zA-Z0-9.-]+)\s+SYSTEM\s+\'([^\']+)\'>/Usm', $d,
$matches);
+ $docs = $GLOBALS['DOCS'] . DIRECTORY_SEPARATOR;
+ $docslen = strlen($docs);
+ $realdocs = realpath($docs) . DIRECTORY_SEPARATOR;
+ $reallen = strlen($realdocs);
+ $lang = $GLOBALS['LANG'] . DIRECTORY_SEPARATOR;
+ $langlen = strlen($lang);
+ for ($i = 0; $i < $x; $i++) {
+ $id = sqlite_escape_string($matches[1][$i]);
+ $value = sqlite_escape_string($matches[2][$i]);
+ echo "value: $value\ndocs: $docs\nreal: $realdocs\nlang:
$lang\n";
+ if (strncmp($value, $docs, $docslen) == 0) {
+ $value = substr($value, $docslen);
+ $check_lang = true;
+ } else if (strncmp($value, $realdocs, $reallen) == 0) {
+ $value = substr($value, $reallen);
+ $check_lang = true;
+ } else {
+ $check_lang = true;
+ }
+
+ if ($check_lang && strncmp($value, $lang, $langlen) == 0) {
+ $value = substr($value, $langlen);
+ }
+ echo " ---> $value\n";
+ @sqlite_query($idx, "INSERT INTO ents VALUES ('$id', '$value',
1)");
+ }
}
return $replacements;
}
@@ -306,7 +334,8 @@
CREATE TABLE ents (
entid TEXT PRIMARY KEY,
- value TEXT
+ value TEXT,
+ is_file INTEGER default 0
);
CREATE TABLE funcs (
@@ -324,6 +353,9 @@
title TEXT,
descr TEXT
);
+CREATE INDEX toc_parent_idx on toc(parent_id);
+CREATE INDEX toc_docbook_id_idx on toc(docbook_id);
+CREATE INDEX toc_parent_docbook_id_idx on toc(parent_docbook_id);
CREATE TABLE searchi (
skey VARCHAR(230),
http://cvs.php.net/diff.php/livedocs/themes/default/html_format.php?r1=1.10&r2=1.11&ty=u
Index: livedocs/themes/default/html_format.php
diff -u livedocs/themes/default/html_format.php:1.10
livedocs/themes/default/html_format.php:1.11
--- livedocs/themes/default/html_format.php:1.10 Mon May 24 08:43:25 2004
+++ livedocs/themes/default/html_format.php Tue May 25 07:33:48 2004
@@ -18,7 +18,7 @@
// | headers and footers for the HTML rendering |
// +----------------------------------------------------------------------+
//
-// $Id: html_format.php,v 1.10 2004/05/24 12:43:25 wez Exp $
+// $Id: html_format.php,v 1.11 2004/05/25 11:33:48 wez Exp $
// in livedoc.php
@@ -32,7 +32,7 @@
"http://www.w3.org/TR/html4/loose.dtd">
<html lang="$lang">
<head>
-<meta http-equiv="Content-Type" content="text/html; charset="$charset"/>
+<meta http-equiv="Content-Type" content="text/html; charset=$charset"/>
<title>$title</title>
<link rel="stylesheet" href="$css_url" />
</head>
http://cvs.php.net/co.php/livedocs/livedoc_funcs.php?r=1.1&p=1
Index: livedocs/livedoc_funcs.php
+++ livedocs/livedoc_funcs.php
<?php
include LIVEDOC_SOURCE . '/common.php';
if (version_compare(phpversion(), "5", "ge")) {
include LIVEDOC_SOURCE . '/xml_classes5.php';
} else {
include LIVEDOC_SOURCE . '/xml_classes.php';
}
include LIVEDOC_SOURCE . '/style_mapping.php';
include LIVEDOC_SOURCE . '/handlers.php';
include LIVEDOC_SOURCE . '/themes/' . THEME_NAME . '/html_format.php';
/*****************************************************************************
* Helper functions for navigation
*/
function do_nav($idx, $fb_idx, $lang, $current_page, &$nav, &$children)
{
$children = array();
$nav = "<table class='nav' border='0' cellpadding='0' cellspacing='0'
width='150'>";
/* Get the fileinfo for the reference */
list($tr) = sqlite_array_query($idx, "SELECT title, filename, idents.fileid,
files.dirid from idents left join files where id='$current_page' and
idents.fileid=files.fileid", SQLITE_NUM);
if (!$tr) {
list($tr) = sqlite_array_query($fb_idx, "SELECT title, filename,
idents.fileid, files.dirid from idents left join files where id='$current_page' and
idents.fileid=files.fileid", SQLITE_NUM);
}
if ($tr) {
list($title, $filename, $fileid, $dirid) = $tr;
}
/* Get parent ID and child IDs */
/* - first we get the first three parts of the path */
$last_item = 'manual';
if (($r = sqlite_single_query($idx, "SELECT path FROM toc WHERE docbook_id =
'$current_page' LIMIT 1", SQLITE_NUM))) {
$path = explode(",", $r);
foreach ($path as $item) {
$nav .= do_nav_line($item, 'up', $current_page, $lang, $dummy);
$last_item = $item;
}
} else {
$nav .= do_nav_line('manual', 'up', $current_page, $lang, $dummy);
}
/* With $last_item we're going to show all brothers */
$r = (array) sqlite_single_query($idx, "SELECT docbook_id FROM toc WHERE
parent_docbook_id = '$last_item' ORDER BY id");
foreach ($r as $val) {
$nav .= do_nav_line($val, 'down', $current_page, $lang, $dummy);
}
/* And finally all children, but only if $current_page != $last_item
* because showing the same thing twice makes no sense */
if ($current_page != $last_item && $current_page != 'manual') {
$r = (array) sqlite_single_query($idx, "SELECT docbook_id FROM toc
WHERE parent_docbook_id = '$current_page' ORDER BY id");
foreach ($r as $val) {
$nav .= do_nav_line($val, 'downdown', $current_page, $lang,
$title);
$children[$val] = $title;
}
}
$nav .= "</table>\n";
return $tr;
}
function generate_url_for_id($lang, $ref)
{
static $cache = array();
if (isset($cache[$lang][$ref])) {
return $cache[$lang][$ref];
}
/* first determine the file in which the node can be found */
$fileid = null;
$firstid = $ref;
$saferef = sqlite_escape_string($ref);
$fileid = sqlite_single_query($GLOBALS['idx'], "SELECT fileid from idents
where id='$saferef'");
if ($fileid) {
$index = $GLOBALS['idx'];
} else {
$fileid = sqlite_single_query($GLOBALS['fb_idx'], "SELECT fileid from
idents where id='$saferef'");
if ($fileid) {
$index = $GLOBALS['fb_idx'];
} else {
$index = null;
}
}
if ($fileid !== null && $index !== null) {
/* determine the first node within that file */
$firstid = sqlite_single_query($index, "SELECT id from idents where
fileid='$fileid' LIMIT 1");
}
if ($firstid != $ref) {
$hash = "#$ref";
} else {
$hash = "";
}
if ($firstid == 'manual') {
$firstid = $ref;
$hash = '';
}
if (FORCE_DYNAMIC) {
$url = "{$_SERVER['PHP_SELF']}?l=$lang&q=$firstid$hash";
} else {
$url = WEBBASE . "$lang/$firstid.html$hash";
}
$cache[$lang][$ref] = $url;
return $url;
}
function do_nav_line($item, $class, $current_page, $lang, &$fulltitle) {
global $current_page_title;
$nolink = FALSE;
$title = lookup_title($item);
$fulltitle = $title;
if (strlen($title) > 25) {
$ftitle = " title='$title'";
$title = substr($title, 0, 22). '...';
} else {
$ftitle = "";
if (!$title) {
$title = $item . ' [?]';
$nolink = TRUE;
}
}
if ($item == $current_page) {
$current_page_title = $title;
$title = "<b>$title</b>";
}
$title = str_replace(' ', ' ', $title);
if ($nolink) {
return "<tr><td class='$class'>$title</td></tr>\n";
} else {
$url = generate_url_for_id($lang, $item);
return "<tr><td class='$class'><a $ftitle class='$class'
href='$url'>$title</a></td></tr>\n";
}
}
/*****************************************************************************
* Search & Replace entities
*/
function bind_entities($data) {
global $idx;
static $entity_cache = array();
$entities = array();
$sanity = 0;
while (($ent_count = preg_match_all('/&([a-zA-Z0-9.-]+);/sm', $data,
$matches)) && $sanity++ < 5) {
/* now collect their values */
$entities_to_find = array_unique($matches[1]);
foreach ($entities_to_find as $ent) {
if (isset($entity_cache[$ent])) {
$entities['&' . $ent . ';'] = $entity_cache[$ent];
unset($entities_to_find[$ent]);
}
}
if (count($entities_to_find)) {
$ents = implode("','", $entities_to_find);
$q = sqlite_query($idx, "SELECT entid, value from ents where
is_file=0 and entid in ('" . $ents . "')");
if ($q) {
while ($r = sqlite_fetch_array($q, SQLITE_NUM)) {
$entities['&' . $r[0] . ';'] = $r[1];
$entities_cache[$r[0]] = $r[1];
}
}
}
if (!count($entities))
break;
/* substitute */
$data = strtr($data, $entities);
} while ($sanity++ < 5);
return $data;
}
/*****************************************************************************
* Helper functions for transformation
*/
function load_xml_doc($filename, $included = false, $fallback_filename = '',
$return_rev = 0)
{
global $file_revision, $idx, $lang;
$replace = array();
$search = array('æ', '©', 'é', 'è', 'à',
'ï', 'ö', 'ä', 'Ä',
'ô', 'ê', 'û', 'î', 'â', 'ë',
'ç', 'ù');
foreach ($search as $item) {
$replace[] = html_entity_decode($item);
}
$lang_rev = 0;
$data = @file_get_contents($filename);
if (strlen($data) == 0 && strlen($fallback_filename)) {
$data = @file_get_contents($fallback_filename);
if (strlen($data) == 0) {
$data = "<warning>permissions problem for
$filename?</warning>";
}
} elseif ($lang != 'en' && preg_match('/<!-- EN-Revision: \d+\.(\d+)/', $data,
$matches)) {
$lang_rev = $matches[1];
}
/* get file revision */
if (empty($file_revision) && preg_match('/\$' . 'Revision: [^$]+ \$/', $data,
$matches)) {
$file_revision .= $matches[0];
}
/* strip comments */
$data = preg_replace('@<!--\s+.*\s-->@Usm', '', $data);
/* Replace entities */
$data = bind_entities($data);
/* catch any undefined entities */
if ($included) {
if (basename($filename) == 'functions.xml') {
$data =
preg_replace('/&([a-zA-Z0-9-]+)\.([a-zA-Z0-9.-]+);/sme',
'make_function_link("\\1.\\2");', $data);
} else {
$data =
preg_replace('/&([a-zA-Z0-9-]+)\.([a-zA-Z0-9.-]+);/sme', 'make_xref("\\1.\\2");',
$data);
}
if (!$data || $data{1} != '?') {
$data = '<div>' . $data . '</div>';
} else {
$data = preg_replace('@(<\\?xml.*\\?>)@U', '\\1<div>', $data)
. '</div>';
}
} else {
$data = preg_replace('/&([a-zA-Z0-9-]+)\.([a-zA-Z0-9.-]+);/sm',
'<phpdoc_include ref="\\1.\\2"/>', $data);
}
$data = str_replace($search, $replace, $data);
$page = new DocBookToHTML($data);
if ($return_rev) {
return array($page, $lang_rev);
} else {
return $page;
}
}
function format_user_notes($id)
{
$notes = sqlite_array_query($GLOBALS['NOTESDB'], "SELECT id, xwhen, who, note
from notes where sect='$id' order by xwhen desc");
if (count($notes) == 0)
return '';
$inner = <<<HTML
<div class="usernotes">
<span class="title">User Contributed Notes</span>
HTML;
foreach ($notes as $note) {
$date = date("d-M-Y h:i", $note['xwhen']);
$node = new stdClass;
$node->content = $note['note'];
$node->attributes['role'] = 'php';
$the_note = format_listing($node);
$inner .= <<<HTML
<div class="usernote">
<div class="noteheader">
<span class="user">$note[who]</span><br />
<span class="when">$date</span>
</div>
$the_note
</div>
HTML;
}
return $inner . "</div>";
}
function lookup_title($nodeid)
{
static $ids = array();
/* Define your own title mappings here: */
static $special = array ('indexes' => 'FunctionIndex');
/* we're going to do some tricky stuff here for languages,
* by using entities as much as possible */
if (isset($special[$nodeid])) {
/* Check for the entity value */
if (($r = sqlite_single_query($GLOBALS['idx'], "SELECT entid FROM ents
WHERE entid = '$special[$nodeid]'"))) {
return $r;
} else { /* It's not an entity, let's just return it then */
return $special[$nodeid];
}
}
/* See if the title lookup is in the cache already */
if (isset($ids[$nodeid])) {
return $ids[$nodeid];
}
/* It's not, so we try to resolve it from the DB */
$safeid = sqlite_escape_string($nodeid);
if (($ids[$nodeid] = sqlite_single_query($GLOBALS['idx'], "SELECT title from
idents where id='$safeid'"))) {
return $ids[$nodeid];
} else if (isset($GLOBALS['fb_idx']) && ($ids[$nodeid] =
sqlite_single_query($GLOBALS['fb_idx'], "SELECT title from idents where
id='$safeid'"))) {
return $ids[$nodeid];
}
return null;
}
/* transform an entity name of the form "reference.XXXX.functions.ID"
* and generate a link to its node using its title */
function make_function_link($ref)
{
$parts = explode('.', $ref);
$stag = 'function';
$etag = 'function';
switch (count($parts)) {
case 4:
$id = 'function.' . $parts[3];
$func_name = lookup_title($id);
break;
case 5:
if ($parts[3] == 'class') {
$id = 'class.' . $parts[4];
$func_name = str_replace('-', '_', $parts[4]);
$stag = "xref linkend=\"$id\"";
$etag = "xref";
break;
}
/* fall through */
default:
/* some weird node type we don't understand */
$id = $ref;
$func_name = 'Unknown ??';
}
if ($parts[3] == 'class') {
$title = ' - ' . lookup_title($id) . ' class';
} else {
$title = ' - ' . bind_entities(sqlite_single_query($GLOBALS['idx'],
"SELECT descr from toc where docbook_id='$id'"));
}
return "<div class=\"function_link\"><$stag>$func_name</$etag>$title</div>";
}
function make_xref($ref)
{
$parts = explode('.', $ref);
if ($parts[0] == 'reference' && $parts[2] == 'functions') {
$id = 'function.'. $parts[3];
} else {
$id = $ref;
}
$title = lookup_title($id);
if (!$title) {
$title = $id. ' [?]';
}
return "<xref linkend=\"$id\">$title</xref>";
}
function do_contents($id, $level)
{
global $lang;
$ret = '';
if (($r = sqlite_array_query($GLOBALS['idx'], "SELECT id, docbook_id FROM toc
WHERE parent_id = ".$id, SQLITE_NUM))) {
foreach($r as $row) {
$ret .= "<li>";
if (!($title = lookup_title($row[1]))) {
$ret .= $row[1]. ' [?]';
} else {
$ret .= "<a href='".generate_url_for_id($lang,
$row[1])."'>".$title."</a>";
}
if (($level < 2 && strncmp($row[1], 'ref', 3)) || $level < 1)
{
$ret .= do_contents($row[0], $level + 1);
}
$ret .= "</li>\n";
}
return "<ul>" . $ret . "</ul>\n";
}
return '';
}
function handle_include($node)
{
global $current_page;
$ref = $node->attributes['ref'];
$curr_lvl = sqlite_single_query($GLOBALS['idx'], "SELECT lvl from toc where
docbook_id='$current_page'");
list($row) = sqlite_array_query($GLOBALS['idx'], "SELECT idents.id, lvl from
ents left join files on ents.value = files.filename left join idents on files.fileid =
idents.fileid left join toc on ents.entid=toc.docbook_id where is_file=1 and
ents.entid='$ref' limit 1");
list($id, $lvl) = $row;
$filename = sqlite_single_query($GLOBALS['idx'], "SELECT value from ents where
entid='$ref' and is_file=1");
$path = PHPDOC . DIRECTORY_SEPARATOR . $filename;
if (!file_exists($path)) {
$path = PHPDOC . DIRECTORY_SEPARATOR . $GLOBALS['lang'] .
DIRECTORY_SEPARATOR . $filename;
}
if ($lvl > $curr_lvl) {
$fake->content = null;
$fake->attributes['linkend'] = $id;
$fake->tagname = 'xref';
return format_link($fake) . " [$ref, $id, $lvl vs $curr_lvl]<br />";
}
$doc = load_xml_doc($path, true, null);
return "<!-- $ref : $filename -->" . $doc->transform($GLOBALS['map']);
}
// Handle the case where a requested node id was not found
function handle_missing_index()
{
global $current_page, $lang;
header('Location: ' . WEBBASE . 'search.php?q=' . urlencode($current_page) .
'&l=' . $lang);
exit;
}
?>
http://cvs.php.net/co.php/livedocs/pregenerate.php?r=1.1&p=1
Index: livedocs/pregenerate.php
+++ livedocs/pregenerate.php
<?php
/* walk the index and spit out an html page for each item.
* Could be modified to spit out .chm bits too.
* Unfortunately, PHP 4 and reference assignments leak MASSIVE
* amounts of memory if we run the whole thing in a single process.
* So, only run this with PHP 5 if you value your RAM!
*/
define('LIVEDOC_SOURCE', dirname(__FILE__));
include LIVEDOC_SOURCE . '/livedoc_funcs.php';
$ids_and_pages = sqlite_query($idx, "select id, filename from idents left join files
on idents.fileid=files.fileid");
$last_file_name = null;
chdir(OUTPUTDIR);
ob_start();
$start_time = microtime(true);
$gen_time = 0;
$clean_time = 0;
$number_processed = 0;
$note_time = 0;
$nav_time = 0;
$load_time = 0;
while ($page_row = sqlite_fetch_array($ids_and_pages)) {
if ($last_file_name == $page_row[1])
continue;
$number_processed++;
$last_file_name = $page_row[1];
$current_page = $page_row[0];
fwrite(STDERR, "Generating $current_page\t"); fflush(STDERR);
$ts = microtime(true);
list($title, $filename, $fileid, $dirid) = do_nav($idx, $fb_idx, $lang,
$current_page, $nav, $children);
$tnav = microtime(true) - $ts;
$ts = microtime(true);
list($page, $lang_rev) = load_xml_doc(BASE . $filename, false, FALLBACK_BASE .
$filename, 1);
$tload = microtime(true) - $ts;
$load_time += $tload;
$nav_time += $tnav;
ob_clean();
echo manual_page_header();
$ts = microtime(true);
echo $page->transform($map, $current_page);
$tgen = microtime(true) - $ts;
$gen_time += $tgen;
if ($NOTESDB) {
$tn = microtime(true);
fwrite(STDERR, "[notes]\t"); fflush(STDERR);
echo format_user_notes($current_page);
$gen_note = microtime(true) - $tn;
$note_time += $gen_note;
} else {
$gen_note = 0;
}
if (empty($file_revision)) {
$file_revision = 'unknown revision';
}
echo manual_page_footer();
$contents = ob_get_contents();
ob_clean();
$save_file = $lang . "/" . $current_page . ".html";
fwrite(STDERR, "\t$save_file "); fflush(STDERR);
$f = fopen($save_file, 'w');
fwrite($f, $contents);
fclose($f);
fwrite(STDERR, "\n"); fflush(STDERR);
$ts = microtime(true);
$nodes = $__node_count;
/* try to release as much memory as possible */
$page = null;
unset($page);
unset($nav);
unset($children);
unset($current_page_title);
unset($dirid);
unset($fileid);
unset($filename);
unset($title);
unset($file_revision);
unset($contents);
unset($f);
unset($save_file);
$tclean = microtime(true) - $ts;
$clean_time += $tclean;
fprintf(STDERR, "nav %.2fs, load %.2fs, gen %.2fs [note %.2fs], clean(%d) in
%.2fs\n\n",
$tnav, $tload,
$tgen, $gen_note, $nodes, $tclean);
if ($__node_count > 0) {
fwrite(STDERR, "nodes: $__node_count\n"); fflush(STDERR);
}
}
$elapsed = microtime(true) - $start_time;
fprintf(STDERR, "\nProcessed %d pages.\n\nOverall: %.2fs (%.2fs
each)\nGeneration: %.2fs (%.2fs each)\nCleaning: %.2fs (%.2fs each)\nNotes:
%.2fs (%.2fs each)\nNav: %.2fs (%.2fs each)\nLoad: %.2fs (%.2fs each)\n\n",
$number_processed,
$elapsed, $elapsed / $number_processed,
$gen_time, $gen_time / $number_processed,
$clean_time, $clean_time / $number_processed,
$nav_time, $nav_time / $number_processed,
$load_time, $load_time / $number_processed,
$note_time, $note_time / $number_processed
);
?>
http://cvs.php.net/co.php/livedocs/xml_classes5.php?r=1.1&p=1
Index: livedocs/xml_classes5.php
+++ livedocs/xml_classes5.php
<?php
/* vim: set tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2004 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 3.0 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available through the world-wide-web at the following url: |
// | http://www.php.net/license/3_0.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | [EMAIL PROTECTED] so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Wez Furlong, Derick Rethans, Ilia Alshanetsky |
// +----------------------------------------------------------------------+
// | Two XML handling classes for the docbook to html transformation, |
// | PHP 5 style |
// +----------------------------------------------------------------------+
//
// $Id: xml_classes5.php,v 1.1 2004/05/25 11:33:48 wez Exp $
class Node { /* {{{ */
var $tagname = "";
var $attributes = array();
var $children = array();
var $parent = null;
var $index = 0;
var $content = "";
var $nodeid = 0;
function transform($map)
{
if (strlen($this->tagname) == 0) {
return htmlspecialchars($this->content, ENT_NOQUOTES);
}
$tagname = 'div';
$attributes = $this->attributes;
$attributes['class'] = $this->tagname;
/* do we match any of the patterns in the map ? */
foreach ($map as $mapent) {
if ($mapent[0][0] == $this->tagname) {
$n = $this->parent;
$match = true;
for ($i = 1; $i < count($mapent[0]); $i++) {
if ($n->tagname != $mapent[0][$i]) {
$match = false;
break;
}
$n = $n->parent;
}
if ($match) {
if (is_callable($mapent[1])) {
return call_user_func($mapent[1],
$this);
} else {
$tagname = $mapent[1];
}
}
}
}
if (isset($this->attributes['id'])) {
$anchor = sprintf('<a name="%s"></a>',
$this->attributes['id']);
} else {
$anchor = '';
}
if (strlen($tagname)) {
$xml = '<' . $tagname;
foreach ($attributes as $name => $value) {
$xml .= ' ' . $name . '="' . htmlspecialchars($value)
. '"';
}
} else {
$xml = '';
}
$content = "";
if (count($this->children) == 0) {
if (strlen($tagname) == 0) {
return '';
}
if (strlen($this->content)) {
$content = htmlspecialchars($this->content,
ENT_NOQUOTES);
}
} else {
for ($i = 0; $i < count($this->children); $i++) {
$child = $this->children[$i];
$content .= $child->transform($map);
}
}
if (strlen($tagname)) {
$xml .= '>';
}
if ($tagname == 'th' && strlen($content) == 0) {
$content = ' ';
}
$xml .= $anchor;
$xml .= $content;
if (strlen($tagname)) {
$xml .= '</' . $tagname . '>';
}
return $xml;
}
function select_node($id)
{
if (isset($this->attributes['id']) && $this->attributes['id'] == $id) {
return $node;
}
// look for children that match
for ($i = 0; $i < count($this->children); $i++) {
$x = $this->select_node($this->children[$i], $id);
if (is_object($x)) {
return $x;
}
}
return null;
}
function Node($tagname, $attributes)
{
static $nodeid = 0;
$this->nodeid = $nodeid++;
$this->tagname = $tagname;
$this->attributes = $attributes;
$GLOBALS['__node_count']++;
}
function set_parent($parent)
{
$this->parent = $parent;
$this->index = count($parent->children);
$parent->children[$this->index] = $this;
}
function compress()
{
if (count($this->children) == 1 && $this->children[0]->tagname == '') {
$this->content = $this->children[0]->content;
$this->children = array();
}
}
function as_xml()
{
if (strlen($this->tagname) == 0) {
return htmlspecialchars($this->content, ENT_NOQUOTES);
}
$xml = '<' . $this->tagname;
foreach ($this->attributes as $name => $value) {
$xml .= ' ' . $name . '="' . htmlspecialchars($value) . '"';
}
if (count($this->children) == 0) {
if (strlen($this->content) == 0) {
$xml .= '/>';
} else {
$xml .= '>' . htmlspecialchars($this->content,
ENT_NOQUOTES) . '</' . $this->tagname . '>';
}
} else {
$xml .= '>';
for ($i = 0; $i < count($this->children); $i++) {
$xml .= $this->children[$i]->as_xml();
}
$xml .= '</' . $this->tagname . '>';
}
return $xml;
}
function add_child($child)
{
if (count($this->children) == 0 && strlen($this->content)) {
if (strlen(trim($this->content)) > 0) {
// promote content to an anonymous cdata node
$node = new Node("", array());
$node->content = $this->content;
$node->set_parent($this);
}
$this->content = "";
}
$child->set_parent($this);
}
function add_cdata($data)
{
if (count($this->children) == 0) {
$this->content .= $data;
} else {
$node = new Node("", array());
$node->content = $data;
$this->add_child($node);
}
}
function __destruct() {
$GLOBALS['__node_count']--;
}
function release()
{
for ($i = 0; $i < count($this->children); $i++) {
if (is_object($this->children[$i])) {
$this->children[$i]->release();
}
}
for ($i = 0; $i < count($this->children); $i++) {
$this->children[$i] = null;
}
$this->parent = null;
}
}
/* }}} */
class DocBookToHTML { /* {{{ */
var $html = "";
var $top = null;
var $current = null;
function __destruct() {
if (is_object($this->top)) {
$this->top->release();
}
if (is_object($this->current)) {
$this->current->release();
}
$this->top = null;
unset($this->top);
$this->current = null;
unset($this->current);
}
function DocBookToHTML($xml, $id = null)
{
if (strlen($xml) == 0) {
return;
}
$p = xml_parser_create();
xml_set_object($p, $this);
xml_parser_set_option($p, XML_OPTION_CASE_FOLDING, 0);
xml_set_element_handler($p, 'start_elem', 'end_elem');
xml_set_character_data_handler($p, 'cdata');
if (!xml_parse($p, $xml, true)) {
printf("XML: %d:%d %s\n",
xml_get_current_line_number($p),
xml_get_current_column_number($p),
xml_error_string(xml_get_error_code($p))
);
$lines = explode("\n", $xml);
$l = xml_get_current_line_number($p);
echo "\nLine: $l is <b>" . htmlentities($lines[$l-1]) .
"</b><br />\n";
echo '<pre>';
echo htmlentities($xml);
echo '</pre>';
}
xml_parser_free($p);
if ($id !== null) {
$newtop = $this->top->select_node($id);
if (is_object($newtop)) {
$this->top = $newtop;
$this->top->parent = null;
}
}
}
/* apply a transformation map to content */
function transform($map)
{
/* pre-parse the map */
if (!is_object($this->top)) {
return "<div class=\"warning\">XML document contained no
data</div>";
}
$pmap = array();
foreach ($map as $pat => $rep) {
$h = array_reverse(explode('/', $pat));
$pmap[] = array($h, $rep);
}
return $this->top->transform($pmap);
}
/* returns structure as XML */
function as_xml()
{
return $this->_as_xml($this->top);
}
function _as_xml($node)
{
if (strlen($node->tagname) == 0) {
return htmlspecialchars($node->content, ENT_NOQUOTES);
}
$xml = '<' . $node->tagname;
foreach ($node->attributes as $name => $value) {
$xml .= ' ' . $name . '="' . htmlspecialchars($value) . '"';
}
if (count($node->children) == 0) {
if (strlen($node->content) == 0) {
$xml .= '/>';
} else {
$xml .= '>' . htmlspecialchars($node->content,
ENT_NOQUOTES) . '</' . $node->tagname . '>';
}
} else {
$xml .= '>';
for ($i = 0; $i < count($node->children); $i++) {
$xml .= $this->_as_xml($node->children[$i]);
}
$xml .= '</' . $node->tagname . '>';
}
return $xml . "<!-- {$node->nodeid} -->";
}
function start_elem($parser, $tagname, $attributes)
{
/* create a new node as a child of the current node */
$node = new Node($tagname, $attributes);
if ($this->top === null) {
/* set the top node */
$this->top = $node;
$this->current = $node;
} else {
/* child of current */
$this->current->add_child($node);
$this->current = $node;
}
}
function end_elem($parser, $tagname)
{
/* pop up to parent of the current node */
if ($this->current === null) {
return;
}
/* optimize the node; if it only contains a single cdata (anonymous)
node,
* compress that node into the content */
$this->current->compress();
$this->current = $this->current->parent;
}
function cdata($parser, $data)
{
$this->current->add_cdata($data);
}
}
/* }}} */
?>