diff --git a/src/HTML5/Elements.php b/src/HTML5/Elements.php
index 1632dcf..5d8cfd4 100644
--- a/src/HTML5/Elements.php
+++ b/src/HTML5/Elements.php
@@ -71,6 +71,24 @@ class Elements
*/
const BLOCK_ONLY_INLINE = 128;
+ /**
+ * Elements with optional end tags that cause auto-closing of previous and parent tags,
+ * as example most of the table related tags, see https://www.w3.org/TR/html401/struct/tables.html
+ * Structure is as follows:
+ * TAG-NAME => [PARENT-TAG-NAME-TO-CLOSE1, PARENT-TAG-NAME-TO-CLOSE2, ...].
+ *
+ * Order is important, after auto-closing one parent with might have to close also their parent.
+ *
+ * @var array
+ */
+ public static $optionalEndElementsParentsToClose = array(
+ 'tr' => array('td', 'tr'),
+ 'td' => array('td', 'th'),
+ 'th' => array('td', 'th'),
+ 'tfoot' => array('td', 'th', 'tr', 'tbody', 'thead'),
+ 'tbody' => array('td', 'th', 'tr', 'thead'),
+ );
+
/**
* The HTML5 elements as defined in http://dev.w3.org/html5/markup/elements.html.
*
diff --git a/src/HTML5/Parser/DOMTreeBuilder.php b/src/HTML5/Parser/DOMTreeBuilder.php
index 293d83e..d165b66 100644
--- a/src/HTML5/Parser/DOMTreeBuilder.php
+++ b/src/HTML5/Parser/DOMTreeBuilder.php
@@ -359,6 +359,16 @@ public function startTag($name, $attributes = array(), $selfClosing = false)
$this->onlyInline = null;
}
+ // some elements as table related tags might have optional end tags that force us to auto close multiple tags
+ // https://www.w3.org/TR/html401/struct/tables.html
+ if ($this->current instanceof \DOMElement && isset(Elements::$optionalEndElementsParentsToClose[$lname])) {
+ foreach (Elements::$optionalEndElementsParentsToClose[$lname] as $parentElName) {
+ if ($this->current instanceof \DOMElement && $this->current->tagName === $parentElName) {
+ $this->autoclose($parentElName);
+ }
+ }
+ }
+
try {
$prefix = ($pos = strpos($lname, ':')) ? substr($lname, 0, $pos) : '';
diff --git a/test/HTML5/Html5Test.php b/test/HTML5/Html5Test.php
index 1887a8d..62f36e1 100644
--- a/test/HTML5/Html5Test.php
+++ b/test/HTML5/Html5Test.php
@@ -56,6 +56,60 @@ public function testImageTagsInSvg()
$this->assertEmpty($this->html5->getErrors());
}
+ public function testSelfClosingTableHierarchyElements()
+ {
+ $html = '
+
+
+
+ 0
+ |
+
+ A
+ |
+ B1
+ | B2
+ |
+ C
+ |
+
+ 1
+ | 2
+ |
';
+
+ $expected = '
+
+
+ 0 |
+
+
+
+
+ A |
+
+
+ B1 |
+ B2 |
+
+
+ C |
+
+
+
+
+ 1 |
+ 2 |
+
+
+
';
+
+ $doc = $this->html5->loadHTMLFragment($html);
+ $this->assertSame(
+ preg_replace('/\s+/', '', $expected),
+ preg_replace('/\s+/', '', $this->html5->saveHTML($doc))
+ );
+ }
+
public function testLoadOptions()
{
// doc