1
0
mirror of https://github.com/php/phd.git synced 2026-03-23 22:52:05 +01:00
Files
archived-phd/phpdotnet/phd/Render.php
2024-10-20 13:34:46 +02:00

220 lines
7.1 KiB
PHP

<?php
namespace phpdotnet\phd;
class Render extends ObjectStorage
{
const CHUNK = 0x001;
const OPEN = 0x002;
const CLOSE = 0x004;
const STANDALONE = 0x008;
const INIT = 0x010;
const FINALIZE = 0x020;
const VERBOSE = 0x040;
private $STACK = array();
public function __construct() { /* {{{ */
} /* }}} */
public function notXPath($tag, $depth) { /* {{{ */
do {
if ((--$depth >= 0) && isset($tag[$this->STACK[$depth]])) {
$tag = $tag[$this->STACK[$depth]];
} else {
$tag = $tag[0];
}
} while (is_array($tag));
return $tag;
} /* }}} */
public function attach($obj, $inf = array()): void { /* {{{ */
if (!($obj instanceof Format)) {
throw new \InvalidArgumentException(
'All formats *MUST* inherit ' . __NAMESPACE__ . '\\Format'
);
}
$obj->notify(Render::STANDALONE, true);
parent::attach($obj, $inf);
} /* }}} */
public function execute(Reader $r) { /* {{{ */
ReaderKeeper::setReader($r);
foreach($this as $format) {
$format->notify(Render::INIT, true);
}
$lastdepth = -1;
while($r->read()) {
$type = $r->nodeType;
$open = false;
switch($type) {
case \XMLReader::ELEMENT: /* {{{ */
$open = true;
/* break intentionally omitted */
case \XMLReader::END_ELEMENT:
$name = $r->name;
$depth = $r->depth;
$attrs = array(
Reader::XMLNS_DOCBOOK => array(),
Reader::XMLNS_XML => array(),
);
if ($r->hasAttributes) {
$r->moveToFirstAttribute();
do {
$attrs[$r->namespaceURI ?: Reader::XMLNS_DOCBOOK][$r->localName] = $r->value;
} while ($r->moveToNextAttribute());
$r->moveToElement();
}
$innerXml = "";
if (
$open &&
(
$r->name === "type" ||
$r->name === "classsynopsis" ||
$r->name === "qandaset" ||
in_array($r->name, ["methodsynopsis", "constructorsynopsis", "destructorsynopsis"], true)
)
) {
$innerXml = $r->readInnerXml();
}
$props = array(
"empty" => $r->isEmptyElement,
"isChunk" => false,
"lang" => $r->xmlLang,
"ns" => $r->namespaceURI,
"sibling" => $lastdepth >= $depth ? $this->STACK[$depth] : "",
"innerXml" => $innerXml,
"depth" => $depth,
);
$this->STACK[$depth] = $name;
if ($name == "notatag")
break;
foreach($this as $format) {
$map = $this[$format][\XMLReader::ELEMENT];
if (isset($map[$name]) === false) {
$data = $format->UNDEF($open, $name, $attrs, $props);
$format->appendData($data);
continue;
}
$tag = $map[$name];
if (is_array($tag)) {
$tag = $this->notXPath($tag, $depth);
}
if ($tag === false) {
$data = $format->UNDEF($open, $name, $attrs, $props);
$format->appendData($data);
continue;
}
// Current doc box uses PHP 7.3 so cannot use PHP 8 functions
//if (/* !($tag instanceof \Closure) && */ !str_starts_with($tag ?? '', "format_")) {
if (strncmp($tag ?? '', "format_", 7) !== 0) {
$data = $format->transformFromMap($open, $tag, $name, $attrs, $props);
} else {
$data = $format->{$tag}($open, $name, $attrs, $props);
}
$format->appendData($data);
}
$lastdepth = $depth;
break;
/* }}} */
case \XMLReader::TEXT: /* {{{ */
$value = $r->value;
$eldepth = $r->depth - 1;
$name = $this->STACK[$eldepth];
foreach($this as $format) {
$map = $this[$format][\XMLReader::TEXT];
if (isset($map[$name])) {
$tag = $map[$name];
if (is_array($tag)) {
$tag = $this->notXPath($tag, $eldepth);
}
if ($tag !== false) {
$data = $format->{$tag}($value, $name);
} else {
$data = $format->TEXT($value);
}
} else {
$data = $format->TEXT($value);
}
if ($data === false) {
$format->appendData($value);
} else {
$format->appendData($data);
}
}
break;
/* }}} */
case \XMLReader::CDATA: /* {{{ */
/* Different formats may want to escape the CDATA sections differently */
$value = $r->value;
foreach($this as $format) {
$retval = $format->CDATA($value);
$format->appendData($retval);
}
break;
/* }}} */
case \XMLReader::WHITESPACE: /* {{{ */
case \XMLReader::SIGNIFICANT_WHITESPACE:
$retval = $r->value;
foreach($this as $format) {
if (method_exists($format, 'format_whitespace')) {
$retval = $format->format_whitespace($retval, $this->STACK, $r->depth);
if ($retval === false) {
continue;
}
}
$format->appendData($retval);
}
break;
/* }}} */
case \XMLReader::PI:
$target = $r->name;
$data = $r->value;
foreach ($this as $format) {
$retval = $format->parsePI($target, $data);
if ($retval) {
$format->appendData($retval);
}
}
break;
}
}
/* Closing time */
foreach($this as $format) {
$format->notify(Render::FINALIZE, true);
}
$r->close();
ReaderKeeper::popReader();
} /* }}} */
}