28 }
catch (DOMException $e) {
31 $context->register(
'PH5PError', $e);
36 $doc->getElementsByTagName(
'html')->item(0)->
37 getElementsByTagName(
'body')->item(0)
79 private $escape =
false;
467 $this->content_model = self::PCDATA;
469 $this->state =
'data';
471 while ($this->state !== null) {
472 $this->{$this->state .
'State'}();
478 return $this->tree->save();
483 return ($this->char < $this->
EOF)
484 ? $this->
data[$this->char]
490 if ($s + $l < $this->
EOF) {
492 return $this->
data[$s];
494 return substr($this->
data, $s,
$l);
501 return preg_replace(
'#^([' . $char_class .
']+).*#s',
'\\1', substr($this->
data,
$start));
508 $char = $this->char();
510 if ($char ===
'&' && ($this->content_model === self::PCDATA || $this->content_model === self::RCDATA)) {
515 $this->state =
'entityData';
517 } elseif ($char ===
'-') {
524 if (($this->content_model === self::RCDATA || $this->content_model ===
525 self::CDATA) && $this->escape ===
false &&
526 $this->
char >= 3 && $this->character($this->
char - 4, 4) ===
'<!--' 528 $this->escape =
true;
535 'type' => self::CHARACTR,
541 } elseif ($char ===
'<' && ($this->content_model === self::PCDATA ||
542 (($this->content_model === self::RCDATA ||
543 $this->content_model === self::CDATA) && $this->escape ===
false))
553 $this->state =
'tagOpen';
556 } elseif ($char ===
'>') {
562 if (($this->content_model === self::RCDATA ||
563 $this->content_model === self::CDATA) && $this->escape ===
true &&
564 $this->character($this->
char, 3) ===
'-->' 566 $this->escape =
false;
573 'type' => self::CHARACTR,
578 } elseif ($this->
char === $this->
EOF) {
583 } elseif ($this->content_model === self::PLAINTEXT) {
589 'type' => self::CHARACTR,
590 'data' => substr($this->
data, $this->
char)
601 $len = strcspn($this->
data,
'<&', $this->
char);
602 $char = substr($this->
data, $this->
char, $len);
603 $this->
char += $len - 1;
607 'type' => self::CHARACTR,
612 $this->state =
'data';
619 $entity = $this->entity();
623 $char = (!$entity) ?
'&' : $entity;
626 'type' => self::CHARACTR,
632 $this->state =
'data';
637 switch ($this->content_model) {
645 if ($this->character($this->
char + 1) ===
'/') {
647 $this->state =
'closeTagOpen';
652 'type' => self::CHARACTR,
657 $this->state =
'data';
665 $char = $this->char();
670 $this->state =
'markupDeclarationOpen';
672 } elseif ($char ===
'/') {
675 $this->state =
'closeTagOpen';
677 } elseif (preg_match(
'/^[A-Za-z]$/', $char)) {
683 $this->token =
array(
684 'name' => strtolower($char),
685 'type' => self::STARTTAG,
689 $this->state =
'tagName';
691 } elseif ($char ===
'>') {
697 'type' => self::CHARACTR,
702 $this->state =
'data';
704 } elseif ($char ===
'?') {
707 $this->state =
'bogusComment';
715 'type' => self::CHARACTR,
721 $this->state =
'data';
729 $next_node = strtolower($this->characters(
'A-Za-z', $this->
char + 1));
730 $the_same = count($this->tree->stack) > 0 && $next_node === end($this->tree->stack)->nodeName;
732 if (($this->content_model === self::RCDATA || $this->content_model === self::CDATA) &&
733 (!$the_same || ($the_same && (!preg_match(
734 '/[\t\n\x0b\x0c >\/]/',
735 $this->character($this->
char + 1 + strlen($next_node))
736 ) || $this->
EOF === $this->
char)))
755 'type' => self::CHARACTR,
760 $this->state =
'data';
767 $char = $this->char();
769 if (preg_match(
'/^[A-Za-z]$/', $char)) {
775 $this->token =
array(
776 'name' => strtolower($char),
777 'type' => self::ENDTAG
780 $this->state =
'tagName';
782 } elseif ($char ===
'>') {
785 $this->state =
'data';
787 } elseif ($this->
char === $this->
EOF) {
793 'type' => self::CHARACTR,
799 $this->state =
'data';
803 $this->state =
'bogusComment';
812 $char = $this->character($this->
char);
814 if (preg_match(
'/^[\t\n\x0b\x0c ]$/', $char)) {
821 $this->state =
'beforeAttributeName';
823 } elseif ($char ===
'>') {
826 $this->emitToken($this->token);
827 $this->state =
'data';
829 } elseif ($this->
char === $this->
EOF) {
833 $this->emitToken($this->token);
836 $this->state =
'data';
838 } elseif ($char ===
'/') {
842 $this->state =
'beforeAttributeName';
848 $this->token[
'name'] .= strtolower($char);
849 $this->state =
'tagName';
857 $char = $this->character($this->
char);
859 if (preg_match(
'/^[\t\n\x0b\x0c ]$/', $char)) {
866 $this->state =
'beforeAttributeName';
868 } elseif ($char ===
'>') {
871 $this->emitToken($this->token);
872 $this->state =
'data';
874 } elseif ($char ===
'/') {
878 $this->state =
'beforeAttributeName';
880 } elseif ($this->
char === $this->
EOF) {
884 $this->emitToken($this->token);
887 $this->state =
'data';
894 $this->token[
'attr'][] =
array(
895 'name' => strtolower($char),
899 $this->state =
'attributeName';
907 $char = $this->character($this->
char);
909 if (preg_match(
'/^[\t\n\x0b\x0c ]$/', $char)) {
916 $this->state =
'afterAttributeName';
918 } elseif ($char ===
'=') {
921 $this->state =
'beforeAttributeValue';
923 } elseif ($char ===
'>') {
926 $this->emitToken($this->token);
927 $this->state =
'data';
929 } elseif ($char ===
'/' && $this->character($this->
char + 1) !==
'>') {
933 $this->state =
'beforeAttributeName';
935 } elseif ($this->
char === $this->
EOF) {
939 $this->emitToken($this->token);
942 $this->state =
'data';
948 $last = count($this->token[
'attr']) - 1;
949 $this->token[
'attr'][$last][
'name'] .= strtolower($char);
951 $this->state =
'attributeName';
959 $char = $this->character($this->
char);
961 if (preg_match(
'/^[\t\n\x0b\x0c ]$/', $char)) {
968 $this->state =
'afterAttributeName';
970 } elseif ($char ===
'=') {
973 $this->state =
'beforeAttributeValue';
975 } elseif ($char ===
'>') {
978 $this->emitToken($this->token);
979 $this->state =
'data';
981 } elseif ($char ===
'/' && $this->character($this->
char + 1) !==
'>') {
985 $this->state =
'beforeAttributeName';
987 } elseif ($this->
char === $this->
EOF) {
991 $this->emitToken($this->token);
994 $this->state =
'data';
1001 $this->token[
'attr'][] =
array(
1002 'name' => strtolower($char),
1006 $this->state =
'attributeName';
1014 $char = $this->character($this->
char);
1016 if (preg_match(
'/^[\t\n\x0b\x0c ]$/', $char)) {
1023 $this->state =
'beforeAttributeValue';
1025 } elseif ($char ===
'"') {
1028 $this->state =
'attributeValueDoubleQuoted';
1030 } elseif ($char ===
'&') {
1035 $this->state =
'attributeValueUnquoted';
1037 } elseif ($char ===
'\'') {
1040 $this->state =
'attributeValueSingleQuoted';
1042 } elseif ($char ===
'>') {
1045 $this->emitToken($this->token);
1046 $this->state =
'data';
1052 $last = count($this->token[
'attr']) - 1;
1053 $this->token[
'attr'][$last][
'value'] .= $char;
1055 $this->state =
'attributeValueUnquoted';
1063 $char = $this->character($this->
char);
1065 if ($char ===
'"') {
1068 $this->state =
'beforeAttributeName';
1070 } elseif ($char ===
'&') {
1073 $this->entityInAttributeValueState(
'double');
1075 } elseif ($this->
char === $this->
EOF) {
1079 $this->emitToken($this->token);
1082 $this->state =
'data';
1088 $last = count($this->token[
'attr']) - 1;
1089 $this->token[
'attr'][$last][
'value'] .= $char;
1091 $this->state =
'attributeValueDoubleQuoted';
1099 $char = $this->character($this->
char);
1101 if ($char ===
'\'') {
1104 $this->state =
'beforeAttributeName';
1106 } elseif ($char ===
'&') {
1109 $this->entityInAttributeValueState(
'single');
1111 } elseif ($this->
char === $this->
EOF) {
1115 $this->emitToken($this->token);
1118 $this->state =
'data';
1124 $last = count($this->token[
'attr']) - 1;
1125 $this->token[
'attr'][$last][
'value'] .= $char;
1127 $this->state =
'attributeValueSingleQuoted';
1135 $char = $this->character($this->
char);
1137 if (preg_match(
'/^[\t\n\x0b\x0c ]$/', $char)) {
1144 $this->state =
'beforeAttributeName';
1146 } elseif ($char ===
'&') {
1149 $this->entityInAttributeValueState();
1151 } elseif ($char ===
'>') {
1154 $this->emitToken($this->token);
1155 $this->state =
'data';
1161 $last = count($this->token[
'attr']) - 1;
1162 $this->token[
'attr'][$last][
'value'] .= $char;
1164 $this->state =
'attributeValueUnquoted';
1171 $entity = $this->entity();
1180 $last = count($this->token[
'attr']) - 1;
1181 $this->token[
'attr'][$last][
'value'] .= $char;
1194 $data = $this->characters(
'^>', $this->
char);
1198 'type' => self::COMMENT
1202 $this->
char += strlen(
$data);
1205 $this->state =
'data';
1208 if ($this->
char === $this->
EOF) {
1209 $this->
char = $this->
EOF - 1;
1218 if ($this->character($this->
char + 1, 2) ===
'--') {
1220 $this->state =
'comment';
1221 $this->token =
array(
1223 'type' => self::COMMENT
1229 } elseif (strtolower($this->character($this->
char + 1, 7)) ===
'doctype') {
1231 $this->state =
'doctype';
1238 $this->state =
'bogusComment';
1246 $char = $this->char();
1249 if ($char ===
'-') {
1251 $this->state =
'commentDash';
1254 } elseif ($this->
char === $this->
EOF) {
1257 $this->emitToken($this->token);
1259 $this->state =
'data';
1265 $this->token[
'data'] .= $char;
1273 $char = $this->char();
1276 if ($char ===
'-') {
1278 $this->state =
'commentEnd';
1281 } elseif ($this->
char === $this->
EOF) {
1284 $this->emitToken($this->token);
1286 $this->state =
'data';
1292 $this->token[
'data'] .=
'-' . $char;
1293 $this->state =
'comment';
1301 $char = $this->char();
1303 if ($char ===
'>') {
1304 $this->emitToken($this->token);
1305 $this->state =
'data';
1307 } elseif ($char ===
'-') {
1308 $this->token[
'data'] .=
'-';
1310 } elseif ($this->
char === $this->
EOF) {
1311 $this->emitToken($this->token);
1313 $this->state =
'data';
1316 $this->token[
'data'] .=
'--' . $char;
1317 $this->state =
'comment';
1325 $char = $this->char();
1327 if (preg_match(
'/^[\t\n\x0b\x0c ]$/', $char)) {
1328 $this->state =
'beforeDoctypeName';
1332 $this->state =
'beforeDoctypeName';
1340 $char = $this->char();
1342 if (preg_match(
'/^[\t\n\x0b\x0c ]$/', $char)) {
1345 } elseif (preg_match(
'/^[a-z]$/', $char)) {
1346 $this->token =
array(
1347 'name' => strtoupper($char),
1348 'type' => self::DOCTYPE,
1352 $this->state =
'doctypeName';
1354 } elseif ($char ===
'>') {
1358 'type' => self::DOCTYPE,
1363 $this->state =
'data';
1365 } elseif ($this->
char === $this->
EOF) {
1369 'type' => self::DOCTYPE,
1375 $this->state =
'data';
1378 $this->token =
array(
1380 'type' => self::DOCTYPE,
1384 $this->state =
'doctypeName';
1392 $char = $this->char();
1394 if (preg_match(
'/^[\t\n\x0b\x0c ]$/', $char)) {
1395 $this->state =
'AfterDoctypeName';
1397 } elseif ($char ===
'>') {
1398 $this->emitToken($this->token);
1399 $this->state =
'data';
1401 } elseif (preg_match(
'/^[a-z]$/', $char)) {
1402 $this->token[
'name'] .= strtoupper($char);
1404 } elseif ($this->
char === $this->
EOF) {
1405 $this->emitToken($this->token);
1407 $this->state =
'data';
1410 $this->token[
'name'] .= $char;
1413 $this->token[
'error'] = ($this->token[
'name'] ===
'HTML')
1422 $char = $this->char();
1424 if (preg_match(
'/^[\t\n\x0b\x0c ]$/', $char)) {
1427 } elseif ($char ===
'>') {
1428 $this->emitToken($this->token);
1429 $this->state =
'data';
1431 } elseif ($this->
char === $this->
EOF) {
1432 $this->emitToken($this->token);
1434 $this->state =
'data';
1437 $this->token[
'error'] =
true;
1438 $this->state =
'bogusDoctype';
1446 $char = $this->char();
1448 if ($char ===
'>') {
1449 $this->emitToken($this->token);
1450 $this->state =
'data';
1452 } elseif ($this->
char === $this->
EOF) {
1453 $this->emitToken($this->token);
1455 $this->state =
'data';
1472 switch ($this->character($this->
char + 1)) {
1478 switch ($this->character($this->
char + 1)) {
1490 $char_class =
'0-9A-Fa-f';
1499 $char_class =
'0-9';
1506 $e_name = $this->characters($char_class, $this->
char + $char + 1);
1507 $entity = $this->character(
$start, $this->
char);
1508 $cond = strlen($e_name) > 0;
1518 $e_name = $this->characters(
'0-9A-Za-z;', $this->
char + 1);
1519 $len = strlen($e_name);
1521 for ($c = 1; $c <= $len; $c++) {
1522 $id = substr($e_name, 0, $c);
1525 if (in_array($id, $this->entities)) {
1526 if ($e_name[$c - 1] !==
';') {
1527 if ($c < $len && $e_name[$c] ==
';') {
1536 $cond = isset($entity);
1550 return html_entity_decode(
'&' . $entity .
';', ENT_QUOTES,
'UTF-8');
1555 $emit = $this->tree->emitToken($token);
1557 if (is_int($emit)) {
1558 $this->content_model = $emit;
1560 } elseif ($token[
'type'] === self::ENDTAG) {
1561 $this->content_model = self::PCDATA;
1567 $this->state = null;
1568 $this->tree->emitToken(
1583 private $foster_parent = null;
1586 private $head_pointer = null;
1587 private $form_pointer = null;
1589 private $scoping =
array(
'button',
'caption',
'html',
'marquee',
'object',
'table',
'td',
'th');
1670 const INIT_PHASE = 0;
1671 const ROOT_PHASE = 1;
1672 const MAIN_PHASE = 2;
1673 const END_PHASE = 3;
1676 const BEFOR_HEAD = 0;
1678 const AFTER_HEAD = 2;
1681 const IN_CAPTION = 5;
1682 const IN_CGROUP = 6;
1686 const IN_SELECT = 10;
1687 const AFTER_BODY = 11;
1688 const IN_FRAME = 12;
1689 const AFTR_FRAME = 13;
1694 const FORMATTING = 2;
1701 $this->phase = self::INIT_PHASE;
1702 $this->mode = self::BEFOR_HEAD;
1705 $this->dom->encoding =
'UTF-8';
1706 $this->dom->preserveWhiteSpace =
true;
1707 $this->dom->substituteEntities =
true;
1708 $this->dom->strictErrorChecking =
false;
1714 switch ($this->phase) {
1715 case self::INIT_PHASE:
1716 return $this->initPhase($token);
1718 case self::ROOT_PHASE:
1719 return $this->rootElementPhase($token);
1721 case self::MAIN_PHASE:
1722 return $this->mainPhase($token);
1724 case self::END_PHASE :
1725 return $this->trailingEndPhase($token);
1743 if ((isset($token[
'error']) && $token[
'error']) ||
1749 !preg_match(
'/^[\t\n\x0b\x0c ]+$/', $token[
'data']))
1756 $this->phase = self::ROOT_PHASE;
1757 return $this->rootElementPhase($token);
1760 } elseif (isset($token[
'error']) && !$token[
'error']) {
1765 $doctype =
new DOMDocumentType(null, null,
'HTML');
1769 $this->phase = self::ROOT_PHASE;
1774 } elseif (isset($token[
'data']) && preg_match(
1775 '/^[\t\n\x0b\x0c ]+$/',
1780 $text = $this->dom->createTextNode($token[
'data']);
1781 $this->dom->appendChild(
$text);
1798 $comment = $this->dom->createComment($token[
'data']);
1805 preg_match(
'/^[\t\n\x0b\x0c ]+$/', $token[
'data'])
1808 $text = $this->dom->createTextNode($token[
'data']);
1809 $this->dom->appendChild(
$text);
1818 !preg_match(
'/^[\t\n\x0b\x0c ]+$/', $token[
'data'])) ||
1826 $html = $this->dom->createElement(
'html');
1827 $this->dom->appendChild(
$html);
1828 $this->stack[] =
$html;
1830 $this->phase = self::MAIN_PHASE;
1831 return $this->mainPhase($token);
1844 } elseif ($token[
'type'] ===
HTML5::STARTTAG && $token[
'name'] ===
'html') {
1852 foreach ($token[
'attr'] as $attr) {
1853 if (!$this->stack[0]->hasAttribute($attr[
'name'])) {
1854 $this->stack[0]->setAttribute($attr[
'name'], $attr[
'value']);
1861 $this->generateImpliedEndTags();
1866 switch ($this->mode) {
1867 case self::BEFOR_HEAD:
1868 return $this->beforeHead($token);
1871 return $this->inHead($token);
1873 case self::AFTER_HEAD:
1874 return $this->afterHead($token);
1877 return $this->inBody($token);
1879 case self::IN_TABLE:
1880 return $this->inTable($token);
1882 case self::IN_CAPTION:
1883 return $this->inCaption($token);
1885 case self::IN_CGROUP:
1886 return $this->inColumnGroup($token);
1888 case self::IN_TBODY:
1889 return $this->inTableBody($token);
1892 return $this->inRow($token);
1895 return $this->inCell($token);
1897 case self::IN_SELECT:
1898 return $this->inSelect($token);
1900 case self::AFTER_BODY:
1901 return $this->afterBody($token);
1903 case self::IN_FRAME:
1904 return $this->inFrameset($token);
1906 case self::AFTR_FRAME:
1907 return $this->afterFrameset($token);
1909 case self::END_PHASE:
1910 return $this->trailingEndPhase($token);
1924 preg_match(
'/^[\t\n\x0b\x0c ]+$/', $token[
'data'])
1927 $this->insertText($token[
'data']);
1933 $this->insertComment($token[
'data']);
1936 } elseif ($token[
'type'] ===
HTML5::STARTTAG && $token[
'name'] ===
'head') {
1939 $element = $this->insertElement($token);
1942 $this->head_pointer = $element;
1945 $this->mode = self::IN_HEAD;
1953 ($token[
'type'] ===
HTML5::ENDTAG && $token[
'name'] ===
'html') ||
1955 '/^[\t\n\x0b\x0c ]$/',
1969 return $this->inHead($token);
1989 preg_match(
'/^[\t\n\x0b\x0c ]+$/', $token[
'data'])) || (
1991 end($this->stack)->nodeName,
1992 array(
'title',
'style',
'script')
1996 $this->insertText($token[
'data']);
2002 $this->insertComment($token[
'data']);
2005 in_array($token[
'name'],
array(
'title',
'style',
'script'))
2007 array_pop($this->stack);
2011 } elseif ($token[
'type'] ===
HTML5::STARTTAG && $token[
'name'] ===
'title') {
2015 if ($this->head_pointer !== null) {
2016 $element = $this->insertElement($token,
false);
2017 $this->head_pointer->appendChild($element);
2020 $element = $this->insertElement($token);
2027 } elseif ($token[
'type'] ===
HTML5::STARTTAG && $token[
'name'] ===
'style') {
2031 if ($this->head_pointer !== null) {
2032 $element = $this->insertElement($token,
false);
2033 $this->head_pointer->appendChild($element);
2036 $this->insertElement($token);
2043 } elseif ($token[
'type'] ===
HTML5::STARTTAG && $token[
'name'] ===
'script') {
2045 $element = $this->insertElement($token,
false);
2046 $this->head_pointer->appendChild($element);
2054 array(
'base',
'link',
'meta')
2060 if ($this->head_pointer !== null) {
2061 $element = $this->insertElement($token,
false);
2062 $this->head_pointer->appendChild($element);
2063 array_pop($this->stack);
2066 $this->insertElement($token);
2070 } elseif ($token[
'type'] ===
HTML5::ENDTAG && $token[
'name'] ===
'head') {
2073 if ($this->head_pointer->isSameNode(end($this->stack))) {
2074 array_pop($this->stack);
2082 $this->mode = self::AFTER_HEAD;
2085 } elseif (($token[
'type'] ===
HTML5::STARTTAG && $token[
'name'] ===
'head') ||
2086 ($token[
'type'] ===
HTML5::ENDTAG && $token[
'name'] !==
'html')
2094 if ($this->head_pointer->isSameNode(end($this->stack))) {
2104 $this->mode = self::AFTER_HEAD;
2108 return $this->afterHead($token);
2120 preg_match(
'/^[\t\n\x0b\x0c ]+$/', $token[
'data'])
2123 $this->insertText($token[
'data']);
2129 $this->insertComment($token[
'data']);
2132 } elseif ($token[
'type'] ===
HTML5::STARTTAG && $token[
'name'] ===
'body') {
2134 $this->insertElement($token);
2137 $this->mode = self::IN_BODY;
2140 } elseif ($token[
'type'] ===
HTML5::STARTTAG && $token[
'name'] ===
'frameset') {
2142 $this->insertElement($token);
2145 $this->mode = self::IN_FRAME;
2151 array(
'base',
'link',
'meta',
'script',
'style',
'title')
2156 $this->mode = self::IN_HEAD;
2157 return $this->inHead($token);
2171 return $this->inBody($token);
2179 switch ($token[
'type']) {
2183 $this->reconstructActiveFormattingElements();
2186 $this->insertText($token[
'data']);
2193 $this->insertComment($token[
'data']);
2197 switch ($token[
'name']) {
2204 return $this->inHead($token);
2215 return $this->inHead($token);
2224 if (count($this->stack) === 1 || $this->stack[1]->nodeName !==
'body') {
2233 foreach ($token[
'attr'] as $attr) {
2234 if (!$this->stack[1]->hasAttribute($attr[
'name'])) {
2235 $this->stack[1]->setAttribute($attr[
'name'], $attr[
'value']);
2259 if ($this->elementInScope(
'p')) {
2269 $this->insertElement($token);
2276 if ($this->form_pointer !== null) {
2284 if ($this->elementInScope(
'p')) {
2295 $element = $this->insertElement($token);
2296 $this->form_pointer = $element;
2307 if ($this->elementInScope(
'p')) {
2316 $stack_length = count($this->stack) - 1;
2318 for (
$n = $stack_length; 0 <=
$n;
$n--) {
2322 $node = $this->stack[
$n];
2323 $cat = $this->getElementCategory($node->tagName);
2328 if ($token[
'name'] === $node->tagName || ($token[
'name'] !==
'li' 2329 && ($node->tagName ===
'dd' || $node->tagName ===
'dt'))
2331 for (
$x = $stack_length;
$x >=
$n;
$x--) {
2332 array_pop($this->stack);
2341 if ($cat !== self::FORMATTING && $cat !== self::PHRASING &&
2342 $node->tagName !==
'address' && $node->tagName !==
'div' 2350 $this->insertElement($token);
2358 if ($this->elementInScope(
'p')) {
2368 $this->insertElement($token);
2383 if ($this->elementInScope(
'p')) {
2397 while ($this->elementInScope(
array(
'h1',
'h2',
'h3',
'h4',
'h5',
'h6'))) {
2398 array_pop($this->stack);
2402 $this->insertElement($token);
2416 $leng = count($this->a_formatting);
2418 for (
$n = $leng - 1;
$n >= 0;
$n--) {
2419 if ($this->a_formatting[
$n] === self::MARKER) {
2422 } elseif ($this->a_formatting[
$n]->nodeName ===
'a') {
2434 $this->reconstructActiveFormattingElements();
2437 $el = $this->insertElement($token);
2441 $this->a_formatting[] = $el;
2459 $this->reconstructActiveFormattingElements();
2462 $el = $this->insertElement($token);
2466 $this->a_formatting[] = $el;
2475 if ($this->elementInScope(
'button')) {
2485 $this->reconstructActiveFormattingElements();
2488 $this->insertElement($token);
2492 $this->a_formatting[] = self::MARKER;
2499 $this->reconstructActiveFormattingElements();
2502 $this->insertElement($token);
2506 $this->a_formatting[] = self::MARKER;
2512 $this->reconstructActiveFormattingElements();
2515 $this->insertElement($token);
2525 if ($this->elementInScope(
'p')) {
2535 $this->insertElement($token);
2538 $this->mode = self::IN_TABLE;
2553 $this->reconstructActiveFormattingElements();
2556 $this->insertElement($token);
2559 array_pop($this->stack);
2566 if ($this->elementInScope(
'p')) {
2576 $this->insertElement($token);
2579 array_pop($this->stack);
2586 $token[
'name'] =
'img';
2587 return $this->inBody($token);
2593 $this->reconstructActiveFormattingElements();
2596 $element = $this->insertElement($token,
false);
2601 $this->form_pointer !== null
2602 ? $this->form_pointer->appendChild($element)
2603 : end($this->stack)->appendChild($element);
2606 array_pop($this->stack);
2616 if ($this->form_pointer === null) {
2659 'This is a searchable index. ' .
2660 'Insert your search keywords here: ' 2667 $attr = $token[
'attr'];
2668 $attr[] =
array(
'name' =>
'name',
'value' =>
'isindex');
2681 'This is a searchable index. ' .
2682 'Insert your search keywords here: ' 2725 $this->insertElement($token);
2737 $this->insertElement($token);
2746 $this->reconstructActiveFormattingElements();
2749 $this->insertElement($token);
2752 $this->mode = self::IN_SELECT;
2778 case 'event-source':
2793 $this->reconstructActiveFormattingElements();
2795 $this->insertElement($token,
true,
true);
2801 switch ($token[
'name']) {
2807 if (count($this->stack) < 2 || $this->stack[1]->nodeName !==
'body') {
2812 } elseif (end($this->stack)->nodeName !==
'body') {
2817 $this->mode = self::AFTER_BODY;
2832 return $this->afterBody($token);
2853 if ($this->elementInScope($token[
'name'])) {
2854 $this->generateImpliedEndTags();
2865 for (
$n = count($this->stack) - 1;
$n >= 0;
$n--) {
2866 if ($this->stack[
$n]->nodeName === $token[
'name']) {
2870 array_pop($this->stack);
2880 if ($this->elementInScope($token[
'name'])) {
2881 $this->generateImpliedEndTags();
2885 if (end($this->stack)->nodeName !== $token[
'name']) {
2895 array_pop($this->stack);
2899 $this->form_pointer = null;
2906 if ($this->elementInScope(
'p')) {
2907 $this->generateImpliedEndTags(
array(
'p'));
2916 for (
$n = count($this->stack) - 1;
$n >= 0;
$n--) {
2917 if ($this->elementInScope(
'p')) {
2918 array_pop($this->stack);
2935 if ($this->elementInScope($token[
'name'])) {
2936 $this->generateImpliedEndTags(
array($token[
'name']));
2946 for (
$n = count($this->stack) - 1;
$n >= 0;
$n--) {
2947 if ($this->stack[
$n]->nodeName === $token[
'name']) {
2951 array_pop($this->stack);
2964 $elements =
array(
'h1',
'h2',
'h3',
'h4',
'h5',
'h6');
2969 if ($this->elementInScope($elements)) {
2970 $this->generateImpliedEndTags();
2980 while ($this->elementInScope($elements)) {
2981 array_pop($this->stack);
3009 for ($a = count($this->a_formatting) - 1; $a >= 0; $a--) {
3010 if ($this->a_formatting[$a] === self::MARKER) {
3013 } elseif ($this->a_formatting[$a]->tagName === $token[
'name']) {
3014 $formatting_element = $this->a_formatting[$a];
3015 $in_stack = in_array($formatting_element, $this->stack,
true);
3025 if (!isset($formatting_element) || ($in_stack &&
3026 !$this->elementInScope($token[
'name']))
3034 } elseif (isset($formatting_element) && !$in_stack) {
3035 unset($this->a_formatting[$fe_af_pos]);
3036 $this->a_formatting = array_merge($this->a_formatting);
3045 $fe_s_pos = array_search($formatting_element, $this->stack,
true);
3046 $length = count($this->stack);
3048 for ($s = $fe_s_pos + 1; $s < $length; $s++) {
3049 $category = $this->getElementCategory($this->stack[$s]->nodeName);
3051 if ($category !== self::PHRASING && $category !== self::FORMATTING) {
3052 $furthest_block = $this->stack[$s];
3062 if (!isset($furthest_block)) {
3063 for (
$n = $length - 1;
$n >= $fe_s_pos;
$n--) {
3064 array_pop($this->stack);
3067 unset($this->a_formatting[$fe_af_pos]);
3068 $this->a_formatting = array_merge($this->a_formatting);
3075 $common_ancestor = $this->stack[$fe_s_pos - 1];
3079 if ($furthest_block->parentNode !== null) {
3080 $furthest_block->parentNode->removeChild($furthest_block);
3087 $bookmark = $fe_af_pos;
3091 $node = $furthest_block;
3092 $last_node = $furthest_block;
3095 for (
$n = array_search($node, $this->stack,
true) - 1;
$n >= 0;
$n--) {
3098 $node = $this->stack[
$n];
3104 if (!in_array($node, $this->a_formatting,
true)) {
3105 unset($this->stack[
$n]);
3106 $this->stack = array_merge($this->stack);
3116 if ($node === $formatting_element) {
3123 } elseif ($last_node === $furthest_block) {
3124 $bookmark = array_search($node, $this->a_formatting,
true) + 1;
3133 if ($node->hasChildNodes()) {
3134 $clone = $node->cloneNode();
3135 $s_pos = array_search($node, $this->stack,
true);
3136 $a_pos = array_search($node, $this->a_formatting,
true);
3138 $this->stack[$s_pos] = $clone;
3139 $this->a_formatting[$a_pos] = $clone;
3145 if ($last_node->parentNode !== null) {
3146 $last_node->parentNode->removeChild($last_node);
3149 $node->appendChild($last_node);
3159 if ($last_node->parentNode !== null) {
3160 $last_node->parentNode->removeChild($last_node);
3163 $common_ancestor->appendChild($last_node);
3167 $clone = $formatting_element->cloneNode();
3172 while ($furthest_block->hasChildNodes()) {
3173 $child = $furthest_block->firstChild;
3174 $furthest_block->removeChild($child);
3175 $clone->appendChild($child);
3179 $furthest_block->appendChild($clone);
3185 $fe_af_pos = array_search($formatting_element, $this->a_formatting,
true);
3186 unset($this->a_formatting[$fe_af_pos]);
3187 $this->a_formatting = array_merge($this->a_formatting);
3189 $af_part1 = array_slice($this->a_formatting, 0, $bookmark - 1);
3190 $af_part2 = array_slice($this->a_formatting, $bookmark, count($this->a_formatting));
3191 $this->a_formatting = array_merge($af_part1,
array($clone), $af_part2);
3198 $fe_s_pos = array_search($formatting_element, $this->stack,
true);
3199 $fb_s_pos = array_search($furthest_block, $this->stack,
true);
3200 unset($this->stack[$fe_s_pos]);
3202 $s_part1 = array_slice($this->stack, 0, $fb_s_pos);
3203 $s_part2 = array_slice($this->stack, $fb_s_pos + 1, count($this->stack));
3204 $this->stack = array_merge($s_part1,
array($clone), $s_part2);
3207 unset($formatting_element, $fe_af_pos, $fe_s_pos, $furthest_block);
3219 if ($this->elementInScope($token[
'name'])) {
3220 $this->generateImpliedEndTags();
3231 for (
$n = count($this->stack) - 1;
$n >= 0;
$n--) {
3232 if ($this->stack[
$n]->nodeName === $token[
'name']) {
3236 array_pop($this->stack);
3239 $marker = end(array_keys($this->a_formatting, self::MARKER,
true));
3241 for (
$n = count($this->a_formatting) - 1;
$n > $marker;
$n--) {
3242 array_pop($this->a_formatting);
3275 for (
$n = count($this->stack) - 1;
$n >= 0;
$n--) {
3278 $node = end($this->stack);
3282 if ($token[
'name'] === $node->nodeName) {
3284 $this->generateImpliedEndTags();
3293 for (
$x = count($this->stack) -
$n;
$x >=
$n;
$x--) {
3294 array_pop($this->stack);
3298 $category = $this->getElementCategory($node);
3300 if ($category !== self::SPECIAL && $category !== self::SCOPING) {
3317 $clear =
array(
'html',
'table');
3323 preg_match(
'/^[\t\n\x0b\x0c ]+$/', $token[
'data'])
3326 $text = $this->dom->createTextNode($token[
'data']);
3327 end($this->stack)->appendChild(
$text);
3333 $comment = $this->dom->createComment($token[
'data']);
3334 end($this->stack)->appendChild(
$comment);
3338 $token[
'name'] ===
'caption' 3341 $this->clearStackToTableContext($clear);
3345 $this->a_formatting[] = self::MARKER;
3349 $this->insertElement($token);
3350 $this->mode = self::IN_CAPTION;
3354 $token[
'name'] ===
'colgroup' 3357 $this->clearStackToTableContext($clear);
3361 $this->insertElement($token);
3362 $this->mode = self::IN_CGROUP;
3366 $token[
'name'] ===
'col' 3370 'name' =>
'colgroup',
3376 $this->inColumnGroup($token);
3381 array(
'tbody',
'tfoot',
'thead')
3385 $this->clearStackToTableContext($clear);
3389 $this->insertElement($token);
3390 $this->mode = self::IN_TBODY;
3394 in_array($token[
'name'],
array(
'td',
'th',
'tr'))
3406 return $this->inTableBody($token);
3410 $token[
'name'] ===
'table' 3422 return $this->mainPhase($token);
3426 $token[
'name'] ===
'table' 3431 if (!$this->elementInScope($token[
'name'],
true)) {
3437 $this->generateImpliedEndTags();
3446 $current = end($this->stack)->nodeName;
3447 array_pop($this->stack);
3449 if ($current ===
'table') {
3455 $this->resetInsertionMode();
3488 end($this->stack)->nodeName,
3489 array(
'table',
'tbody',
'tfoot',
'thead',
'tr')
3503 for (
$n = count($this->stack) - 1;
$n >= 0;
$n--) {
3504 if ($this->stack[
$n]->nodeName ===
'table') {
3505 $table = $this->stack[
$n];
3510 if (isset($table) && $table->parentNode !== null) {
3511 $this->foster_parent = $table->parentNode;
3513 } elseif (!isset($table)) {
3514 $this->foster_parent = $this->stack[0];
3516 } elseif (isset($table) && ($table->parentNode === null ||
3517 $table->parentNode->nodeType !== XML_ELEMENT_NODE)
3519 $this->foster_parent = $this->stack[
$n - 1];
3523 $this->inBody($token);
3530 if ($token[
'type'] ===
HTML5::ENDTAG && $token[
'name'] ===
'caption') {
3534 if (!$this->elementInScope($token[
'name'],
true)) {
3540 $this->generateImpliedEndTags();
3549 $node = end($this->stack)->nodeName;
3550 array_pop($this->stack);
3552 if ($node ===
'caption') {
3559 $this->clearTheActiveFormattingElementsUpToTheLastMarker();
3562 $this->mode = self::IN_TABLE;
3582 $token[
'name'] ===
'table')
3589 'name' =>
'caption',
3594 return $this->inTable($token);
3618 $this->inBody($token);
3628 preg_match(
'/^[\t\n\x0b\x0c ]+$/', $token[
'data'])
3631 $text = $this->dom->createTextNode($token[
'data']);
3632 end($this->stack)->appendChild(
$text);
3638 $comment = $this->dom->createComment($token[
'data']);
3639 end($this->stack)->appendChild(
$comment);
3642 } elseif ($token[
'type'] ===
HTML5::STARTTAG && $token[
'name'] ===
'col') {
3645 $this->insertElement($token);
3646 array_pop($this->stack);
3650 $token[
'name'] ===
'colgroup' 3654 if (end($this->stack)->nodeName ===
'html') {
3661 array_pop($this->stack);
3662 $this->mode = self::IN_TABLE;
3666 } elseif ($token[
'type'] ===
HTML5::ENDTAG && $token[
'name'] ===
'col') {
3673 $this->inColumnGroup(
3675 'name' =>
'colgroup',
3680 return $this->inTable($token);
3686 $clear =
array(
'tbody',
'tfoot',
'thead',
'html');
3691 $this->clearStackToTableContext($clear);
3695 $this->insertElement($token);
3696 $this->mode = self::IN_ROW;
3700 ($token[
'name'] ===
'th' || $token[
'name'] ===
'td')
3712 return $this->inRow($token);
3716 in_array($token[
'name'],
array(
'tbody',
'tfoot',
'thead'))
3721 if (!$this->elementInScope($token[
'name'],
true)) {
3727 $this->clearStackToTableContext($clear);
3731 array_pop($this->stack);
3732 $this->mode = self::IN_TABLE;
3739 array(
'caption',
'col',
'colgroup',
'tbody',
'tfoor',
'thead')
3746 if (!$this->elementInScope(
array(
'tbody',
'thead',
'tfoot'),
true)) {
3752 $this->clearStackToTableContext($clear);
3759 'name' => end($this->stack)->nodeName,
3764 return $this->mainPhase($token);
3771 array(
'body',
'caption',
'col',
'colgroup',
'html',
'td',
'th',
'tr')
3779 $this->inTable($token);
3785 $clear =
array(
'tr',
'html');
3789 ($token[
'name'] ===
'th' || $token[
'name'] ===
'td')
3792 $this->clearStackToTableContext($clear);
3796 $this->insertElement($token);
3797 $this->mode = self::IN_CELL;
3801 $this->a_formatting[] = self::MARKER;
3804 } elseif ($token[
'type'] ===
HTML5::ENDTAG && $token[
'name'] ===
'tr') {
3808 if (!$this->elementInScope($token[
'name'],
true)) {
3814 $this->clearStackToTableContext($clear);
3819 array_pop($this->stack);
3820 $this->mode = self::IN_TBODY;
3827 array(
'caption',
'col',
'colgroup',
'tbody',
'tfoot',
'thead',
'tr')
3839 return $this->inCell($token);
3843 in_array($token[
'name'],
array(
'tbody',
'tfoot',
'thead'))
3848 if (!$this->elementInScope($token[
'name'],
true)) {
3862 return $this->inCell($token);
3869 array(
'body',
'caption',
'col',
'colgroup',
'html',
'td',
'th',
'tr')
3877 $this->inTable($token);
3885 ($token[
'name'] ===
'td' || $token[
'name'] ===
'th')
3890 if (!$this->elementInScope($token[
'name'],
true)) {
3897 $this->generateImpliedEndTags(
array($token[
'name']));
3906 $node = end($this->stack)->nodeName;
3907 array_pop($this->stack);
3909 if ($node === $token[
'name']) {
3916 $this->clearTheActiveFormattingElementsUpToTheLastMarker();
3920 $this->mode = self::IN_ROW;
3943 if (!$this->elementInScope(
array(
'td',
'th'),
true)) {
3950 return $this->inRow($token);
3973 if (!$this->elementInScope(
array(
'td',
'th'),
true)) {
3980 return $this->inRow($token);
3987 array(
'body',
'caption',
'col',
'colgroup',
'html')
3996 array(
'table',
'tbody',
'tfoot',
'thead',
'tr')
4003 if (!$this->elementInScope($token[
'name'],
true)) {
4010 return $this->inRow($token);
4016 $this->inBody($token);
4027 $this->insertText($token[
'data']);
4033 $this->insertComment($token[
'data']);
4037 $token[
'name'] ===
'option' 4041 if (end($this->stack)->nodeName ===
'option') {
4051 $this->insertElement($token);
4055 $token[
'name'] ===
'optgroup' 4059 if (end($this->stack)->nodeName ===
'option') {
4070 if (end($this->stack)->nodeName ===
'optgroup') {
4073 'name' =>
'optgroup',
4080 $this->insertElement($token);
4084 $token[
'name'] ===
'optgroup' 4090 $elements_in_stack = count($this->stack);
4092 if ($this->stack[$elements_in_stack - 1]->nodeName ===
'option' &&
4093 $this->stack[$elements_in_stack - 2]->nodeName ===
'optgroup' 4106 if ($this->stack[$elements_in_stack - 1] ===
'optgroup') {
4107 array_pop($this->stack);
4112 $token[
'name'] ===
'option' 4117 if (end($this->stack)->nodeName ===
'option') {
4118 array_pop($this->stack);
4123 $token[
'name'] ===
'select' 4128 if (!$this->elementInScope($token[
'name'],
true)) {
4136 $current = end($this->stack)->nodeName;
4137 array_pop($this->stack);
4139 if ($current ===
'select') {
4145 $this->resetInsertionMode();
4149 } elseif ($token[
'name'] ===
'select' &&
4184 if ($this->elementInScope($token[
'name'],
true)) {
4192 $this->mainPhase($token);
4209 preg_match(
'/^[\t\n\x0b\x0c ]+$/', $token[
'data'])
4213 $this->inBody($token);
4220 $comment = $this->dom->createComment($token[
'data']);
4221 $this->stack[0]->appendChild(
$comment);
4224 } elseif ($token[
'type'] ===
HTML5::ENDTAG && $token[
'name'] ===
'html') {
4231 $this->phase = self::END_PHASE;
4237 $this->mode = self::IN_BODY;
4238 return $this->inBody($token);
4250 preg_match(
'/^[\t\n\x0b\x0c ]+$/', $token[
'data'])
4253 $this->insertText($token[
'data']);
4259 $this->insertComment($token[
'data']);
4262 } elseif ($token[
'name'] ===
'frameset' &&
4265 $this->insertElement($token);
4268 } elseif ($token[
'name'] ===
'frameset' &&
4273 if (end($this->stack)->nodeName ===
'html') {
4279 array_pop($this->stack);
4285 $this->mode = self::AFTR_FRAME;
4289 } elseif ($token[
'name'] ===
'frame' &&
4293 $this->insertElement($token);
4296 array_pop($this->stack);
4299 } elseif ($token[
'name'] ===
'noframes' &&
4303 $this->inBody($token);
4319 preg_match(
'/^[\t\n\x0b\x0c ]+$/', $token[
'data'])
4322 $this->insertText($token[
'data']);
4328 $this->insertComment($token[
'data']);
4331 } elseif ($token[
'name'] ===
'html' &&
4335 $this->phase = self::END_PHASE;
4338 } elseif ($token[
'name'] ===
'noframes' &&
4342 $this->inBody($token);
4363 $comment = $this->dom->createComment($token[
'data']);
4370 preg_match(
'/^[\t\n\x0b\x0c ]+$/', $token[
'data'])
4373 $this->mainPhase($token);
4379 preg_match(
'/^[\t\n\x0b\x0c ]+$/', $token[
'data'])) ||
4384 $this->phase = self::MAIN_PHASE;
4385 return $this->mainPhase($token);
4399 $token[
'name'] = preg_replace(
'/[^a-z0-9-]/i',
'', $token[
'name']);
4401 $token[
'name'] = ltrim($token[
'name'],
'-0..9');
4403 if ($token[
'name'] ===
'') {
4404 $token[
'name'] =
'span';
4408 $el = $this->dom->createElement($token[
'name']);
4410 foreach ($token[
'attr'] as $attr) {
4411 if (!$el->hasAttribute($attr[
'name'])) {
4412 $el->setAttribute($attr[
'name'], $attr[
'value']);
4416 $this->appendToRealParent($el);
4417 $this->stack[] = $el;
4425 $this->appendToRealParent(
$text);
4431 $this->appendToRealParent(
$comment);
4436 if ($this->foster_parent === null) {
4437 end($this->stack)->appendChild($node);
4439 } elseif ($this->foster_parent !== null) {
4446 for (
$n = count($this->stack) - 1;
$n >= 0;
$n--) {
4447 if ($this->stack[
$n]->nodeName ===
'table' &&
4448 $this->stack[
$n]->parentNode !== null
4450 $table = $this->stack[
$n];
4455 if (isset($table) && $this->foster_parent->isSameNode($table->parentNode)) {
4456 $this->foster_parent->insertBefore($node, $table);
4458 $this->foster_parent->appendChild($node);
4461 $this->foster_parent = null;
4467 if (is_array($el)) {
4468 foreach ($el as $element) {
4469 if ($this->elementInScope($element, $table)) {
4477 $leng = count($this->stack);
4479 for (
$n = 0;
$n < $leng;
$n++) {
4482 $node = $this->stack[$leng - 1 -
$n];
4484 if ($node->tagName === $el) {
4488 } elseif ($node->tagName ===
'table') {
4493 } elseif ($table ===
true && in_array(
4510 } elseif ($node === $node->ownerDocument->documentElement) {
4529 $formatting_elements = count($this->a_formatting);
4531 if ($formatting_elements === 0) {
4537 $entry = end($this->a_formatting);
4543 if ($entry === self::MARKER || in_array($entry, $this->stack,
true)) {
4547 for ($a = $formatting_elements - 1; $a >= 0;
true) {
4551 $step_seven =
false;
4558 $entry = $this->a_formatting[$a];
4562 if ($entry === self::MARKER || in_array($entry, $this->stack,
true)) {
4570 if (isset($step_seven) && $step_seven ===
true) {
4572 $entry = $this->a_formatting[$a];
4576 $clone = $entry->cloneNode();
4580 end($this->stack)->appendChild($clone);
4581 $this->stack[] = $clone;
4585 $this->a_formatting[$a] = $clone;
4589 if (end($this->a_formatting) !== $clone) {
4606 $entry = end($this->a_formatting);
4609 array_pop($this->a_formatting);
4613 if ($entry === self::MARKER) {
4626 $node = end($this->stack);
4627 $elements = array_diff(
array(
'dd',
'dt',
'li',
'p',
'td',
'th',
'tr'),
$exclude);
4629 while (in_array(end($this->stack)->nodeName, $elements)) {
4630 array_pop($this->stack);
4636 $name = $node->tagName;
4637 if (in_array($name, $this->special)) {
4638 return self::SPECIAL;
4639 } elseif (in_array($name, $this->scoping)) {
4640 return self::SCOPING;
4641 } elseif (in_array($name, $this->
formatting)) {
4642 return self::FORMATTING;
4644 return self::PHRASING;
4656 $node = end($this->stack)->nodeName;
4658 if (in_array($node, $elements)) {
4661 array_pop($this->stack);
4670 $leng = count($this->stack);
4672 for (
$n = $leng - 1;
$n >= 0;
$n--) {
4674 $node = $this->stack[
$n];
4680 if ($this->stack[0]->isSameNode($node)) {
4686 if ($node->nodeName ===
'select') {
4687 $this->mode = self::IN_SELECT;
4692 } elseif ($node->nodeName ===
'td' || $node->nodeName ===
'th') {
4693 $this->mode = self::IN_CELL;
4698 } elseif ($node->nodeName ===
'tr') {
4699 $this->mode = self::IN_ROW;
4704 } elseif (in_array($node->nodeName,
array(
'tbody',
'thead',
'tfoot'))) {
4705 $this->mode = self::IN_TBODY;
4710 } elseif ($node->nodeName ===
'caption') {
4711 $this->mode = self::IN_CAPTION;
4716 } elseif ($node->nodeName ===
'colgroup') {
4717 $this->mode = self::IN_CGROUP;
4722 } elseif ($node->nodeName ===
'table') {
4723 $this->mode = self::IN_TABLE;
4729 } elseif ($node->nodeName ===
'head') {
4730 $this->mode = self::IN_BODY;
4735 } elseif ($node->nodeName ===
'body') {
4736 $this->mode = self::IN_BODY;
4741 } elseif ($node->nodeName ===
'frameset') {
4742 $this->mode = self::IN_FRAME;
4749 } elseif ($node->nodeName ===
'html') {
4750 $this->mode = ($this->head_pointer === null)
4759 $this->mode = self::IN_BODY;
4769 foreach (
array(
'td',
'th') as $cell) {
4770 if ($this->elementInScope($cell,
true)) {
tokenizeDOM($node, &$tokens)
Iterative function that tokenizes a node, putting it into an accumulator.
attributeValueUnquotedState()
attributeValueSingleQuotedState()
getElementCategory($node)
wrapHTML($html, $config, $context)
Wraps an HTML fragment in the necessary HTML.
Experimental HTML5-based parser using Jeroen van der Meer's PH5P library.
clearTheActiveFormattingElementsUpToTheLastMarker()
characters($char_class, $start)
markupDeclarationOpenState()
Parser that uses PHP 5's DOM extension (part of the core).
tokenizeHTML($html, $config, $context)
beforeAttributeValueState()
Our in-house implementation of a parser.
generateImpliedEndTags($exclude=array())
entityInAttributeValueState()
clearStackToTableContext($elements)
elementInScope($el, $table=false)
normalize($html, $config, $context)
Takes a piece of HTML and normalizes it by converting entities, fixing encoding, extracting bits...
insertElement($token, $append=true, $check=false)
Create styles array
The data for the language used.
appendToRealParent($node)
afterAttributeNameState()
attributeValueDoubleQuotedState()
beforeAttributeNameState()
reconstructActiveFormattingElements()
const EOF
How fgetc() reports an End Of File.