12 private $entities =
array(
'AElig;',
'AElig',
'AMP;',
'AMP',
'Aacute;',
'Aacute',
13 'Acirc;',
'Acirc',
'Agrave;',
'Agrave',
'Alpha;',
'Aring;',
'Aring',
'Atilde;',
14 'Atilde',
'Auml;',
'Auml',
'Beta;',
'COPY;',
'COPY',
'Ccedil;',
'Ccedil',
'Chi;',
15 'Dagger;',
'Delta;',
'ETH;',
'ETH',
'Eacute;',
'Eacute',
'Ecirc;',
'Ecirc',
'Egrave;',
16 'Egrave',
'Epsilon;',
'Eta;',
'Euml;',
'Euml',
'GT;',
'GT',
'Gamma;',
'Iacute;',
17 'Iacute',
'Icirc;',
'Icirc',
'Igrave;',
'Igrave',
'Iota;',
'Iuml;',
'Iuml',
'Kappa;',
18 'LT;',
'LT',
'Lambda;',
'Mu;',
'Ntilde;',
'Ntilde',
'Nu;',
'OElig;',
'Oacute;',
19 'Oacute',
'Ocirc;',
'Ocirc',
'Ograve;',
'Ograve',
'Omega;',
'Omicron;',
'Oslash;',
20 'Oslash',
'Otilde;',
'Otilde',
'Ouml;',
'Ouml',
'Phi;',
'Pi;',
'Prime;',
'Psi;',
21 'QUOT;',
'QUOT',
'REG;',
'REG',
'Rho;',
'Scaron;',
'Sigma;',
'THORN;',
'THORN',
22 'TRADE;',
'Tau;',
'Theta;',
'Uacute;',
'Uacute',
'Ucirc;',
'Ucirc',
'Ugrave;',
23 'Ugrave',
'Upsilon;',
'Uuml;',
'Uuml',
'Xi;',
'Yacute;',
'Yacute',
'Yuml;',
'Zeta;',
24 'aacute;',
'aacute',
'acirc;',
'acirc',
'acute;',
'acute',
'aelig;',
'aelig',
25 'agrave;',
'agrave',
'alefsym;',
'alpha;',
'amp;',
'amp',
'and;',
'ang;',
'apos;',
26 'aring;',
'aring',
'asymp;',
'atilde;',
'atilde',
'auml;',
'auml',
'bdquo;',
'beta;',
27 'brvbar;',
'brvbar',
'bull;',
'cap;',
'ccedil;',
'ccedil',
'cedil;',
'cedil',
28 'cent;',
'cent',
'chi;',
'circ;',
'clubs;',
'cong;',
'copy;',
'copy',
'crarr;',
29 'cup;',
'curren;',
'curren',
'dArr;',
'dagger;',
'darr;',
'deg;',
'deg',
'delta;',
30 'diams;',
'divide;',
'divide',
'eacute;',
'eacute',
'ecirc;',
'ecirc',
'egrave;',
31 'egrave',
'empty;',
'emsp;',
'ensp;',
'epsilon;',
'equiv;',
'eta;',
'eth;',
'eth',
32 'euml;',
'euml',
'euro;',
'exist;',
'fnof;',
'forall;',
'frac12;',
'frac12',
33 'frac14;',
'frac14',
'frac34;',
'frac34',
'frasl;',
'gamma;',
'ge;',
'gt;',
'gt',
34 'hArr;',
'harr;',
'hearts;',
'hellip;',
'iacute;',
'iacute',
'icirc;',
'icirc',
35 'iexcl;',
'iexcl',
'igrave;',
'igrave',
'image;',
'infin;',
'int;',
'iota;',
36 'iquest;',
'iquest',
'isin;',
'iuml;',
'iuml',
'kappa;',
'lArr;',
'lambda;',
'lang;',
37 'laquo;',
'laquo',
'larr;',
'lceil;',
'ldquo;',
'le;',
'lfloor;',
'lowast;',
'loz;',
38 'lrm;',
'lsaquo;',
'lsquo;',
'lt;',
'lt',
'macr;',
'macr',
'mdash;',
'micro;',
'micro',
39 'middot;',
'middot',
'minus;',
'mu;',
'nabla;',
'nbsp;',
'nbsp',
'ndash;',
'ne;',
40 'ni;',
'not;',
'not',
'notin;',
'nsub;',
'ntilde;',
'ntilde',
'nu;',
'oacute;',
41 'oacute',
'ocirc;',
'ocirc',
'oelig;',
'ograve;',
'ograve',
'oline;',
'omega;',
42 'omicron;',
'oplus;',
'or;',
'ordf;',
'ordf',
'ordm;',
'ordm',
'oslash;',
'oslash',
43 'otilde;',
'otilde',
'otimes;',
'ouml;',
'ouml',
'para;',
'para',
'part;',
'permil;',
44 'perp;',
'phi;',
'pi;',
'piv;',
'plusmn;',
'plusmn',
'pound;',
'pound',
'prime;',
45 'prod;',
'prop;',
'psi;',
'quot;',
'quot',
'rArr;',
'radic;',
'rang;',
'raquo;',
46 'raquo',
'rarr;',
'rceil;',
'rdquo;',
'real;',
'reg;',
'reg',
'rfloor;',
'rho;',
47 'rlm;',
'rsaquo;',
'rsquo;',
'sbquo;',
'scaron;',
'sdot;',
'sect;',
'sect',
'shy;',
48 'shy',
'sigma;',
'sigmaf;',
'sim;',
'spades;',
'sub;',
'sube;',
'sum;',
'sup1;',
49 'sup1',
'sup2;',
'sup2',
'sup3;',
'sup3',
'sup;',
'supe;',
'szlig;',
'szlig',
'tau;',
50 'there4;',
'theta;',
'thetasym;',
'thinsp;',
'thorn;',
'thorn',
'tilde;',
'times;',
51 'times',
'trade;',
'uArr;',
'uacute;',
'uacute',
'uarr;',
'ucirc;',
'ucirc',
52 'ugrave;',
'ugrave',
'uml;',
'uml',
'upsih;',
'upsilon;',
'uuml;',
'uuml',
'weierp;',
53 'xi;',
'yacute;',
'yacute',
'yen;',
'yen',
'yuml;',
'yuml',
'zeta;',
'zwj;',
'zwnj;');
69 $data = str_replace(
"\r\n",
"\n", $data);
70 $date = str_replace(
"\r", null, $data);
74 $this->
EOF = strlen($data);
76 $this->content_model = self::PCDATA;
78 $this->state =
'data';
80 while($this->state !== null) {
81 $this->{$this->state.
'State'}();
87 return $this->tree->save();
92 return ($this->char < $this->
EOF)
99 if($s + $l < $this->
EOF) {
101 return $this->
data[$s];
103 return substr($this->
data, $s,
$l);
110 return preg_replace(
'#^(['.$char_class.
']+).*#s',
'\\1', substr($this->
data,
$start));
119 if(
$char ===
'&' && ($this->content_model === self::PCDATA || $this->content_model === self::RCDATA)) {
124 $this->state =
'entityData';
126 } elseif(
$char ===
'-') {
133 if(($this->content_model === self::RCDATA || $this->content_model ===
134 self::CDATA) && $this->escape ===
false &&
135 $this->
char >= 3 && $this->
character($this->
char - 4, 4) ===
'<!--') {
136 $this->escape =
true;
142 'type' => self::CHARACTR,
147 } elseif(
$char ===
'<' && ($this->content_model === self::PCDATA ||
148 (($this->content_model === self::RCDATA ||
149 $this->content_model === self::CDATA) && $this->escape ===
false))) {
158 $this->state =
'tagOpen';
161 } elseif(
$char ===
'>') {
167 if(($this->content_model === self::RCDATA ||
168 $this->content_model === self::CDATA) && $this->escape ===
true &&
169 $this->
character($this->
char, 3) ===
'-->') {
170 $this->escape =
false;
176 'type' => self::CHARACTR,
180 } elseif($this->
char === $this->
EOF) {
185 } elseif($this->content_model === self::PLAINTEXT) {
190 'type' => self::CHARACTR,
191 'data' => substr($this->
data, $this->
char)
201 $len = strcspn($this->
data,
'<&', $this->
char);
202 $char = substr($this->
data, $this->
char, $len);
203 $this->
char += $len - 1;
206 'type' => self::CHARACTR,
210 $this->state =
'data';
217 $entity = $this->
entity();
221 $char = (!$entity) ?
'&' : $entity;
225 $this->state =
'data';
230 switch($this->content_model) {
238 if($this->
character($this->
char + 1) ===
'/') {
240 $this->state =
'closeTagOpen';
244 'type' => self::CHARACTR,
248 $this->state =
'data';
261 $this->state =
'markupDeclarationOpen';
263 } elseif(
$char ===
'/') {
266 $this->state =
'closeTagOpen';
268 } elseif(preg_match(
'/^[A-Za-z]$/',
$char)) {
274 $this->token =
array(
275 'name' => strtolower(
$char),
276 'type' => self::STARTTAG,
280 $this->state =
'tagName';
282 } elseif(
$char ===
'>') {
287 'type' => self::CHARACTR,
291 $this->state =
'data';
293 } elseif(
$char ===
'?') {
296 $this->state =
'bogusComment';
303 'type' => self::CHARACTR,
308 $this->state =
'data';
316 $next_node = strtolower($this->
characters(
'A-Za-z', $this->
char + 1));
317 $the_same = count($this->tree->stack) > 0 && $next_node === end($this->tree->stack)->nodeName;
319 if(($this->content_model === self::RCDATA || $this->content_model === self::CDATA) &&
320 (!$the_same || ($the_same && (!preg_match(
'/[\t\n\x0b\x0c >\/]/',
321 $this->
character($this->
char + 1 + strlen($next_node))) || $this->
EOF === $this->
char)))) {
338 'type' => self::CHARACTR,
342 $this->state =
'data';
351 if(preg_match(
'/^[A-Za-z]$/',
$char)) {
357 $this->token =
array(
358 'name' => strtolower(
$char),
359 'type' => self::ENDTAG
362 $this->state =
'tagName';
364 } elseif(
$char ===
'>') {
367 $this->state =
'data';
369 } elseif($this->
char === $this->
EOF) {
374 'type' => self::CHARACTR,
379 $this->state =
'data';
383 $this->state =
'bogusComment';
394 if(preg_match(
'/^[\t\n\x0b\x0c ]$/',
$char)) {
401 $this->state =
'beforeAttributeName';
403 } elseif(
$char ===
'>') {
407 $this->state =
'data';
409 } elseif($this->
char === $this->
EOF) {
416 $this->state =
'data';
418 } elseif(
$char ===
'/') {
422 $this->state =
'beforeAttributeName';
428 $this->token[
'name'] .= strtolower(
$char);
429 $this->state =
'tagName';
439 if(preg_match(
'/^[\t\n\x0b\x0c ]$/',
$char)) {
446 $this->state =
'beforeAttributeName';
448 } elseif(
$char ===
'>') {
452 $this->state =
'data';
454 } elseif(
$char ===
'/') {
458 $this->state =
'beforeAttributeName';
460 } elseif($this->
char === $this->
EOF) {
467 $this->state =
'data';
474 $this->token[
'attr'][] =
array(
475 'name' => strtolower(
$char),
479 $this->state =
'attributeName';
489 if(preg_match(
'/^[\t\n\x0b\x0c ]$/',
$char)) {
496 $this->state =
'afterAttributeName';
498 } elseif(
$char ===
'=') {
501 $this->state =
'beforeAttributeValue';
503 } elseif(
$char ===
'>') {
507 $this->state =
'data';
509 } elseif(
$char ===
'/' && $this->
character($this->
char + 1) !==
'>') {
513 $this->state =
'beforeAttributeName';
515 } elseif($this->
char === $this->
EOF) {
522 $this->state =
'data';
528 $last = count($this->token[
'attr']) - 1;
529 $this->token[
'attr'][$last][
'name'] .= strtolower(
$char);
531 $this->state =
'attributeName';
541 if(preg_match(
'/^[\t\n\x0b\x0c ]$/',
$char)) {
548 $this->state =
'afterAttributeName';
550 } elseif(
$char ===
'=') {
553 $this->state =
'beforeAttributeValue';
555 } elseif(
$char ===
'>') {
559 $this->state =
'data';
561 } elseif(
$char ===
'/' && $this->
character($this->
char + 1) !==
'>') {
565 $this->state =
'beforeAttributeName';
567 } elseif($this->
char === $this->
EOF) {
574 $this->state =
'data';
581 $this->token[
'attr'][] =
array(
582 'name' => strtolower(
$char),
586 $this->state =
'attributeName';
596 if(preg_match(
'/^[\t\n\x0b\x0c ]$/',
$char)) {
603 $this->state =
'beforeAttributeValue';
605 } elseif(
$char ===
'"') {
608 $this->state =
'attributeValueDoubleQuoted';
610 } elseif(
$char ===
'&') {
615 $this->state =
'attributeValueUnquoted';
617 } elseif(
$char ===
'\'') {
620 $this->state =
'attributeValueSingleQuoted';
622 } elseif(
$char ===
'>') {
626 $this->state =
'data';
632 $last = count($this->token[
'attr']) - 1;
633 $this->token[
'attr'][$last][
'value'] .=
$char;
635 $this->state =
'attributeValueUnquoted';
648 $this->state =
'beforeAttributeName';
650 } elseif(
$char ===
'&') {
655 } elseif($this->
char === $this->
EOF) {
662 $this->state =
'data';
668 $last = count($this->token[
'attr']) - 1;
669 $this->token[
'attr'][$last][
'value'] .=
$char;
671 $this->state =
'attributeValueDoubleQuoted';
684 $this->state =
'beforeAttributeName';
686 } elseif(
$char ===
'&') {
691 } elseif($this->
char === $this->
EOF) {
698 $this->state =
'data';
704 $last = count($this->token[
'attr']) - 1;
705 $this->token[
'attr'][$last][
'value'] .=
$char;
707 $this->state =
'attributeValueSingleQuoted';
717 if(preg_match(
'/^[\t\n\x0b\x0c ]$/',
$char)) {
724 $this->state =
'beforeAttributeName';
726 } elseif(
$char ===
'&') {
731 } elseif(
$char ===
'>') {
735 $this->state =
'data';
741 $last = count($this->token[
'attr']) - 1;
742 $this->token[
'attr'][$last][
'value'] .=
$char;
744 $this->state =
'attributeValueUnquoted';
751 $entity = $this->
entity();
776 'type' => self::COMMENT
779 $this->
char += strlen($data);
782 $this->state =
'data';
785 if($this->
char === $this->
EOF) {
786 $this->
char = $this->
EOF - 1;
795 if($this->
character($this->
char + 1, 2) ===
'--') {
797 $this->state =
'comment';
798 $this->token =
array(
800 'type' => self::COMMENT
806 } elseif(strtolower($this->
character($this->
char + 1, 7)) ===
'doctype') {
808 $this->state =
'doctype';
815 $this->state =
'bogusComment';
828 $this->state =
'commentDash';
831 } elseif($this->
char === $this->
EOF) {
836 $this->state =
'data';
842 $this->token[
'data'] .=
$char;
855 $this->state =
'commentEnd';
858 } elseif($this->
char === $this->
EOF) {
863 $this->state =
'data';
869 $this->token[
'data'] .=
'-'.$char;
870 $this->state =
'comment';
882 $this->state =
'data';
884 } elseif(
$char ===
'-') {
885 $this->token[
'data'] .=
'-';
887 } elseif($this->
char === $this->
EOF) {
890 $this->state =
'data';
893 $this->token[
'data'] .=
'--'.$char;
894 $this->state =
'comment';
904 if(preg_match(
'/^[\t\n\x0b\x0c ]$/',
$char)) {
905 $this->state =
'beforeDoctypeName';
909 $this->state =
'beforeDoctypeName';
919 if(preg_match(
'/^[\t\n\x0b\x0c ]$/',
$char)) {
922 } elseif(preg_match(
'/^[a-z]$/',
$char)) {
923 $this->token =
array(
924 'name' => strtoupper(
$char),
925 'type' => self::DOCTYPE,
929 $this->state =
'doctypeName';
931 } elseif(
$char ===
'>') {
934 'type' => self::DOCTYPE,
938 $this->state =
'data';
940 } elseif($this->
char === $this->
EOF) {
943 'type' => self::DOCTYPE,
948 $this->state =
'data';
951 $this->token =
array(
953 'type' => self::DOCTYPE,
957 $this->state =
'doctypeName';
967 if(preg_match(
'/^[\t\n\x0b\x0c ]$/',
$char)) {
968 $this->state =
'AfterDoctypeName';
970 } elseif(
$char ===
'>') {
972 $this->state =
'data';
974 } elseif(preg_match(
'/^[a-z]$/',
$char)) {
975 $this->token[
'name'] .= strtoupper(
$char);
977 } elseif($this->
char === $this->
EOF) {
980 $this->state =
'data';
983 $this->token[
'name'] .=
$char;
986 $this->token[
'error'] = ($this->token[
'name'] ===
'HTML')
997 if(preg_match(
'/^[\t\n\x0b\x0c ]$/',
$char)) {
1000 } elseif(
$char ===
'>') {
1002 $this->state =
'data';
1004 } elseif($this->
char === $this->
EOF) {
1007 $this->state =
'data';
1010 $this->token[
'error'] =
true;
1011 $this->state =
'bogusDoctype';
1023 $this->state =
'data';
1025 } elseif($this->
char === $this->
EOF) {
1028 $this->state =
'data';
1045 switch($this->
character($this->
char + 1)) {
1051 switch($this->
character($this->
char + 1)) {
1063 $char_class =
'0-9A-Fa-f';
1072 $char_class =
'0-9';
1081 $cond = strlen($e_name) > 0;
1091 $e_name = $this->
characters(
'0-9A-Za-z;', $this->
char + 1);
1092 $len = strlen($e_name);
1094 for($c = 1; $c <= $len; $c++) {
1095 $id = substr($e_name, 0, $c);
1098 if(in_array($id, $this->entities)) {
1104 $cond = isset($entity);
1118 return html_entity_decode(
'&'.$entity.
';', ENT_QUOTES,
'UTF-8');
1123 $emit = $this->tree->emitToken(
$token);
1126 $this->content_model = $emit;
1128 } elseif(
$token[
'type'] === self::ENDTAG) {
1129 $this->content_model = self::PCDATA;
1135 $this->state = null;
1136 $this->tree->emitToken(
array(
1144 public $stack =
array();
1149 private $foster_parent = null;
1150 private $a_formatting =
array();
1152 private $head_pointer = null;
1153 private $form_pointer = null;
1155 private $scoping =
array(
'button',
'caption',
'html',
'marquee',
'object',
'table',
'td',
'th');
1156 private $formatting =
array(
'a',
'b',
'big',
'em',
'font',
'i',
'nobr',
's',
'small',
'strike',
'strong',
'tt',
'u');
1157 private $special =
array(
'address',
'area',
'base',
'basefont',
'bgsound',
1158 'blockquote',
'body',
'br',
'center',
'col',
'colgroup',
'dd',
'dir',
'div',
'dl',
1159 'dt',
'embed',
'fieldset',
'form',
'frame',
'frameset',
'h1',
'h2',
'h3',
'h4',
'h5',
1160 'h6',
'head',
'hr',
'iframe',
'image',
'img',
'input',
'isindex',
'li',
'link',
1161 'listing',
'menu',
'meta',
'noembed',
'noframes',
'noscript',
'ol',
'optgroup',
1162 'option',
'p',
'param',
'plaintext',
'pre',
'script',
'select',
'spacer',
'style',
1163 'tbody',
'textarea',
'tfoot',
'thead',
'title',
'tr',
'ul',
'wbr');
1166 const INIT_PHASE = 0;
1167 const ROOT_PHASE = 1;
1168 const MAIN_PHASE = 2;
1169 const END_PHASE = 3;
1172 const BEFOR_HEAD = 0;
1174 const AFTER_HEAD = 2;
1177 const IN_CAPTION = 5;
1178 const IN_CGROUP = 6;
1182 const IN_SELECT = 10;
1183 const AFTER_BODY = 11;
1184 const IN_FRAME = 12;
1185 const AFTR_FRAME = 13;
1190 const FORMATTING = 2;
1197 $this->phase = self::INIT_PHASE;
1198 $this->mode = self::BEFOR_HEAD;
1201 $this->dom->encoding =
'UTF-8';
1202 $this->dom->preserveWhiteSpace =
true;
1203 $this->dom->substituteEntities =
true;
1204 $this->dom->strictErrorChecking =
false;
1210 switch($this->phase) {
1211 case self::INIT_PHASE:
return $this->initPhase(
$token);
break;
1212 case self::ROOT_PHASE:
return $this->rootElementPhase(
$token);
break;
1213 case self::MAIN_PHASE:
return $this->mainPhase(
$token);
break;
1214 case self::END_PHASE :
return $this->trailingEndPhase(
$token);
break;
1237 !preg_match(
'/^[\t\n\x0b\x0c ]+$/',
$token[
'data']))) {
1243 $this->phase = self::ROOT_PHASE;
1244 return $this->rootElementPhase(
$token);
1252 $doctype =
new DOMDocumentType(null, null,
'HTML');
1256 $this->phase = self::ROOT_PHASE;
1261 } elseif(isset(
$token[
'data']) && preg_match(
'/^[\t\n\x0b\x0c ]+$/',
1264 $text = $this->dom->createTextNode(
$token[
'data']);
1265 $this->dom->appendChild(
$text);
1289 preg_match(
'/^[\t\n\x0b\x0c ]+$/',
$token[
'data'])) {
1291 $text = $this->dom->createTextNode(
$token[
'data']);
1292 $this->dom->appendChild(
$text);
1301 !preg_match(
'/^[\t\n\x0b\x0c ]+$/',
$token[
'data'])) ||
1308 $html = $this->dom->createElement(
'html');
1309 $this->dom->appendChild(
$html);
1310 $this->stack[] =
$html;
1312 $this->phase = self::MAIN_PHASE;
1313 return $this->mainPhase(
$token);
1334 foreach(
$token[
'attr'] as $attr) {
1335 if(!$this->stack[0]->hasAttribute($attr[
'name'])) {
1336 $this->stack[0]->setAttribute($attr[
'name'], $attr[
'value']);
1343 $this->generateImpliedEndTags();
1348 switch($this->mode) {
1349 case self::BEFOR_HEAD:
return $this->beforeHead(
$token);
break;
1350 case self::IN_HEAD:
return $this->inHead(
$token);
break;
1351 case self::AFTER_HEAD:
return $this->afterHead(
$token);
break;
1352 case self::IN_BODY:
return $this->inBody(
$token);
break;
1353 case self::IN_TABLE:
return $this->inTable(
$token);
break;
1354 case self::IN_CAPTION:
return $this->inCaption(
$token);
break;
1355 case self::IN_CGROUP:
return $this->inColumnGroup(
$token);
break;
1356 case self::IN_TBODY:
return $this->inTableBody(
$token);
break;
1357 case self::IN_ROW:
return $this->inRow(
$token);
break;
1358 case self::IN_CELL:
return $this->inCell(
$token);
break;
1359 case self::IN_SELECT:
return $this->inSelect(
$token);
break;
1360 case self::AFTER_BODY:
return $this->afterBody(
$token);
break;
1361 case self::IN_FRAME:
return $this->inFrameset(
$token);
break;
1362 case self::AFTR_FRAME:
return $this->afterFrameset(
$token);
break;
1363 case self::END_PHASE:
return $this->trailingEndPhase(
$token);
break;
1376 preg_match(
'/^[\t\n\x0b\x0c ]+$/',
$token[
'data'])) {
1378 $this->insertText(
$token[
'data']);
1384 $this->insertComment(
$token[
'data']);
1390 $element = $this->insertElement(
$token);
1393 $this->head_pointer = $element;
1396 $this->mode = self::IN_HEAD;
1409 $this->beforeHead(
array(
1415 return $this->inHead(
$token);
1435 preg_match(
'/^[\t\n\x0b\x0c ]+$/',
$token[
'data'])) || (
1437 array(
'title',
'style',
'script')))) {
1439 $this->insertText(
$token[
'data']);
1445 $this->insertComment(
$token[
'data']);
1448 in_array(
$token[
'name'],
array(
'title',
'style',
'script'))) {
1449 array_pop($this->stack);
1457 if($this->head_pointer !== null) {
1458 $element = $this->insertElement(
$token,
false);
1459 $this->head_pointer->appendChild($element);
1462 $element = $this->insertElement(
$token);
1473 if($this->head_pointer !== null) {
1474 $element = $this->insertElement(
$token,
false);
1475 $this->head_pointer->appendChild($element);
1478 $this->insertElement(
$token);
1487 $element = $this->insertElement(
$token,
false);
1488 $this->head_pointer->appendChild($element);
1495 array(
'base',
'link',
'meta'))) {
1499 if($this->head_pointer !== null) {
1500 $element = $this->insertElement(
$token,
false);
1501 $this->head_pointer->appendChild($element);
1502 array_pop($this->stack);
1505 $this->insertElement(
$token);
1512 if($this->head_pointer->isSameNode(end($this->stack))) {
1513 array_pop($this->stack);
1521 $this->mode = self::AFTER_HEAD;
1532 if($this->head_pointer->isSameNode(end($this->stack))) {
1533 $this->inHead(
array(
1540 $this->mode = self::AFTER_HEAD;
1544 return $this->afterHead(
$token);
1556 preg_match(
'/^[\t\n\x0b\x0c ]+$/',
$token[
'data'])) {
1558 $this->insertText(
$token[
'data']);
1564 $this->insertComment(
$token[
'data']);
1569 $this->insertElement(
$token);
1572 $this->mode = self::IN_BODY;
1577 $this->insertElement(
$token);
1580 $this->mode = self::IN_FRAME;
1585 array(
'base',
'link',
'meta',
'script',
'style',
'title'))) {
1588 $this->mode = self::IN_HEAD;
1589 return $this->inHead(
$token);
1595 $this->afterHead(
array(
1601 return $this->inBody(
$token);
1613 $this->reconstructActiveFormattingElements();
1616 $this->insertText(
$token[
'data']);
1623 $this->insertComment(
$token[
'data']);
1630 case 'script':
case 'style':
1633 return $this->inHead(
$token);
1638 case 'base':
case 'link':
case 'meta':
case 'title':
1641 return $this->inHead(
$token);
1650 if(count($this->stack) === 1 || $this->stack[1]->nodeName !==
'body') {
1659 foreach(
$token[
'attr'] as $attr) {
1660 if(!$this->stack[1]->hasAttribute($attr[
'name'])) {
1661 $this->stack[1]->setAttribute($attr[
'name'], $attr[
'value']);
1670 case 'address':
case 'blockquote':
case 'center':
case 'dir':
1671 case 'div':
case 'dl':
case 'fieldset':
case 'listing':
1672 case 'menu':
case 'ol':
case 'p':
case 'ul':
1676 if($this->elementInScope(
'p')) {
1684 $this->insertElement(
$token);
1691 if($this->form_pointer !== null) {
1699 if($this->elementInScope(
'p')) {
1708 $element = $this->insertElement(
$token);
1709 $this->form_pointer = $element;
1714 case 'li':
case 'dd':
case 'dt':
1718 if($this->elementInScope(
'p')) {
1725 $stack_length = count($this->stack) - 1;
1727 for(
$n = $stack_length; 0 <=
$n;
$n--) {
1731 $node = $this->stack[
$n];
1732 $cat = $this->getElementCategory($node->tagName);
1737 if(
$token[
'name'] === $node->tagName || (
$token[
'name'] !==
'li' 1738 && ($node->tagName ===
'dd' || $node->tagName ===
'dt'))) {
1739 for(
$x = $stack_length;
$x >=
$n ;
$x--) {
1740 array_pop($this->stack);
1749 if($cat !== self::FORMATTING && $cat !== self::PHRASING &&
1750 $node->tagName !==
'address' && $node->tagName !==
'div') {
1757 $this->insertElement(
$token);
1765 if($this->elementInScope(
'p')) {
1773 $this->insertElement(
$token);
1780 case 'h1':
case 'h2':
case 'h3':
case 'h4':
case 'h5':
case 'h6':
1783 if($this->elementInScope(
'p')) {
1795 while($this->elementInScope(
array(
'h1',
'h2',
'h3',
'h4',
'h5',
'h6'))) {
1796 array_pop($this->stack);
1800 $this->insertElement(
$token);
1814 $leng = count($this->a_formatting);
1816 for(
$n = $leng - 1;
$n >= 0;
$n--) {
1817 if($this->a_formatting[
$n] === self::MARKER) {
1820 } elseif($this->a_formatting[
$n]->nodeName ===
'a') {
1830 $this->reconstructActiveFormattingElements();
1833 $el = $this->insertElement(
$token);
1837 $this->a_formatting[] = $el;
1842 case 'b':
case 'big':
case 'em':
case 'font':
case 'i':
1843 case 'nobr':
case 's':
case 'small':
case 'strike':
1844 case 'strong':
case 'tt':
case 'u':
1846 $this->reconstructActiveFormattingElements();
1849 $el = $this->insertElement(
$token);
1853 $this->a_formatting[] = $el;
1862 if($this->elementInScope(
'button')) {
1863 $this->inBody(
array(
1870 $this->reconstructActiveFormattingElements();
1873 $this->insertElement(
$token);
1877 $this->a_formatting[] = self::MARKER;
1881 case 'marquee':
case 'object':
1883 $this->reconstructActiveFormattingElements();
1886 $this->insertElement(
$token);
1890 $this->a_formatting[] = self::MARKER;
1896 $this->reconstructActiveFormattingElements();
1899 $this->insertElement(
$token);
1909 if($this->elementInScope(
'p')) {
1917 $this->insertElement(
$token);
1920 $this->mode = self::IN_TABLE;
1925 case 'area':
case 'basefont':
case 'bgsound':
case 'br':
1926 case 'embed':
case 'img':
case 'param':
case 'spacer':
1929 $this->reconstructActiveFormattingElements();
1932 $this->insertElement(
$token);
1935 array_pop($this->stack);
1942 if($this->elementInScope(
'p')) {
1950 $this->insertElement(
$token);
1953 array_pop($this->stack);
1961 return $this->inBody(
$token);
1967 $this->reconstructActiveFormattingElements();
1970 $element = $this->insertElement(
$token,
false);
1975 $this->form_pointer !== null
1976 ? $this->form_pointer->appendChild($element)
1977 : end($this->stack)->appendChild($element);
1980 array_pop($this->stack);
1990 if($this->form_pointer === null) {
1993 $this->inBody(
array(
2001 $this->inBody(
array(
2009 $this->inBody(
array(
2017 $this->inBody(
array(
2024 $this->insertText(
'This is a searchable index. '.
2025 'Insert your search keywords here: ');
2032 $attr[] =
array(
'name' =>
'name',
'value' =>
'isindex');
2034 $this->inBody(
array(
2042 $this->insertText(
'This is a searchable index. '.
2043 'Insert your search keywords here: ');
2047 $this->inBody(
array(
2054 $this->inBody(
array(
2061 $this->inBody(
array(
2068 $this->inBody(
array(
2077 $this->insertElement(
$token);
2086 case 'iframe':
case 'noembed':
case 'noframes':
2087 $this->insertElement(
$token);
2096 $this->reconstructActiveFormattingElements();
2099 $this->insertElement(
$token);
2102 $this->mode = self::IN_SELECT;
2108 case 'caption':
case 'col':
case 'colgroup':
case 'frame':
2109 case 'frameset':
case 'head':
case 'option':
case 'optgroup':
2110 case 'tbody':
case 'td':
case 'tfoot':
case 'th':
case 'thead':
2118 case 'event-source':
case 'section':
case 'nav':
case 'article':
2119 case 'aside':
case 'header':
case 'footer':
case 'datagrid':
2127 $this->reconstructActiveFormattingElements();
2129 $this->insertElement(
$token);
2141 if(count($this->stack) < 2 || $this->stack[1]->nodeName !==
'body') {
2146 } elseif(end($this->stack)->nodeName !==
'body') {
2151 $this->mode = self::AFTER_BODY;
2159 $this->inBody(
array(
2164 return $this->afterBody(
$token);
2170 case 'address':
case 'blockquote':
case 'center':
case 'dir':
2171 case 'div':
case 'dl':
case 'fieldset':
case 'listing':
2172 case 'menu':
case 'ol':
case 'pre':
case 'ul':
2176 if($this->elementInScope(
$token[
'name'])) {
2177 $this->generateImpliedEndTags();
2188 for(
$n = count($this->stack) - 1;
$n >= 0;
$n--) {
2189 if($this->stack[
$n]->nodeName ===
$token[
'name']) {
2193 array_pop($this->stack);
2203 if($this->elementInScope(
$token[
'name'])) {
2204 $this->generateImpliedEndTags();
2208 if(end($this->stack)->nodeName !==
$token[
'name']) {
2218 array_pop($this->stack);
2222 $this->form_pointer = null;
2229 if($this->elementInScope(
'p')) {
2230 $this->generateImpliedEndTags(
array(
'p'));
2239 for(
$n = count($this->stack) - 1;
$n >= 0;
$n--) {
2240 if($this->elementInScope(
'p')) {
2241 array_pop($this->stack);
2251 case 'dd':
case 'dt':
case 'li':
2256 if($this->elementInScope(
$token[
'name'])) {
2257 $this->generateImpliedEndTags(
array(
$token[
'name']));
2267 for(
$n = count($this->stack) - 1;
$n >= 0;
$n--) {
2268 if($this->stack[
$n]->nodeName ===
$token[
'name']) {
2272 array_pop($this->stack);
2279 case 'h1':
case 'h2':
case 'h3':
case 'h4':
case 'h5':
case 'h6':
2280 $elements =
array(
'h1',
'h2',
'h3',
'h4',
'h5',
'h6');
2285 if($this->elementInScope($elements)) {
2286 $this->generateImpliedEndTags();
2296 while($this->elementInScope($elements)) {
2297 array_pop($this->stack);
2304 case 'a':
case 'b':
case 'big':
case 'em':
case 'font':
2305 case 'i':
case 'nobr':
case 's':
case 'small':
case 'strike':
2306 case 'strong':
case 'tt':
case 'u':
2315 for($a = count($this->a_formatting) - 1; $a >= 0; $a--) {
2316 if($this->a_formatting[$a] === self::MARKER) {
2319 } elseif($this->a_formatting[$a]->tagName ===
$token[
'name']) {
2320 $formatting_element = $this->a_formatting[$a];
2321 $in_stack = in_array($formatting_element, $this->stack,
true);
2331 if(!isset($formatting_element) || ($in_stack &&
2332 !$this->elementInScope(
$token[
'name']))) {
2339 } elseif(isset($formatting_element) && !$in_stack) {
2340 unset($this->a_formatting[$fe_af_pos]);
2341 $this->a_formatting = array_merge($this->a_formatting);
2350 $fe_s_pos = array_search($formatting_element, $this->stack,
true);
2351 $length = count($this->stack);
2353 for($s = $fe_s_pos + 1; $s < $length; $s++) {
2354 $category = $this->getElementCategory($this->stack[$s]->nodeName);
2356 if($category !== self::PHRASING && $category !== self::FORMATTING) {
2357 $furthest_block = $this->stack[$s];
2367 if(!isset($furthest_block)) {
2368 for(
$n = $length - 1;
$n >= $fe_s_pos;
$n--) {
2369 array_pop($this->stack);
2372 unset($this->a_formatting[$fe_af_pos]);
2373 $this->a_formatting = array_merge($this->a_formatting);
2380 $common_ancestor = $this->stack[$fe_s_pos - 1];
2384 if($furthest_block->parentNode !== null) {
2385 $furthest_block->parentNode->removeChild($furthest_block);
2392 $bookmark = $fe_af_pos;
2396 $node = $furthest_block;
2397 $last_node = $furthest_block;
2400 for(
$n = array_search($node, $this->stack,
true) - 1;
$n >= 0;
$n--) {
2403 $node = $this->stack[
$n];
2409 if(!in_array($node, $this->a_formatting,
true)) {
2410 unset($this->stack[
$n]);
2411 $this->stack = array_merge($this->stack);
2421 if($node === $formatting_element) {
2428 } elseif($last_node === $furthest_block) {
2429 $bookmark = array_search($node, $this->a_formatting,
true) + 1;
2438 if($node->hasChildNodes()) {
2439 $clone = $node->cloneNode();
2440 $s_pos = array_search($node, $this->stack,
true);
2441 $a_pos = array_search($node, $this->a_formatting,
true);
2443 $this->stack[$s_pos] = $clone;
2444 $this->a_formatting[$a_pos] = $clone;
2450 if($last_node->parentNode !== null) {
2451 $last_node->parentNode->removeChild($last_node);
2454 $node->appendChild($last_node);
2464 if($last_node->parentNode !== null) {
2465 $last_node->parentNode->removeChild($last_node);
2468 $common_ancestor->appendChild($last_node);
2472 $clone = $formatting_element->cloneNode();
2477 while($furthest_block->hasChildNodes()) {
2478 $child = $furthest_block->firstChild;
2479 $furthest_block->removeChild($child);
2480 $clone->appendChild($child);
2484 $furthest_block->appendChild($clone);
2490 $fe_af_pos = array_search($formatting_element, $this->a_formatting,
true);
2491 unset($this->a_formatting[$fe_af_pos]);
2492 $this->a_formatting = array_merge($this->a_formatting);
2494 $af_part1 = array_slice($this->a_formatting, 0, $bookmark - 1);
2495 $af_part2 = array_slice($this->a_formatting, $bookmark, count($this->a_formatting));
2496 $this->a_formatting = array_merge($af_part1,
array($clone), $af_part2);
2503 $fe_s_pos = array_search($formatting_element, $this->stack,
true);
2504 $fb_s_pos = array_search($furthest_block, $this->stack,
true);
2505 unset($this->stack[$fe_s_pos]);
2507 $s_part1 = array_slice($this->stack, 0, $fb_s_pos);
2508 $s_part2 = array_slice($this->stack, $fb_s_pos + 1, count($this->stack));
2509 $this->stack = array_merge($s_part1,
array($clone), $s_part2);
2512 unset($formatting_element, $fe_af_pos, $fe_s_pos, $furthest_block);
2518 case 'button':
case 'marquee':
case 'object':
2522 if($this->elementInScope(
$token[
'name'])) {
2523 $this->generateImpliedEndTags();
2534 for(
$n = count($this->stack) - 1;
$n >= 0;
$n--) {
2535 if($this->stack[
$n]->nodeName ===
$token[
'name']) {
2539 array_pop($this->stack);
2542 $marker = end(array_keys($this->a_formatting, self::MARKER,
true));
2544 for(
$n = count($this->a_formatting) - 1;
$n > $marker;
$n--) {
2545 array_pop($this->a_formatting);
2554 case 'area':
case 'basefont':
case 'bgsound':
case 'br':
2555 case 'embed':
case 'hr':
case 'iframe':
case 'image':
2556 case 'img':
case 'input':
case 'isindex':
case 'noembed':
2557 case 'noframes':
case 'param':
case 'select':
case 'spacer':
2558 case 'table':
case 'textarea':
case 'wbr':
2564 for(
$n = count($this->stack) - 1;
$n >= 0;
$n--) {
2567 $node = end($this->stack);
2571 if(
$token[
'name'] === $node->nodeName) {
2573 $this->generateImpliedEndTags();
2582 for(
$x = count($this->stack) -
$n;
$x >=
$n;
$x--) {
2583 array_pop($this->stack);
2587 $category = $this->getElementCategory($node);
2589 if($category !== self::SPECIAL && $category !== self::SCOPING) {
2606 $clear =
array(
'html',
'table');
2612 preg_match(
'/^[\t\n\x0b\x0c ]+$/',
$token[
'data'])) {
2614 $text = $this->dom->createTextNode(
$token[
'data']);
2615 end($this->stack)->appendChild(
$text);
2622 end($this->stack)->appendChild(
$comment);
2626 $token[
'name'] ===
'caption') {
2628 $this->clearStackToTableContext($clear);
2632 $this->a_formatting[] = self::MARKER;
2636 $this->insertElement(
$token);
2637 $this->mode = self::IN_CAPTION;
2641 $token[
'name'] ===
'colgroup') {
2643 $this->clearStackToTableContext($clear);
2647 $this->insertElement(
$token);
2648 $this->mode = self::IN_CGROUP;
2652 $token[
'name'] ===
'col') {
2653 $this->inTable(
array(
2654 'name' =>
'colgroup',
2659 $this->inColumnGroup(
$token);
2663 array(
'tbody',
'tfoot',
'thead'))) {
2665 $this->clearStackToTableContext($clear);
2669 $this->insertElement(
$token);
2670 $this->mode = self::IN_TBODY;
2674 in_array(
$token[
'name'],
array(
'td',
'th',
'tr'))) {
2677 $this->inTable(
array(
2683 return $this->inTableBody(
$token);
2687 $token[
'name'] ===
'table') {
2691 $this->inTable(
array(
2696 return $this->mainPhase(
$token);
2700 $token[
'name'] ===
'table') {
2704 if(!$this->elementInScope(
$token[
'name'],
true)) {
2710 $this->generateImpliedEndTags();
2719 $current = end($this->stack)->nodeName;
2720 array_pop($this->stack);
2722 if($current ===
'table') {
2728 $this->resetInsertionMode();
2734 array(
'body',
'caption',
'col',
'colgroup',
'html',
'tbody',
'td',
2735 'tfoot',
'th',
'thead',
'tr'))) {
2746 if(in_array(end($this->stack)->nodeName,
2747 array(
'table',
'tbody',
'tfoot',
'thead',
'tr'))) {
2759 for(
$n = count($this->stack) - 1;
$n >= 0;
$n--) {
2760 if($this->stack[
$n]->nodeName ===
'table') {
2761 $table = $this->stack[
$n];
2766 if(isset($table) && $table->parentNode !== null) {
2767 $this->foster_parent = $table->parentNode;
2769 } elseif(!isset($table)) {
2770 $this->foster_parent = $this->stack[0];
2772 } elseif(isset($table) && ($table->parentNode === null ||
2773 $table->parentNode->nodeType !== XML_ELEMENT_NODE)) {
2774 $this->foster_parent = $this->stack[
$n - 1];
2789 if(!$this->elementInScope(
$token[
'name'],
true)) {
2795 $this->generateImpliedEndTags();
2804 $node = end($this->stack)->nodeName;
2805 array_pop($this->stack);
2807 if($node ===
'caption') {
2814 $this->clearTheActiveFormattingElementsUpToTheLastMarker();
2817 $this->mode = self::IN_TABLE;
2824 array(
'caption',
'col',
'colgroup',
'tbody',
'td',
'tfoot',
'th',
2826 $token[
'name'] ===
'table')) {
2830 $this->inCaption(
array(
2831 'name' =>
'caption',
2835 return $this->inTable(
$token);
2840 array(
'body',
'col',
'colgroup',
'html',
'tbody',
'tfoot',
'th',
2857 preg_match(
'/^[\t\n\x0b\x0c ]+$/',
$token[
'data'])) {
2859 $text = $this->dom->createTextNode(
$token[
'data']);
2860 end($this->stack)->appendChild(
$text);
2867 end($this->stack)->appendChild(
$comment);
2873 $this->insertElement(
$token);
2874 array_pop($this->stack);
2878 $token[
'name'] ===
'colgroup') {
2881 if(end($this->stack)->nodeName ===
'html') {
2888 array_pop($this->stack);
2889 $this->mode = self::IN_TABLE;
2900 $this->inColumnGroup(
array(
2901 'name' =>
'colgroup',
2905 return $this->inTable(
$token);
2911 $clear =
array(
'tbody',
'tfoot',
'thead',
'html');
2916 $this->clearStackToTableContext($clear);
2920 $this->insertElement(
$token);
2921 $this->mode = self::IN_ROW;
2925 (
$token[
'name'] ===
'th' ||
$token[
'name'] ===
'td')) {
2928 $this->inTableBody(
array(
2934 return $this->inRow(
$token);
2938 in_array(
$token[
'name'],
array(
'tbody',
'tfoot',
'thead'))) {
2942 if(!$this->elementInScope(
$token[
'name'],
true)) {
2948 $this->clearStackToTableContext($clear);
2952 array_pop($this->stack);
2953 $this->mode = self::IN_TABLE;
2959 array(
'caption',
'col',
'colgroup',
'tbody',
'tfoor',
'thead'))) ||
2964 if(!$this->elementInScope(
array(
'tbody',
'thead',
'tfoot'),
true)) {
2970 $this->clearStackToTableContext($clear);
2975 $this->inTableBody(
array(
2976 'name' => end($this->stack)->nodeName,
2980 return $this->mainPhase(
$token);
2986 array(
'body',
'caption',
'col',
'colgroup',
'html',
'td',
'th',
'tr'))) {
2998 $clear =
array(
'tr',
'html');
3002 (
$token[
'name'] ===
'th' ||
$token[
'name'] ===
'td')) {
3004 $this->clearStackToTableContext($clear);
3008 $this->insertElement(
$token);
3009 $this->mode = self::IN_CELL;
3013 $this->a_formatting[] = self::MARKER;
3020 if(!$this->elementInScope(
$token[
'name'],
true)) {
3026 $this->clearStackToTableContext($clear);
3031 array_pop($this->stack);
3032 $this->mode = self::IN_TBODY;
3038 array(
'caption',
'col',
'colgroup',
'tbody',
'tfoot',
'thead',
'tr'))) {
3046 return $this->inCell(
$token);
3050 in_array(
$token[
'name'],
array(
'tbody',
'tfoot',
'thead'))) {
3054 if(!$this->elementInScope(
$token[
'name'],
true)) {
3066 return $this->inCell(
$token);
3072 array(
'body',
'caption',
'col',
'colgroup',
'html',
'td',
'th',
'tr'))) {
3086 (
$token[
'name'] ===
'td' ||
$token[
'name'] ===
'th')) {
3090 if(!$this->elementInScope(
$token[
'name'],
true)) {
3097 $this->generateImpliedEndTags(
array(
$token[
'name']));
3106 $node = end($this->stack)->nodeName;
3107 array_pop($this->stack);
3109 if($node ===
$token[
'name']) {
3116 $this->clearTheActiveFormattingElementsUpToTheLastMarker();
3120 $this->mode = self::IN_ROW;
3126 array(
'caption',
'col',
'colgroup',
'tbody',
'td',
'tfoot',
'th',
3131 if(!$this->elementInScope(
array(
'td',
'th'),
true)) {
3138 return $this->inRow(
$token);
3144 array(
'caption',
'col',
'colgroup',
'tbody',
'td',
'tfoot',
'th',
3149 if(!$this->elementInScope(
array(
'td',
'th'),
true)) {
3156 return $this->inRow(
$token);
3162 array(
'body',
'caption',
'col',
'colgroup',
'html'))) {
3168 array(
'table',
'tbody',
'tfoot',
'thead',
'tr'))) {
3173 if(!$this->elementInScope(
$token[
'name'],
true)) {
3180 return $this->inRow(
$token);
3197 $this->insertText(
$token[
'data']);
3203 $this->insertComment(
$token[
'data']);
3207 $token[
'name'] ===
'option') {
3210 if(end($this->stack)->nodeName ===
'option') {
3211 $this->inSelect(
array(
3218 $this->insertElement(
$token);
3222 $token[
'name'] ===
'optgroup') {
3225 if(end($this->stack)->nodeName ===
'option') {
3226 $this->inSelect(
array(
3234 if(end($this->stack)->nodeName ===
'optgroup') {
3235 $this->inSelect(
array(
3236 'name' =>
'optgroup',
3242 $this->insertElement(
$token);
3246 $token[
'name'] ===
'optgroup') {
3251 $elements_in_stack = count($this->stack);
3253 if($this->stack[$elements_in_stack - 1]->nodeName ===
'option' &&
3254 $this->stack[$elements_in_stack - 2]->nodeName ===
'optgroup') {
3255 $this->inSelect(
array(
3264 if($this->stack[$elements_in_stack - 1] ===
'optgroup') {
3265 array_pop($this->stack);
3270 $token[
'name'] ===
'option') {
3274 if(end($this->stack)->nodeName ===
'option') {
3275 array_pop($this->stack);
3280 $token[
'name'] ===
'select') {
3284 if(!$this->elementInScope(
$token[
'name'],
true)) {
3292 $current = end($this->stack)->nodeName;
3293 array_pop($this->stack);
3295 if($current ===
'select') {
3301 $this->resetInsertionMode();
3305 } elseif(
$token[
'name'] ===
'select' &&
3309 $this->inSelect(
array(
3316 } elseif(in_array(
$token[
'name'],
array(
'caption',
'table',
'tbody',
3325 if($this->elementInScope(
$token[
'name'],
true)) {
3326 $this->inSelect(
array(
3331 $this->mainPhase(
$token);
3348 preg_match(
'/^[\t\n\x0b\x0c ]+$/',
$token[
'data'])) {
3359 $this->stack[0]->appendChild(
$comment);
3369 $this->phase = self::END_PHASE;
3375 $this->mode = self::IN_BODY;
3376 return $this->inBody(
$token);
3388 preg_match(
'/^[\t\n\x0b\x0c ]+$/',
$token[
'data'])) {
3390 $this->insertText(
$token[
'data']);
3396 $this->insertComment(
$token[
'data']);
3399 } elseif(
$token[
'name'] ===
'frameset' &&
3401 $this->insertElement(
$token);
3404 } elseif(
$token[
'name'] ===
'frameset' &&
3408 if(end($this->stack)->nodeName ===
'html') {
3414 array_pop($this->stack);
3420 $this->mode = self::AFTR_FRAME;
3424 } elseif(
$token[
'name'] ===
'frame' &&
3427 $this->insertElement(
$token);
3430 array_pop($this->stack);
3433 } elseif(
$token[
'name'] ===
'noframes' &&
3452 preg_match(
'/^[\t\n\x0b\x0c ]+$/',
$token[
'data'])) {
3454 $this->insertText(
$token[
'data']);
3460 $this->insertComment(
$token[
'data']);
3463 } elseif(
$token[
'name'] ===
'html' &&
3466 $this->phase = self::END_PHASE;
3469 } elseif(
$token[
'name'] ===
'noframes' &&
3500 preg_match(
'/^[\t\n\x0b\x0c ]+$/',
$token[
'data'])) {
3502 $this->mainPhase(
$token);
3508 preg_match(
'/^[\t\n\x0b\x0c ]+$/',
$token[
'data'])) ||
3512 $this->phase = self::MAIN_PHASE;
3513 return $this->mainPhase(
$token);
3523 $el = $this->dom->createElement(
$token[
'name']);
3525 foreach(
$token[
'attr'] as $attr) {
3526 if(!$el->hasAttribute($attr[
'name'])) {
3527 $el->setAttribute($attr[
'name'], $attr[
'value']);
3531 $this->appendToRealParent($el);
3532 $this->stack[] = $el;
3540 $this->appendToRealParent(
$text);
3546 $this->appendToRealParent(
$comment);
3551 if($this->foster_parent === null) {
3552 end($this->stack)->appendChild($node);
3554 } elseif($this->foster_parent !== null) {
3561 for(
$n = count($this->stack) - 1;
$n >= 0;
$n--) {
3562 if($this->stack[
$n]->nodeName ===
'table' &&
3563 $this->stack[
$n]->parentNode !== null) {
3564 $table = $this->stack[
$n];
3569 if(isset($table) && $this->foster_parent->isSameNode($table->parentNode))
3570 $this->foster_parent->insertBefore($node, $table);
3572 $this->foster_parent->appendChild($node);
3574 $this->foster_parent = null;
3581 foreach($el as $element) {
3582 if($this->elementInScope($element, $table)) {
3590 $leng = count($this->stack);
3592 for(
$n = 0;
$n < $leng;
$n++) {
3595 $node = $this->stack[$leng - 1 -
$n];
3597 if($node->tagName === $el) {
3601 } elseif($node->tagName ===
'table') {
3606 } elseif($table ===
true && in_array($node->tagName,
array(
'caption',
'td',
3607 'th',
'button',
'marquee',
'object'))) {
3613 } elseif($node === $node->ownerDocument->documentElement) {
3632 $formatting_elements = count($this->a_formatting);
3634 if($formatting_elements === 0) {
3640 $entry = end($this->a_formatting);
3646 if($entry === self::MARKER || in_array($entry, $this->stack,
true)) {
3650 for($a = $formatting_elements - 1; $a >= 0;
true) {
3654 $step_seven =
false;
3661 $entry = $this->a_formatting[$a];
3665 if($entry === self::MARKER || in_array($entry, $this->stack,
true)) {
3673 if(isset($step_seven) && $step_seven ===
true) {
3675 $entry = $this->a_formatting[$a];
3679 $clone = $entry->cloneNode();
3683 end($this->stack)->appendChild($clone);
3684 $this->stack[] = $clone;
3688 $this->a_formatting[$a] = $clone;
3692 if(end($this->a_formatting) !== $clone) {
3709 $entry = end($this->a_formatting);
3712 array_pop($this->a_formatting);
3716 if($entry === self::MARKER) {
3729 $node = end($this->stack);
3730 $elements = array_diff(
array(
'dd',
'dt',
'li',
'p',
'td',
'th',
'tr'),
$exclude);
3732 while(in_array(end($this->stack)->nodeName, $elements)) {
3733 array_pop($this->stack);
3739 if(in_array($name, $this->special))
3740 return self::SPECIAL;
3742 elseif(in_array($name, $this->scoping))
3743 return self::SCOPING;
3746 return self::FORMATTING;
3749 return self::PHRASING;
3760 $node = end($this->stack)->nodeName;
3762 if(in_array($node, $elements)) {
3765 array_pop($this->stack);
3774 $leng = count($this->stack);
3776 for(
$n = $leng - 1;
$n >= 0;
$n--) {
3778 $node = $this->stack[
$n];
3784 if($this->stack[0]->isSameNode($node)) {
3790 if($node->nodeName ===
'select') {
3791 $this->mode = self::IN_SELECT;
3796 } elseif($node->nodeName ===
'td' || $node->nodeName ===
'th') {
3797 $this->mode = self::IN_CELL;
3802 } elseif($node->nodeName ===
'tr') {
3803 $this->mode = self::IN_ROW;
3808 } elseif(in_array($node->nodeName,
array(
'tbody',
'thead',
'tfoot'))) {
3809 $this->mode = self::IN_TBODY;
3814 } elseif($node->nodeName ===
'caption') {
3815 $this->mode = self::IN_CAPTION;
3820 } elseif($node->nodeName ===
'colgroup') {
3821 $this->mode = self::IN_CGROUP;
3826 } elseif($node->nodeName ===
'table') {
3827 $this->mode = self::IN_TABLE;
3833 } elseif($node->nodeName ===
'head') {
3834 $this->mode = self::IN_BODY;
3839 } elseif($node->nodeName ===
'body') {
3840 $this->mode = self::IN_BODY;
3845 } elseif($node->nodeName ===
'frameset') {
3846 $this->mode = self::IN_FRAME;
3853 } elseif($node->nodeName ===
'html') {
3854 $this->mode = ($this->head_pointer === null)
3863 $this->mode = self::IN_BODY;
3873 foreach(
array(
'td',
'th') as $cell) {
3874 if($this->elementInScope($cell,
true)) {
3875 $this->inCell(
array(
attributeValueUnquotedState()
attributeValueSingleQuotedState()
clearTheActiveFormattingElementsUpToTheLastMarker()
characters($char_class, $start)
markupDeclarationOpenState()
beforeAttributeValueState()
generateImpliedEndTags(array $exclude=array())
getElementCategory($name)
entityInAttributeValueState()
clearStackToTableContext($elements)
elementInScope($el, $table=false)
Create styles array
The data for the language used.
appendToRealParent($node)
afterAttributeNameState()
attributeValueDoubleQuotedState()
beforeAttributeNameState()
reconstructActiveFormattingElements()
insertElement($token, $append=true)
const EOF
How fgetc() reports an End Of File.