Skip to content

Refactor Reader and Reader_Partial #112

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 16, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 6 additions & 11 deletions phpdotnet/phd/Reader.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<?php
namespace phpdotnet\phd;
//6271

class Reader extends \XMLReader
{
@@ -13,12 +12,13 @@ public function __construct() {
}

/* Get the content of a named node, or the current node. */
public function readContent($node = null) { /* {{{ */
public function readContent(?string $node = null): string {
$retval = "";

if($this->isEmptyElement) {
return $retval;
}

if (!$node) {
// We need libxml2.6.20 to be able to read the textual content of the node without skipping over the markup too
if (\LIBXML_VERSION >= 20620) {
@@ -29,18 +29,13 @@ public function readContent($node = null) { /* {{{ */
$node = $this->name;
}

$retval = "";
while (self::readNode($node)) {
$retval .= $this->value;
}
return $retval;
} /* }}} */
/* Read $nodeName until END_ELEMENT */
public function readNode($nodeName) { /* {{{ */
return self::read() && !($this->nodeType === self::END_ELEMENT && $this->name == $nodeName);
} /* }}} */
}

private function readNode(string $nodeName): bool {
return self::read() && !($this->nodeType === self::END_ELEMENT && $this->name === $nodeName);
}
}



52 changes: 9 additions & 43 deletions phpdotnet/phd/Reader/Partial.php
Original file line number Diff line number Diff line change
@@ -7,55 +7,27 @@ class Reader_Partial extends Reader
protected $skip = array();
protected $parents = array();

public function __construct() {
public function __construct(
array $render_ids,
?array $skip_ids = [],
?array $parents = [],
) {
parent::__construct();

$render_ids = Config::render_ids();
if ($render_ids !== NULL) {
if (is_array($render_ids)) {
$this->partial = $render_ids;
} else {
$this->partial[$render_ids] = 1;
}
$skip_ids = Config::skip_ids();
if ($skip_ids !== NULL) {
if (is_array($skip_ids)) {
$this->skip = $skip_ids;
} else {
$this->skip[$skip_ids] = 1;
}
}
} else {
if ($render_ids === []) {
throw new \Exception("Didn't get any IDs to seek");
}
$parents = array();
if (file_exists(Config::output_dir() . "index.sqlite")) {
$sqlite = new \SQLite3(Config::output_dir() . "index.sqlite");

// Fetch all ancestors of the ids we should render
foreach($render_ids as $p => $v) {
do {
$id = $sqlite->escapeString($p);
$row = $sqlite->query("SELECT parent_id FROM ids WHERE docbook_id = '$id'")->fetchArray(SQLITE3_ASSOC);
if ($row["parent_id"]) {
$parents[] = $p = $row["parent_id"];
continue;
}
break;
} while(1);
}
}

$this->partial = $render_ids;
$this->skip = $skip_ids;
$this->parents = $parents;
}

public function read() {
static $seeked = 0;
public function read(): bool {
static $currently_reading = false;
static $currently_skipping = false;
static $arrayPartial = array();
static $arraySkip = array();
$ignore = false;

while($ret = parent::read()) {
$id = $this->getAttributeNs("id", self::XMLNS_XML);
@@ -66,14 +38,12 @@ public function read() {
v("%s done", $id, VERBOSE_PARTIAL_READING);

unset($this->partial[$id]);
--$seeked;
$currently_reading = false;
array_pop($arrayPartial);
} else {
v("Starting %s...", $id, VERBOSE_PARTIAL_READING);

$currently_reading = $id;
++$seeked;
$arrayPartial[] = $id;
}
return $ret;
@@ -83,13 +53,11 @@ public function read() {

unset($this->skip[$id]);
$currently_skipping = false;
$ignore = false;
array_pop($arraySkip);
} else {
v("Skipping %s...", $id, VERBOSE_PARTIAL_READING);

$currently_skipping = $id;
$ignore = true;
$arraySkip[] = $id;
}
} elseif ($currently_skipping && $this->skip[$currently_skipping]) {
@@ -99,7 +67,6 @@ public function read() {
v("%s done", $id, VERBOSE_PARTIAL_CHILD_READING);
}

$ignore = true;
} elseif ($currently_reading && $this->partial[$currently_reading]) {
if ($currentPartial == $id) {
v("Rendering child of %s, %s", $currently_reading, $id, VERBOSE_PARTIAL_CHILD_READING);
@@ -120,7 +87,6 @@ public function read() {
parent::next();
}
}
$ignore = true;
}
}
return $ret;
30 changes: 24 additions & 6 deletions render.php
Original file line number Diff line number Diff line change
@@ -77,7 +77,29 @@ function make_reader() {
$idlist = Config::render_ids() + Config::skip_ids();
if (!empty($idlist)) {
v("Running partial build", VERBOSE_RENDER_STYLE);
$reader = new Reader_Partial();

$parents = [];
if (file_exists(Config::output_dir() . "index.sqlite")) {
$sqlite = new \SQLite3(Config::output_dir() . "index.sqlite");
// Fetch all ancestors of the ids we should render
foreach(Config::render_ids() as $p => $v) {
do {
$id = $sqlite->escapeString($p);
$row = $sqlite->query("SELECT parent_id FROM ids WHERE docbook_id = '$id'")->fetchArray(SQLITE3_ASSOC);
if ($row["parent_id"]) {
$parents[] = $p = $row["parent_id"];
continue;
}
break;
} while(1);
}
}

$reader = new Reader_Partial(
Config::render_ids(),
Config::skip_ids(),
$parents
);
} else {
v("Running full build", VERBOSE_RENDER_STYLE);
$reader = new Reader();
@@ -86,8 +108,6 @@ function make_reader() {
}

$render = new Render();
$reader = make_reader();


// Set reader LIBXML options
$readerOpts = LIBXML_PARSEHUGE;
@@ -102,6 +122,7 @@ function make_reader() {
$format = new Index;
$render->attach($format);

$reader = make_reader();
$reader->open(Config::xml_file(), NULL, $readerOpts);
$render->execute($reader);

@@ -135,6 +156,3 @@ function make_reader() {
$render->execute($reader);

v("Finished rendering", VERBOSE_FORMAT_RENDERING);



70 changes: 70 additions & 0 deletions tests/reader/partial_reader_001.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
--TEST--
Reader_Partial 001 - Read and skip elements based on their ID
--FILE--
<?php
namespace phpdotnet\phd;

require_once __DIR__ . "/../setup.php";

$xml = <<<XML
<?xml version="1.0" encoding="utf-8"?>
<section>
<emptyNode xml:id="renderThis1"></emptyNode>

<nonEmptyNode xml:id="renderThis2">
<title>Title here</title>
<content>Some content with <node xml:id="skipThis1">nodes</node></content>
</nonEmptyNode>

<anotherNonEmptyNode>
<content></content>
<content xml:id="renderThis3">
Some more content <node xml:id="skipThis2">but this is not read</node>
</content>
<content></content>
<content xml:id="renderThis4">
Some more content <node>and this is read</node>
</content>
</anotherNonEmptyNode>
</section>

XML;

try {
$reader = new Reader_Partial([]);
} catch (\Exception $e) {
var_dump($e->getMessage());
}

$renderIds = [
"renderThis1" => 1,
"renderThis2" => 1,
"renderThis3" => 1,
"renderThis4" => 1
];
$skipIds = [
"skipThis1" => 1,
"skipThis2" => 1
];
$parentIds = [];

$reader = new Reader_Partial($renderIds, $skipIds, $parentIds);
$reader->XML($xml);

while ($reader->read()) {
}
?>
--EXPECTF--
string(26) "Didn't get any IDs to seek"
%s[%d:%d:%d - Partial Reading ]%s Starting renderThis1...
%s[%d:%d:%d - Partial Reading ]%s renderThis1 done
%s[%d:%d:%d - Partial Reading ]%s Starting renderThis2...
%s[%d:%d:%d - Partial Reading ]%s Skipping skipThis1...
%s[%d:%d:%d - Partial Reading ]%s skipThis1 done
%s[%d:%d:%d - Partial Reading ]%s renderThis2 done
%s[%d:%d:%d - Partial Reading ]%s Starting renderThis3...
%s[%d:%d:%d - Partial Reading ]%s Skipping skipThis2...
%s[%d:%d:%d - Partial Reading ]%s skipThis2 done
%s[%d:%d:%d - Partial Reading ]%s renderThis3 done
%s[%d:%d:%d - Partial Reading ]%s Starting renderThis4...
%s[%d:%d:%d - Partial Reading ]%s renderThis4 done
57 changes: 57 additions & 0 deletions tests/reader/reader_001.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
--TEST--
Reader 001 - Read contents of current empty and non-empty elements
--FILE--
<?php
namespace phpdotnet\phd;

use XMLReader;

require_once __DIR__ . "/../setup.php";

$xml = <<<XML
<section>
<emptyNode></emptyNode>
<nonEmptyNode>
<title>Title here</title>
<content>Some content with <node>nodes</node></content>
</nonEmptyNode>
</section>

XML;

$reader = new Reader;
$reader->XML($xml);

echo "Read current node contents\n";
while ($reader->read()) {
if ($reader->nodeType === XMLReader::ELEMENT
&& ($reader->name === "emptyNode" || $reader->name === "nonEmptyNode")
) {
var_dump($reader->readContent());
}
}

$reader->XML($xml);
$reader->read();

echo "\nRead named node contents\n";
var_dump($reader->readContent("nonEmptyNode"));
var_dump($reader->readContent("emptyNode"));
?>
--EXPECT--
Read current node contents
string(0) ""
string(41) "
Title here
Some content with nodes
"

Read named node contents
string(45) "


Title here
Some content with nodes
"
string(1) "
"
Loading