@@ -139,6 +139,11 @@ private function strConst($number) {
139
139
const NS_XML = 'http://www.w3.org/XML/1998/namespace ' ;
140
140
const NS_XMLNS = 'http://www.w3.org/2000/xmlns/ ' ;
141
141
142
+ // Different types of scopes to test for elements
143
+ const SCOPE = 0 ;
144
+ const SCOPE_LISTITEM = 1 ;
145
+ const SCOPE_TABLE = 2 ;
146
+
142
147
public function __construct () {
143
148
$ this ->mode = self ::INITIAL ;
144
149
$ this ->dom = new DOMDocument ;
@@ -1575,8 +1580,31 @@ public function emitToken($token, $mode = null) {
1575
1580
}
1576
1581
break ;
1577
1582
1583
+ /* An end tag whose tag name is "li" */
1584
+ case 'li ' :
1585
+ /* If the stack of open elements does not have an element
1586
+ * in list item scope with the same tag name as that of the
1587
+ * token, then this is a parse error; ignore the token. */
1588
+ if ($ this ->elementInScope ($ token ['name ' ], self ::SCOPE_LISTITEM )) {
1589
+ /* Generate implied end tags, except for elements with the
1590
+ * same tag name as the token. */
1591
+ $ this ->generateImpliedEndTags (array ($ token ['name ' ]));
1592
+ /* If the current node is not an element with the same tag
1593
+ * name as that of the token, then this is a parse error. */
1594
+ // XERROR: parse error
1595
+ /* Pop elements from the stack of open elements until an
1596
+ * element with the same tag name as the token has been
1597
+ * popped from the stack. */
1598
+ do {
1599
+ $ node = array_pop ($ this ->stack );
1600
+ } while ($ node ->tagName !== $ token ['name ' ]);
1601
+ } else {
1602
+ // XERROR: parse error
1603
+ }
1604
+ break ;
1605
+
1578
1606
/* An end tag whose tag name is "dd", "dt", or "li" */
1579
- case 'dd ' : case 'dt ' : case ' li ' :
1607
+ case 'dd ' : case 'dt ' :
1580
1608
if ($ this ->elementInScope ($ token ['name ' ])) {
1581
1609
$ this ->generateImpliedEndTags (array ($ token ['name ' ]));
1582
1610
@@ -1592,7 +1620,7 @@ public function emitToken($token, $mode = null) {
1592
1620
} while ($ node ->tagName !== $ token ['name ' ]);
1593
1621
1594
1622
} else {
1595
- // parse error
1623
+ // XERROR: parse error
1596
1624
}
1597
1625
break ;
1598
1626
@@ -2073,7 +2101,7 @@ public function emitToken($token, $mode = null) {
2073
2101
/* If the stack of open elements does not have an element in table
2074
2102
scope with the same tag name as the token, this is a parse error.
2075
2103
Ignore the token. (fragment case) */
2076
- if (!$ this ->elementInScope ($ token ['name ' ], true )) {
2104
+ if (!$ this ->elementInScope ($ token ['name ' ], self :: SCOPE_TABLE )) {
2077
2105
$ this ->ignored = true ;
2078
2106
2079
2107
/* Otherwise: */
@@ -2185,7 +2213,7 @@ public function emitToken($token, $mode = null) {
2185
2213
/* If the stack of open elements does not have an element in table
2186
2214
scope with the same tag name as the token, this is a parse error.
2187
2215
Ignore the token. (fragment case) */
2188
- if (!$ this ->elementInScope ($ token ['name ' ], true )) {
2216
+ if (!$ this ->elementInScope ($ token ['name ' ], self :: SCOPE_TABLE )) {
2189
2217
$ this ->ignored = true ;
2190
2218
// Ignore
2191
2219
@@ -2343,7 +2371,7 @@ public function emitToken($token, $mode = null) {
2343
2371
/* If the stack of open elements does not have an element in table
2344
2372
scope with the same tag name as the token, this is a parse error.
2345
2373
Ignore the token. */
2346
- if (!$ this ->elementInScope ($ token ['name ' ], true )) {
2374
+ if (!$ this ->elementInScope ($ token ['name ' ], self :: SCOPE_TABLE )) {
2347
2375
// Parse error
2348
2376
$ this ->ignored = true ;
2349
2377
@@ -2366,7 +2394,7 @@ public function emitToken($token, $mode = null) {
2366
2394
/* If the stack of open elements does not have a tbody, thead, or
2367
2395
tfoot element in table scope, this is a parse error. Ignore the
2368
2396
token. (fragment case) */
2369
- if (!$ this ->elementInScope (array ('tbody ' , 'thead ' , 'tfoot ' ), true )) {
2397
+ if (!$ this ->elementInScope (array ('tbody ' , 'thead ' , 'tfoot ' ), self :: SCOPE_TABLE )) {
2370
2398
// parse error
2371
2399
$ this ->ignored = true ;
2372
2400
@@ -2423,7 +2451,7 @@ public function emitToken($token, $mode = null) {
2423
2451
/* If the stack of open elements does not have an element in table
2424
2452
scope with the same tag name as the token, this is a parse error.
2425
2453
Ignore the token. (fragment case) */
2426
- if (!$ this ->elementInScope ($ token ['name ' ], true )) {
2454
+ if (!$ this ->elementInScope ($ token ['name ' ], self :: SCOPE_TABLE )) {
2427
2455
// Ignore.
2428
2456
$ this ->ignored = true ;
2429
2457
@@ -2458,7 +2486,7 @@ public function emitToken($token, $mode = null) {
2458
2486
/* If the stack of open elements does not have an element in table
2459
2487
scope with the same tag name as the token, this is a parse error.
2460
2488
Ignore the token. */
2461
- if (!$ this ->elementInScope ($ token ['name ' ], true )) {
2489
+ if (!$ this ->elementInScope ($ token ['name ' ], self :: SCOPE_TABLE )) {
2462
2490
$ this ->ignored = true ;
2463
2491
2464
2492
/* Otherwise: */
@@ -2494,7 +2522,7 @@ public function emitToken($token, $mode = null) {
2494
2522
/* If the stack of open elements does not have an element in table
2495
2523
scope with the same tag name as that of the token, then this is a
2496
2524
parse error and the token must be ignored. */
2497
- if (!$ this ->elementInScope ($ token ['name ' ], true )) {
2525
+ if (!$ this ->elementInScope ($ token ['name ' ], self :: SCOPE_TABLE )) {
2498
2526
$ this ->ignored = true ;
2499
2527
2500
2528
/* Otherwise: */
@@ -2530,7 +2558,7 @@ public function emitToken($token, $mode = null) {
2530
2558
/* If the stack of open elements does not have a td or th element
2531
2559
in table scope, then this is a parse error; ignore the token.
2532
2560
(fragment case) */
2533
- if (!$ this ->elementInScope (array ('td ' , 'th ' ), true )) {
2561
+ if (!$ this ->elementInScope (array ('td ' , 'th ' ), self :: SCOPE_TABLE )) {
2534
2562
// parse error
2535
2563
$ this ->ignored = true ;
2536
2564
@@ -2555,7 +2583,7 @@ public function emitToken($token, $mode = null) {
2555
2583
/* If the stack of open elements does not have a td or th element
2556
2584
in table scope, then this is a parse error; ignore the token.
2557
2585
(innerHTML case) */
2558
- if (!$ this ->elementInScope (array ('td ' , 'th ' ), true )) {
2586
+ if (!$ this ->elementInScope (array ('td ' , 'th ' ), self :: SCOPE_TABLE )) {
2559
2587
// Parse error
2560
2588
$ this ->ignored = true ;
2561
2589
@@ -2681,7 +2709,7 @@ public function emitToken($token, $mode = null) {
2681
2709
/* If the stack of open elements does not have an element in table
2682
2710
scope with the same tag name as the token, this is a parse error.
2683
2711
Ignore the token. (fragment case) */
2684
- if (!$ this ->elementInScope ($ token ['name ' ], true )) {
2712
+ if (!$ this ->elementInScope ($ token ['name ' ], self :: SCOPE_TABLE )) {
2685
2713
$ this ->ignored = true ;
2686
2714
// parse error
2687
2715
@@ -2752,7 +2780,7 @@ public function emitToken($token, $mode = null) {
2752
2780
the same tag name as that of the token, then act as if an end tag
2753
2781
with the tag name "select" had been seen, and reprocess the token.
2754
2782
Otherwise, ignore the token. */
2755
- if ($ this ->elementInScope ($ token ['name ' ], true )) {
2783
+ if ($ this ->elementInScope ($ token ['name ' ], self :: SCOPE_TABLE )) {
2756
2784
$ this ->emitToken (array (
2757
2785
'name ' => 'select ' ,
2758
2786
'type ' => HTML5_Tokenizer::ENDTAG
@@ -3170,10 +3198,10 @@ private function appendToRealParent($node) {
3170
3198
}
3171
3199
}
3172
3200
3173
- private function elementInScope ($ el , $ table = false ) {
3201
+ private function elementInScope ($ el , $ scope = self :: SCOPE ) {
3174
3202
if (is_array ($ el )) {
3175
3203
foreach ($ el as $ element ) {
3176
- if ($ this ->elementInScope ($ element , $ table )) {
3204
+ if ($ this ->elementInScope ($ element , $ scope )) {
3177
3205
return true ;
3178
3206
}
3179
3207
}
@@ -3192,16 +3220,25 @@ private function elementInScope($el, $table = false) {
3192
3220
/* 2. If node is the target node, terminate in a match state. */
3193
3221
return true ;
3194
3222
3195
- // these are the common states for "in scope" and "in table scope"
3223
+ // We've expanded the logic for these states a little differently;
3224
+ // Hixie's refactoring into "specific scope" is more general, but
3225
+ // this "gets the job done"
3226
+
3227
+ // these are the common states for all scopes
3196
3228
} elseif ($ node ->tagName === 'table ' || $ node ->tagName === 'html ' ) {
3197
3229
return false ;
3198
3230
3199
- // these are only valid for "in scope"
3200
- } elseif (! $ table &&
3231
+ // these are valid for "in scope" and "in list item scope"
3232
+ } elseif ($ scope !== self :: SCOPE_TABLE &&
3201
3233
(in_array ($ node ->tagName , array ('applet ' , 'caption ' , 'td ' ,
3202
3234
'th ' , 'button ' , 'marquee ' , 'object ' )) ||
3203
3235
$ node ->tagName === 'foreignObject ' && $ node ->namespaceURI === self ::NS_SVG )) {
3204
3236
return false ;
3237
+
3238
+
3239
+ // these are valid for "in list item scope"
3240
+ } elseif ($ scope === self ::SCOPE_LISTITEM && in_array ($ node ->tagName , array ('ol ' , 'ul ' ))) {
3241
+ return false ;
3205
3242
}
3206
3243
3207
3244
/* Otherwise, set node to the previous entry in the stack of open
@@ -3461,7 +3498,7 @@ private function closeCell() {
3461
3498
/* If the stack of open elements has a td or th element in table scope,
3462
3499
then act as if an end tag token with that tag name had been seen. */
3463
3500
foreach (array ('td ' , 'th ' ) as $ cell ) {
3464
- if ($ this ->elementInScope ($ cell , true )) {
3501
+ if ($ this ->elementInScope ($ cell , self :: SCOPE_TABLE )) {
3465
3502
$ this ->emitToken (array (
3466
3503
'name ' => $ cell ,
3467
3504
'type ' => HTML5_Tokenizer::ENDTAG
0 commit comments