Commit 500e7a4f authored by namusyaka's avatar namusyaka Committed by Nigel Tao

html: add "in template" insertion mode support

See:
https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-intemplate

Updates golang/go#23071

Change-Id: I36529b7cf5d2adf159ed5c471fba9f67890b7eb9
Reviewed-on: https://go-review.googlesource.com/94838
Run-TryBot: Kunpei Sakai <namusyaka@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: 's avatarNigel Tao <nigeltao@golang.org>
parent 61147c48
......@@ -174,6 +174,16 @@ func (s *nodeStack) index(n *Node) int {
return -1
}
// contains returns whether a is within s.
func (s *nodeStack) contains(a atom.Atom) bool {
for _, n := range *s {
if n.DataAtom == a {
return true
}
}
return false
}
// insert inserts a node at the given index.
func (s *nodeStack) insert(i int, n *Node) {
(*s) = append(*s, nil)
......@@ -192,3 +202,19 @@ func (s *nodeStack) remove(n *Node) {
(*s)[j] = nil
*s = (*s)[:j]
}
type insertionModeStack []insertionMode
func (s *insertionModeStack) pop() (im insertionMode) {
i := len(*s)
im = (*s)[i-1]
*s = (*s)[:i-1]
return im
}
func (s *insertionModeStack) top() insertionMode {
if i := len(*s); i > 0 {
return (*s)[i-1]
}
return nil
}
......@@ -32,6 +32,8 @@ type parser struct {
head, form *Node
// Other parsing state flags (section 12.2.4.5).
scripting, framesetOK bool
// The stack of template insertion modes
templateStack insertionModeStack
// im is the current insertion mode.
im insertionMode
// originalIM is the insertion mode to go back to after completing a text
......@@ -126,7 +128,7 @@ func (p *parser) indexOfElementInScope(s scope, matchTags ...a.Atom) int {
return -1
}
case tableScope:
if tagAtom == a.Html || tagAtom == a.Table {
if tagAtom == a.Html || tagAtom == a.Table || tagAtom == a.Template {
return -1
}
case selectScope:
......@@ -162,17 +164,17 @@ func (p *parser) clearStackToContext(s scope) {
tagAtom := p.oe[i].DataAtom
switch s {
case tableScope:
if tagAtom == a.Html || tagAtom == a.Table {
if tagAtom == a.Html || tagAtom == a.Table || tagAtom == a.Template {
p.oe = p.oe[:i+1]
return
}
case tableRowScope:
if tagAtom == a.Html || tagAtom == a.Tr {
if tagAtom == a.Html || tagAtom == a.Tr || tagAtom == a.Template {
p.oe = p.oe[:i+1]
return
}
case tableBodyScope:
if tagAtom == a.Html || tagAtom == a.Tbody || tagAtom == a.Tfoot || tagAtom == a.Thead {
if tagAtom == a.Html || tagAtom == a.Tbody || tagAtom == a.Tfoot || tagAtom == a.Thead || tagAtom == a.Template {
p.oe = p.oe[:i+1]
return
}
......@@ -183,7 +185,7 @@ func (p *parser) clearStackToContext(s scope) {
}
// generateImpliedEndTags pops nodes off the stack of open elements as long as
// the top node has a tag name of dd, dt, li, option, optgroup, p, rp, or rt.
// the top node has a tag name of dd, dt, li, optgroup, option, p, rp, or rt.
// If exceptions are specified, nodes with that name will not be popped off.
func (p *parser) generateImpliedEndTags(exceptions ...string) {
var i int
......@@ -192,7 +194,9 @@ loop:
n := p.oe[i]
if n.Type == ElementNode {
switch n.DataAtom {
case a.Dd, a.Dt, a.Li, a.Option, a.Optgroup, a.P, a.Rp, a.Rt:
// TODO: add a.Rb and a.Rtc, to match the spec. This needs additions to the
// atom package. Ditto for generateAllImpliedEndTags.
case a.Dd, a.Dt, a.Li, a.Optgroup, a.Option, a.P, a.Rp, a.Rt:
for _, except := range exceptions {
if n.Data == except {
break loop
......@@ -207,6 +211,27 @@ loop:
p.oe = p.oe[:i+1]
}
// generateAllImpliedEndTags pops nodes off the stack of open elements as long as
// the top node has a tag name of caption, colgroup, dd, div, dt, li, optgroup, option, p, rp, rt,
// span, tbody, td, tfoot, th, thead or tr.
func (p *parser) generateAllImpliedEndTags() {
var i int
for i = len(p.oe) - 1; i >= 0; i-- {
n := p.oe[i]
if n.Type == ElementNode {
switch n.DataAtom {
// TODO: remove this divergence from the HTML5 spec
case a.Caption, a.Colgroup, a.Dd, a.Div, a.Dt, a.Li, a.Optgroup, a.Option, a.P, a.Rp, a.Rt,
a.Span, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
continue
}
}
break
}
p.oe = p.oe[:i+1]
}
// addChild adds a child node n to the top element, and pushes n onto the stack
// of open elements if it is an element node.
func (p *parser) addChild(n *Node) {
......@@ -236,7 +261,7 @@ func (p *parser) shouldFosterParent() bool {
// fosterParent adds a child node according to the foster parenting rules.
// Section 12.2.6.1, "foster parenting".
func (p *parser) fosterParent(n *Node) {
var table, parent, prev *Node
var table, parent, prev, template *Node
var i int
for i = len(p.oe) - 1; i >= 0; i-- {
if p.oe[i].DataAtom == a.Table {
......@@ -245,6 +270,19 @@ func (p *parser) fosterParent(n *Node) {
}
}
var j int
for j = len(p.oe) - 1; j >= 0; j-- {
if p.oe[j].DataAtom == a.Template {
template = p.oe[j]
break
}
}
if template != nil && (table == nil || j < i) {
template.AppendChild(n)
return
}
if table == nil {
// The foster parent is the html element.
parent = p.oe[0]
......@@ -415,14 +453,34 @@ func (p *parser) setOriginalIM() {
func (p *parser) resetInsertionMode() {
for i := len(p.oe) - 1; i >= 0; i-- {
n := p.oe[i]
if i == 0 && p.context != nil {
last := i == 0
if last && p.context != nil {
n = p.context
}
switch n.DataAtom {
case a.Select:
if !last {
for ancestor, first := n, p.oe[0]; ancestor != first; {
if ancestor == first {
break
}
ancestor = p.oe[p.oe.index(ancestor)-1]
switch ancestor.DataAtom {
case a.Template:
p.im = inSelectIM
return
case a.Table:
p.im = inSelectInTableIM
return
}
}
}
p.im = inSelectIM
case a.Td, a.Th:
// TODO: remove this divergence from the HTML5 spec.
//
// See https://bugs.chromium.org/p/chromium/issues/detail?id=829668
p.im = inCellIM
case a.Tr:
p.im = inRowIM
......@@ -434,20 +492,32 @@ func (p *parser) resetInsertionMode() {
p.im = inColumnGroupIM
case a.Table:
p.im = inTableIM
case a.Template:
p.im = p.templateStack.top()
case a.Head:
p.im = inBodyIM
// TODO: remove this divergence from the HTML5 spec.
//
// See https://bugs.chromium.org/p/chromium/issues/detail?id=829668
p.im = inHeadIM
case a.Body:
p.im = inBodyIM
case a.Frameset:
p.im = inFramesetIM
case a.Html:
p.im = beforeHeadIM
if p.head == nil {
p.im = beforeHeadIM
} else {
p.im = afterHeadIM
}
default:
if last {
p.im = inBodyIM
return
}
continue
}
return
}
p.im = inBodyIM
}
const whitespace = " \t\r\n\f"
......@@ -590,19 +660,36 @@ func inHeadIM(p *parser) bool {
case a.Head:
// Ignore the token.
return true
case a.Template:
p.addElement()
p.afe = append(p.afe, &scopeMarker)
p.framesetOK = false
p.im = inTemplateIM
p.templateStack = append(p.templateStack, inTemplateIM)
return true
}
case EndTagToken:
switch p.tok.DataAtom {
case a.Head:
n := p.oe.pop()
if n.DataAtom != a.Head {
panic("html: bad parser state: <head> element not found, in the in-head insertion mode")
}
p.oe.pop()
p.im = afterHeadIM
return true
case a.Body, a.Html, a.Br:
p.parseImpliedToken(EndTagToken, a.Head, a.Head.String())
return false
case a.Template:
if !p.oe.contains(a.Template) {
return true
}
p.generateAllImpliedEndTags()
if n := p.oe.top(); n.DataAtom != a.Template {
return true
}
p.popUntil(defaultScope, a.Template)
p.clearActiveFormattingElements()
p.templateStack.pop()
p.resetInsertionMode()
return true
default:
// Ignore the token.
return true
......@@ -648,7 +735,7 @@ func afterHeadIM(p *parser) bool {
p.addElement()
p.im = inFramesetIM
return true
case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Title:
case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Template, a.Title:
p.oe = append(p.oe, p.head)
defer p.oe.remove(p.head)
return inHeadIM(p)
......@@ -660,6 +747,8 @@ func afterHeadIM(p *parser) bool {
switch p.tok.DataAtom {
case a.Body, a.Html, a.Br:
// Drop down to creating an implied <body> tag.
case a.Template:
return inHeadIM(p)
default:
// Ignore the token.
return true
......@@ -727,10 +816,16 @@ func inBodyIM(p *parser) bool {
case StartTagToken:
switch p.tok.DataAtom {
case a.Html:
if p.oe.contains(a.Template) {
return true
}
copyAttributes(p.oe[0], p.tok)
case a.Base, a.Basefont, a.Bgsound, a.Command, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Title:
case a.Base, a.Basefont, a.Bgsound, a.Command, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Template, a.Title:
return inHeadIM(p)
case a.Body:
if p.oe.contains(a.Template) {
return true
}
if len(p.oe) >= 2 {
body := p.oe[1]
if body.Type == ElementNode && body.DataAtom == a.Body {
......@@ -767,7 +862,7 @@ func inBodyIM(p *parser) bool {
// The newline, if any, will be dealt with by the TextToken case.
p.framesetOK = false
case a.Form:
if p.form == nil {
if p.oe.contains(a.Template) || p.form == nil {
p.popUntil(buttonScope, a.P)
p.addElement()
p.form = p.top()
......@@ -972,7 +1067,13 @@ func inBodyIM(p *parser) bool {
p.acknowledgeSelfClosingTag()
}
return true
case a.Caption, a.Col, a.Colgroup, a.Frame, a.Head, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
case a.Frame:
// TODO: remove this divergence from the HTML5 spec.
if p.oe.contains(a.Template) {
p.addElement()
return true
}
case a.Caption, a.Col, a.Colgroup, a.Head, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
// Ignore the token.
default:
p.reconstructActiveFormattingElements()
......@@ -993,15 +1094,28 @@ func inBodyIM(p *parser) bool {
case a.Address, a.Article, a.Aside, a.Blockquote, a.Button, a.Center, a.Details, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Listing, a.Menu, a.Nav, a.Ol, a.Pre, a.Section, a.Summary, a.Ul:
p.popUntil(defaultScope, p.tok.DataAtom)
case a.Form:
node := p.form
p.form = nil
i := p.indexOfElementInScope(defaultScope, a.Form)
if node == nil || i == -1 || p.oe[i] != node {
// Ignore the token.
return true
if p.oe.contains(a.Template) {
if !p.oe.contains(a.Form) {
// Ignore the token.
return true
}
p.generateImpliedEndTags()
if p.tok.DataAtom == a.Form {
// Ignore the token.
return true
}
p.popUntil(defaultScope, a.Form)
} else {
node := p.form
p.form = nil
i := p.indexOfElementInScope(defaultScope, a.Form)
if node == nil || i == -1 || p.oe[i] != node {
// Ignore the token.
return true
}
p.generateImpliedEndTags()
p.oe.remove(node)
}
p.generateImpliedEndTags()
p.oe.remove(node)
case a.P:
if !p.elementInScope(buttonScope, a.P) {
p.parseImpliedToken(StartTagToken, a.P, a.P.String())
......@@ -1022,6 +1136,8 @@ func inBodyIM(p *parser) bool {
case a.Br:
p.tok.Type = StartTagToken
return false
case a.Template:
return inHeadIM(p)
default:
p.inBodyEndTagOther(p.tok.DataAtom)
}
......@@ -1030,6 +1146,22 @@ func inBodyIM(p *parser) bool {
Type: CommentNode,
Data: p.tok.Data,
})
case ErrorToken:
// TODO: remove this divergence from the HTML5 spec.
if len(p.templateStack) > 0 {
p.im = inTemplateIM
return false
} else {
for _, e := range p.oe {
// TODO(namusyaka): rb and rtc elements should be added after updating atom.
switch e.DataAtom {
case a.Dd, a.Dt, a.Li, a.Optgroup, a.Option, a.P, a.Rp, a.Rt, a.Tbody, a.Td, a.Tfoot, a.Th,
a.Thead, a.Tr, a.Body, a.Html:
default:
return true
}
}
}
}
return true
......@@ -1135,6 +1267,12 @@ func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom) {
switch commonAncestor.DataAtom {
case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr:
p.fosterParent(lastNode)
case a.Template:
// TODO: remove namespace checking
if commonAncestor.Namespace == "html" {
commonAncestor = commonAncestor.LastChild
}
fallthrough
default:
commonAncestor.AppendChild(lastNode)
}
......@@ -1249,7 +1387,7 @@ func inTableIM(p *parser) bool {
}
// Ignore the token.
return true
case a.Style, a.Script:
case a.Style, a.Script, a.Template:
return inHeadIM(p)
case a.Input:
for _, t := range p.tok.Attr {
......@@ -1261,7 +1399,7 @@ func inTableIM(p *parser) bool {
}
// Otherwise drop down to the default action.
case a.Form:
if p.form != nil {
if p.oe.contains(a.Template) || p.form != nil {
// Ignore the token.
return true
}
......@@ -1291,6 +1429,8 @@ func inTableIM(p *parser) bool {
case a.Body, a.Caption, a.Col, a.Colgroup, a.Html, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
// Ignore the token.
return true
case a.Template:
return inHeadIM(p)
}
case CommentToken:
p.addChild(&Node{
......@@ -1386,11 +1526,13 @@ func inColumnGroupIM(p *parser) bool {
p.oe.pop()
p.acknowledgeSelfClosingTag()
return true
case a.Template:
return inHeadIM(p)
}
case EndTagToken:
switch p.tok.DataAtom {
case a.Colgroup:
if p.oe.top().DataAtom != a.Html {
if p.oe.top().DataAtom == a.Colgroup {
p.oe.pop()
p.im = inTableIM
}
......@@ -1398,14 +1540,16 @@ func inColumnGroupIM(p *parser) bool {
case a.Col:
// Ignore the token.
return true
case a.Template:
return inHeadIM(p)
}
}
if p.oe.top().DataAtom != a.Html {
p.oe.pop()
p.im = inTableIM
return false
if p.oe.top().DataAtom != a.Colgroup {
return true
}
return true
p.oe.pop()
p.im = inTableIM
return false
}
// Section 12.2.6.4.13.
......@@ -1597,7 +1741,7 @@ func inSelectIM(p *parser) bool {
p.tokenizer.NextIsNotRawText()
// Ignore the token.
return true
case a.Script:
case a.Script, a.Template:
return inHeadIM(p)
}
case EndTagToken:
......@@ -1618,6 +1762,8 @@ func inSelectIM(p *parser) bool {
if p.popUntil(selectScope, a.Select) {
p.resetInsertionMode()
}
case a.Template:
return inHeadIM(p)
}
case CommentToken:
p.addChild(&Node{
......@@ -1650,6 +1796,61 @@ func inSelectInTableIM(p *parser) bool {
return inSelectIM(p)
}
// Section 12.2.6.4.18.
func inTemplateIM(p *parser) bool {
switch p.tok.Type {
case TextToken, CommentToken, DoctypeToken:
return inBodyIM(p)
case StartTagToken:
switch p.tok.DataAtom {
case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Template, a.Title:
return inHeadIM(p)
case a.Caption, a.Colgroup, a.Tbody, a.Tfoot, a.Thead:
p.templateStack.pop()
p.templateStack = append(p.templateStack, inTableIM)
p.im = inTableIM
return false
case a.Col:
p.templateStack.pop()
p.templateStack = append(p.templateStack, inColumnGroupIM)
p.im = inColumnGroupIM
return false
case a.Tr:
p.templateStack.pop()
p.templateStack = append(p.templateStack, inTableBodyIM)
p.im = inTableBodyIM
return false
case a.Td, a.Th:
p.templateStack.pop()
p.templateStack = append(p.templateStack, inRowIM)
p.im = inRowIM
return false
default:
p.templateStack.pop()
p.templateStack = append(p.templateStack, inBodyIM)
p.im = inBodyIM
return false
}
case EndTagToken:
switch p.tok.DataAtom {
case a.Template:
return inHeadIM(p)
default:
// Ignore the token.
return true
}
}
if !p.oe.contains(a.Template) {
// Ignore the token.
return true
}
p.popUntil(defaultScope, a.Template)
p.clearActiveFormattingElements()
p.templateStack.pop()
p.resetInsertionMode()
return false
}
// Section 12.2.6.4.19.
func afterBodyIM(p *parser) bool {
switch p.tok.Type {
......@@ -1720,6 +1921,11 @@ func inFramesetIM(p *parser) bool {
p.acknowledgeSelfClosingTag()
case a.Noframes:
return inHeadIM(p)
case a.Template:
// TODO: remove this divergence from the HTML5 spec.
//
// See https://bugs.chromium.org/p/chromium/issues/detail?id=829668
return inTemplateIM(p)
}
case EndTagToken:
switch p.tok.DataAtom {
......@@ -2064,6 +2270,9 @@ func ParseFragment(r io.Reader, context *Node) ([]*Node, error) {
}
p.doc.AppendChild(root)
p.oe = nodeStack{root}
if context.DataAtom == a.Template {
p.templateStack = append(p.templateStack, inTemplateIM)
}
p.resetInsertionMode()
for n := context; n != nil; n = n.Parent {
......
......@@ -125,6 +125,7 @@ func (a sortedAttributes) Swap(i, j int) {
func dumpLevel(w io.Writer, n *Node, level int) error {
dumpIndent(w, level)
level++
switch n.Type {
case ErrorNode:
return errors.New("unexpected ErrorNode")
......@@ -140,13 +141,19 @@ func dumpLevel(w io.Writer, n *Node, level int) error {
sort.Sort(attr)
for _, a := range attr {
io.WriteString(w, "\n")
dumpIndent(w, level+1)
dumpIndent(w, level)
if a.Namespace != "" {
fmt.Fprintf(w, `%s %s="%s"`, a.Namespace, a.Key, a.Val)
} else {
fmt.Fprintf(w, `%s="%s"`, a.Key, a.Val)
}
}
if n.Namespace == "" && n.DataAtom == atom.Template {
io.WriteString(w, "\n")
dumpIndent(w, level)
level++
io.WriteString(w, "content")
}
case TextNode:
fmt.Fprintf(w, `"%s"`, n.Data)
case CommentNode:
......@@ -176,7 +183,7 @@ func dumpLevel(w io.Writer, n *Node, level int) error {
}
io.WriteString(w, "\n")
for c := n.FirstChild; c != nil; c = c.NextSibling {
if err := dumpLevel(w, c, level+1); err != nil {
if err := dumpLevel(w, c, level); err != nil {
return err
}
}
......
#data
<body><template>Hello</template>
#errors
#document
| <html>
| <head>
| <body>
| <template>
| content
| "Hello"
#data
<template>Hello</template>
#errors
#document
| <html>
| <head>
| <template>
| content
| "Hello"
| <body>
#data
<template></template><div></div>
#errors
#document
| <html>
| <head>
| <template>
| content
| <body>
| <div>
#data
<html><template>Hello</template>
#errors
#document
| <html>
| <head>
| <template>
| content
| "Hello"
| <body>
#data
<head><template><div></div></template></head>
#errors
#document
| <html>
| <head>
| <template>
| content
| <div>
| <body>
#data
<div><template><div><span></template><b>
#errors
#document
| <html>
| <head>
| <body>
| <div>
| <template>
| content
| <div>
| <span>
| <b>
#data
<div><template></div>Hello
#errors
#document
| <html>
| <head>
| <body>
| <div>
| <template>
| content
| "Hello"
#data
<div></template></div>
#errors
#document
| <html>
| <head>
| <body>
| <div>
#data
<table><template></template></table>
#errors
#document
| <html>
| <head>
| <body>
| <table>
| <template>
| content
#data
<table><template></template></div>
#errors
#document
| <html>
| <head>
| <body>
| <table>
| <template>
| content
#data
<table><div><template></template></div>
#errors
#document
| <html>
| <head>
| <body>
| <div>
| <template>
| content
| <table>
#data
<table><template></template><div></div>
#errors
#document
| <html>
| <head>
| <body>
| <div>
| <table>
| <template>
| content
#data
<table> <template></template></table>
#errors
#document
| <html>
| <head>
| <body>
| <table>
| " "
| <template>
| content
#data
<table><tbody><template></template></tbody>
#errors
#document
| <html>
| <head>
| <body>
| <table>
| <tbody>
| <template>
| content
#data
<table><tbody><template></tbody></template>
#errors
#document
| <html>
| <head>
| <body>
| <table>
| <tbody>
| <template>
| content
#data
<table><tbody><template></template></tbody></table>
#errors
#document
| <html>
| <head>
| <body>
| <table>
| <tbody>
| <template>
| content
#data
<table><thead><template></template></thead>
#errors
#document
| <html>
| <head>
| <body>
| <table>
| <thead>
| <template>
| content
#data
<table><tfoot><template></template></tfoot>
#errors
#document
| <html>
| <head>
| <body>
| <table>
| <tfoot>
| <template>
| content
#data
<select><template></template></select>
#errors
#document
| <html>
| <head>
| <body>
| <select>
| <template>
| content
#data
<select><template><option></option></template></select>
#errors
#document
| <html>
| <head>
| <body>
| <select>
| <template>
| content
| <option>
#data
<template><option></option></select><option></option></template>
#errors
#document
| <html>
| <head>
| <template>
| content
| <option>
| <option>
| <body>
#data
<select><template></template><option></select>
#errors
#document
| <html>
| <head>
| <body>
| <select>
| <template>
| content
| <option>
#data
<select><option><template></template></select>
#errors
#document
| <html>
| <head>
| <body>
| <select>
| <option>
| <template>
| content
#data
<select><template>
#errors
#document
| <html>
| <head>
| <body>
| <select>
| <template>
| content
#data
<select><option></option><template>
#errors
#document
| <html>
| <head>
| <body>
| <select>
| <option>
| <template>
| content
#data
<select><option></option><template><option>
#errors
#document
| <html>
| <head>
| <body>
| <select>
| <option>
| <template>
| content
| <option>
#data
<table><thead><template><td></template></table>
#errors
#document
| <html>
| <head>
| <body>
| <table>
| <thead>
| <template>
| content
| <td>
#data
<table><template><thead></template></table>
#errors
#document
| <html>
| <head>
| <body>
| <table>
| <template>
| content
| <thead>
#data
<body><table><template><td></tr><div></template></table>
#errors
#document
| <html>
| <head>
| <body>
| <table>
| <template>
| content
| <td>
| <div>
#data
<table><template><thead></template></thead></table>
#errors
#document
| <html>
| <head>
| <body>
| <table>
| <template>
| content
| <thead>
#data
<table><thead><template><tr></template></table>
#errors
#document
| <html>
| <head>
| <body>
| <table>
| <thead>
| <template>
| content
| <tr>
#data
<table><template><tr></template></table>
#errors
#document
| <html>
| <head>
| <body>
| <table>
| <template>
| content
| <tr>
#data
<table><tr><template><td>
#errors
#document
| <html>
| <head>
| <body>
| <table>
| <tbody>
| <tr>
| <template>
| content
| <td>
#data
<table><template><tr><template><td></template></tr></template></table>
#errors
#document
| <html>
| <head>
| <body>
| <table>
| <template>
| content
| <tr>
| <template>
| content
| <td>
#data
<table><template><tr><template><td></td></template></tr></template></table>
#errors
#document
| <html>
| <head>
| <body>
| <table>
| <template>
| content
| <tr>
| <template>
| content
| <td>
#data
<table><template><td></template>
#errors
#document
| <html>
| <head>
| <body>
| <table>
| <template>
| content
| <td>
#data
<body><template><td></td></template>
#errors
#document
| <html>
| <head>
| <body>
| <template>
| content
| <td>
#data
<body><template><template><tr></tr></template><td></td></template>
#errors
#document
| <html>
| <head>
| <body>
| <template>
| content
| <template>
| content
| <tr>
| <td>
#data
<table><colgroup><template><col>
#errors
#document
| <html>
| <head>
| <body>
| <table>
| <colgroup>
| <template>
| content
| <col>
#data
<frameset><template><frame></frame></template></frameset>
#errors
#document
| <html>
| <head>
| <frameset>
| <template>
| content
| <frame>
#data
<template><frame></frame></frameset><frame></frame></template>
#errors
#document
| <html>
| <head>
| <template>
| content
| <frame>
| <frame>
| <body>
#data
<template><div><frameset><span></span></div><span></span></template>
#errors
#document
| <html>
| <head>
| <template>
| content
| <div>
| <span>
| <span>
| <body>
#data
<body><template><div><frameset><span></span></div><span></span></template></body>
#errors
#document
| <html>
| <head>
| <body>
| <template>
| content
| <div>
| <span>
| <span>
#data
<body><template><script>var i = 1;</script><td></td></template>
#errors
#document
| <html>
| <head>
| <body>
| <template>
| content
| <script>
| "var i = 1;"
| <td>
#data
<body><template><tr><div></div></tr></template>
#errors
#document
| <html>
| <head>
| <body>
| <template>
| content
| <tr>
| <div>
#data
<body><template><tr></tr><td></td></template>
#errors
#document
| <html>
| <head>
| <body>
| <template>
| content
| <tr>
| <tr>
| <td>
#data
<body><template><td></td></tr><td></td></template>
#errors
#document
| <html>
| <head>
| <body>
| <template>
| content
| <td>
| <td>
#data
<body><template><td></td><tbody><td></td></template>
#errors
#document
| <html>
| <head>
| <body>
| <template>
| content
| <td>
| <td>
#data
<body><template><td></td><caption></caption><td></td></template>
#errors
#document
| <html>
| <head>
| <body>
| <template>
| content
| <td>
| <td>
#data
<body><template><td></td><colgroup></caption><td></td></template>
#errors
#document
| <html>
| <head>
| <body>
| <template>
| content
| <td>
| <td>
#data
<body><template><td></td></table><td></td></template>
#errors
#document
| <html>
| <head>
| <body>
| <template>
| content
| <td>
| <td>
#data
<body><template><tr></tr><tbody><tr></tr></template>
#errors
#document
| <html>
| <head>
| <body>
| <template>
| content
| <tr>
| <tr>
#data
<body><template><tr></tr><caption><tr></tr></template>
#errors
#document
| <html>
| <head>
| <body>
| <template>
| content
| <tr>
| <tr>
#data
<body><template><tr></tr></table><tr></tr></template>
#errors
#document
| <html>
| <head>
| <body>
| <template>
| content
| <tr>
| <tr>
#data
<body><template><thead></thead><caption></caption><tbody></tbody></template>
#errors
#document
| <html>
| <head>
| <body>
| <template>
| content
| <thead>
| <caption>
| <tbody>
#data
<body><template><thead></thead></table><tbody></tbody></template></body>
#errors
#document
| <html>
| <head>
| <body>
| <template>
| content
| <thead>
| <tbody>
#data
<body><template><div><tr></tr></div></template>
#errors
#document
| <html>
| <head>
| <body>
| <template>
| content
| <div>
#data
<body><template><em>Hello</em></template>
#errors
#document
| <html>
| <head>
| <body>
| <template>
| content
| <em>
| "Hello"
#data
<body><template><!--comment--></template>
#errors
#document
| <html>
| <head>
| <body>
| <template>
| content
| <!-- comment -->
#data
<body><template><style></style><td></td></template>
#errors
#document
| <html>
| <head>
| <body>
| <template>
| content
| <style>
| <td>
#data
<body><template><meta><td></td></template>
#errors
#document
| <html>
| <head>
| <body>
| <template>
| content
| <meta>
| <td>
#data
<body><template><link><td></td></template>
#errors
#document
| <html>
| <head>
| <body>
| <template>
| content
| <link>
| <td>
#data
<body><template><template><tr></tr></template><td></td></template>
#errors
#document
| <html>
| <head>
| <body>
| <template>
| content
| <template>
| content
| <tr>
| <td>
#data
<body><table><colgroup><template><col></col></template></colgroup></table></body>
#errors
#document
| <html>
| <head>
| <body>
| <table>
| <colgroup>
| <template>
| content
| <col>
#data
<body a=b><template><div></div><body c=d><div></div></body></template></body>
#errors
#document
| <html>
| <head>
| <body>
| a="b"
| <template>
| content
| <div>
| <div>
#data
<html a=b><template><div><html b=c><span></template>
#errors
#document
| <html>
| a="b"
| <head>
| <template>
| content
| <div>
| <span>
| <body>
#data
<html a=b><template><col></col><html b=c><col></col></template>
#errors
#document
| <html>
| a="b"
| <head>
| <template>
| content
| <col>
| <col>
| <body>
#data
<html a=b><template><frame></frame><html b=c><frame></frame></template>
#errors
#document
| <html>
| a="b"
| <head>
| <template>
| content
| <frame>
| <frame>
| <body>
#data
<body><template><tr></tr><template></template><td></td></template>
#errors
#document
| <html>
| <head>
| <body>
| <template>
| content
| <tr>
| <template>
| content
| <tr>
| <td>
#data
<body><template><thead></thead><template><tr></tr></template><tr></tr><tfoot></tfoot></template>
#errors
#document
| <html>
| <head>
| <body>
| <template>
| content
| <thead>
| <template>
| content
| <tr>
| <tbody>
| <tr>
| <tfoot>
#data
<body><template><col><colgroup>
#errors
#document
| <html>
| <head>
| <body>
| <template>
| content
| <col>
#data
<body><template><col></colgroup>
#errors
#document
| <html>
| <head>
| <body>
| <template>
| content
| <col>
#data
<body><template><col><colgroup></template></body>
#errors
#document
| <html>
| <head>
| <body>
| <template>
| content
| <col>
#data
<body><template><col><div>
#errors
#document
| <html>
| <head>
| <body>
| <template>
| content
| <col>
#data
<body><template><col></div>
#errors
#document
| <html>
| <head>
| <body>
| <template>
| content
| <col>
#data
<body><template><col>Hello
#errors
#document
| <html>
| <head>
| <body>
| <template>
| content
| <col>
#data
<body><template><i><menu>Foo</i>
#errors
#document
| <html>
| <head>
| <body>
| <template>
| content
| <i>
| <menu>
| <i>
| "Foo"
#data
<body><template></div><div>Foo</div><template></template><tr></tr>
#errors
#document
| <html>
| <head>
| <body>
| <template>
| content
| <div>
| "Foo"
| <template>
| content
#data
<body><div><template></div><tr><td>Foo</td></tr></template>
#errors
#document
| <html>
| <head>
| <body>
| <div>
| <template>
| content
| <tr>
| <td>
| "Foo"
#data
<template></figcaption><sub><table></table>
#errors
#document
| <html>
| <head>
| <template>
| content
| <sub>
| <table>
| <body>
#data
<template><template>
#errors
#document
| <html>
| <head>
| <template>
| content
| <template>
| content
| <body>
#data
<template><div>
#errors
#document
| <html>
| <head>
| <template>
| content
| <div>
| <body>
#data
<template><template><div>
#errors
#document
| <html>
| <head>
| <template>
| content
| <template>
| content
| <div>
| <body>
#data
<template><template><script>var i
#errors
#document
| <html>
| <head>
| <template>
| content
| <template>
| content
| <script>
| "var i"
| <body>
#data
<template><template><style>var i
#errors
#document
| <html>
| <head>
| <template>
| content
| <template>
| content
| <style>
| "var i"
| <body>
#data
<template><svg><template>
#errors
#document
| <html>
| <head>
| <template>
| content
| <svg svg>
| <svg template>
| <body>
#data
<dummy><template><span></dummy>
#errors
#document
| <html>
| <head>
| <body>
| <dummy>
| <template>
| content
| <span>
#data
<body><table><tr><td><select><template>Foo</template><caption>A</table>
#errors
#document
| <html>
| <head>
| <body>
| <table>
| <tbody>
| <tr>
| <td>
| <select>
| <template>
| content
| "Foo"
| <caption>
| "A"
#data
<body></body><template>
#errors
#document
| <html>
| <head>
| <body>
| <template>
| content
#data
<head></head><template>
#errors
#document
| <html>
| <head>
| <template>
| content
| <body>
#data
<head></head><template>Foo</template>
#errors
#document
| <html>
| <head>
| <template>
| content
| "Foo"
| <body>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment