Skip to content

Commit c7c7657

Browse files
authored
Merge pull request #137 from apeschar/selfclosing
Respect self-closing tags only on foreign elements
2 parents d06a280 + 222b1f9 commit c7c7657

File tree

4 files changed

+54
-9
lines changed

4 files changed

+54
-9
lines changed

src/HTML5/Parser/DOMTreeBuilder.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -433,10 +433,16 @@ public function startTag($name, $attributes = array(), $selfClosing = false)
433433
else {
434434
$this->current->appendChild($ele);
435435

436-
// XXX: Need to handle self-closing tags and unary tags.
437436
if (! Elements::isA($name, Elements::VOID_TAG)) {
438437
$this->current = $ele;
439438
}
439+
440+
// Self-closing tags should only be respected on foreign elements
441+
// (and are implied on void elements)
442+
// See: https://www.w3.org/TR/html5/syntax.html#start-tags
443+
if (Elements::isHtml5Element($name)) {
444+
$selfClosing = false;
445+
}
440446
}
441447

442448
// This is sort of a last-ditch attempt to correct for cases where no head/body
@@ -453,6 +459,11 @@ public function startTag($name, $attributes = array(), $selfClosing = false)
453459
array_shift($this->nsStack);
454460
}
455461
}
462+
463+
if ($selfClosing) {
464+
$this->endTag($name);
465+
}
466+
456467
// Return the element mask, which the tokenizer can then use to set
457468
// various processing rules.
458469
return Elements::element($name);

src/HTML5/Parser/Tokenizer.php

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -383,11 +383,8 @@ protected function tagName()
383383
}
384384

385385
$mode = $this->events->startTag($name, $attributes, $selfClose);
386-
// Should we do this? What does this buy that selfClose doesn't?
387-
if ($selfClose) {
388-
$this->events->endTag($name);
389-
} elseif (is_int($mode)) {
390-
// fprintf(STDOUT, "Event response says move into mode %d for tag %s", $mode, $name);
386+
387+
if (is_int($mode)) {
391388
$this->setTextMode($mode, $name);
392389
}
393390

test/HTML5/Parser/DOMTreeBuilderTest.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -643,4 +643,40 @@ public function testSelectGroupedOptions()
643643
$this->assertSame(3, $dom->getElementById('first')->getElementsByTagName('option')->length);
644644
$this->assertSame(2, $dom->getElementById('second')->getElementsByTagName('option')->length);
645645
}
646+
647+
public function testVoidTag() {
648+
$html = <<<EOM
649+
<!DOCTYPE html>
650+
<html>
651+
<head>
652+
<title>testVoidTag</title>
653+
<meta>
654+
<meta>
655+
</head>
656+
<body></body>
657+
</html>
658+
EOM;
659+
660+
$dom = $this->parse($html);
661+
$this->assertSame(2, $dom->getElementsByTagName('meta')->length);
662+
$this->assertSame(0, $dom->getElementsByTagName('meta')->item(0)->childNodes->length);
663+
$this->assertSame(0, $dom->getElementsByTagName('meta')->item(1)->childNodes->length);
664+
}
665+
666+
public function testIgnoreSelfClosingTag() {
667+
$html = <<<EOM
668+
<!DOCTYPE html>
669+
<html>
670+
<head>
671+
<title>testIllegalSelfClosingTag</title>
672+
</head>
673+
<body>
674+
<div /><span>Hello, World!</span></div>
675+
</body>
676+
</html>
677+
EOM;
678+
679+
$dom = $this->parse($html);
680+
$this->assertSame(1, $dom->getElementsByTagName('div')->item(0)->childNodes->length);
681+
}
646682
}

test/HTML5/Parser/TokenizerTest.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -447,9 +447,10 @@ public function testSimpleTags()
447447
);
448448
foreach ($selfClose as $test => $expects) {
449449
$events = $this->parse($test);
450-
$this->assertEquals(3, $events->depth(), "Counting events for '$test'" . print_r($events, true));
450+
$this->assertEquals(2, $events->depth(), "Counting events for '$test'" . print_r($events, true));
451451
$this->assertEventEquals('startTag', $expects, $events->get(0));
452-
$this->assertEventEquals('endTag', $expects, $events->get(1));
452+
$event = $events->get(0);
453+
$this->assertTrue($event['data'][2]);
453454
}
454455

455456
$bad = array(
@@ -735,7 +736,7 @@ public function testTagAttributes()
735736
true
736737
)
737738
);
738-
$this->isAllGood('startTag', 3, $withEnd);
739+
$this->isAllGood('startTag', 2, $withEnd);
739740

740741
// Cause a parse error.
741742
$bad = array(

0 commit comments

Comments
 (0)