Skip to content
Open
Show file tree
Hide file tree
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
14 changes: 14 additions & 0 deletions src/HTML5/Serializer/OutputRules.php
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,20 @@ public function comment($ele)
$this->wr($ele->ownerDocument->saveXML($ele));
}

/**
* Write an entity reference node.
*
* Such a node carries the entity name only: its nodeValue is null and its
* textContent is empty, so it cannot go through text(). saveXML() gives
* back the reference as it was written, which is what DOMDocument does.
*
* @param \DOMEntityReference $ele The entity reference to write.
*/
public function entityReference($ele)
{
$this->wr($ele->ownerDocument->saveXML($ele));
}

public function processorInstruction($ele)
{
$this->wr('<?')
Expand Down
8 changes: 8 additions & 0 deletions src/HTML5/Serializer/Traverser.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,14 @@ public function node($node)
case XML_COMMENT_NODE:
$this->rules->comment($node);
break;
case XML_ENTITY_REF_NODE:
// entityReference() is not on RulesInterface, so a custom rules
// implementation keeps the previous behaviour of skipping the node
// rather than fataling on a missing method.
if ($this->rules instanceof OutputRules) {
$this->rules->entityReference($node);
}
break;
// Currently we don't support embedding DTDs.
default:
//print '<!-- Skipped -->';
Expand Down
31 changes: 31 additions & 0 deletions test/HTML5/Serializer/OutputRulesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,37 @@ public function testText()
$this->assertEquals('&lt;script&gt;alert("hi");&lt;/script&gt;', stream_get_contents($stream, -1, 0));
}

public function testEntityReference()
{
$dom = $this->html5->loadHTML('<!doctype html>
<html lang="en">
<body></body>
</html>');

$body = $dom->getElementsByTagName('body')->item(0);
$span = $dom->createElement('span', 'Identit&eacute;');
$body->appendChild($span);

// The entity reference carries the name only: nodeValue is null and
// textContent is empty, so it cannot go through text().
$reference = $span->lastChild;
$this->assertEquals(XML_ENTITY_REF_NODE, $reference->nodeType);

// The traverser has to dispatch it, otherwise the node is skipped silently
// and the reference disappears from the output.
$stream = fopen('php://temp', 'w');
$r = new OutputRules($stream, $this->html5->getOptions());
$t = new Traverser($dom, $stream, $r, $this->html5->getOptions());

$t->node($span);
$this->assertEquals('<span>Identit&eacute;</span>', stream_get_contents($stream, -1, 0));

$stream = fopen('php://temp', 'w');
$r = new OutputRules($stream, $this->html5->getOptions());
$r->entityReference($reference);
$this->assertEquals('&eacute;', stream_get_contents($stream, -1, 0));
}

public function testNl()
{
list($o, $s) = $this->getOutputRules();
Expand Down