diff options
author | Nigel Tao <nigeltao@golang.org> | 2011-10-22 20:18:12 +1100 |
---|---|---|
committer | Nigel Tao <nigeltao@golang.org> | 2011-10-22 20:18:12 +1100 |
commit | 2f352ae48abf1a714f7b3bfb097fab6451067599 (patch) | |
tree | 5d3409fd10a9e80f24e2525fc2870efd5d914752 | |
parent | 696ced50feea2e9711636deeb5a5835cfeb998e9 (diff) | |
download | go-2f352ae48abf1a714f7b3bfb097fab6451067599.tar.gz go-2f352ae48abf1a714f7b3bfb097fab6451067599.zip |
html: parse <select> tags.
The additional test case in parse_test.go is:
<select><b><option><select><option></b></select>X
R=andybalholm
CC=golang-dev
https://golang.org/cl/5293051
-rw-r--r-- | src/pkg/html/parse.go | 106 | ||||
-rw-r--r-- | src/pkg/html/parse_test.go | 2 |
2 files changed, 105 insertions, 3 deletions
diff --git a/src/pkg/html/parse.go b/src/pkg/html/parse.go index ba7e705a79..5b25e2620d 100644 --- a/src/pkg/html/parse.go +++ b/src/pkg/html/parse.go @@ -234,6 +234,41 @@ func (p *parser) setOriginalIM(im insertionMode) { p.originalIM = im } +// Section 11.2.3.1, "reset the insertion mode". +func (p *parser) resetInsertionMode() insertionMode { + for i := len(p.oe) - 1; i >= 0; i-- { + n := p.oe[i] + if i == 0 { + // TODO: set n to the context element, for HTML fragment parsing. + } + switch n.Data { + case "select": + return inSelectIM + case "td", "th": + return inCellIM + case "tr": + return inRowIM + case "tbody", "thead", "tfoot": + return inTableBodyIM + case "caption": + // TODO: return inCaptionIM + case "colgroup": + // TODO: return inColumnGroupIM + case "table": + return inTableIM + case "head": + return inBodyIM + case "body": + return inBodyIM + case "frameset": + // TODO: return inFramesetIM + case "html": + return beforeHeadIM + } + } + return inBodyIM +} + // Section 11.2.5.4.1. func initialIM(p *parser) (insertionMode, bool) { switch p.tok.Type { @@ -478,6 +513,12 @@ func inBodyIM(p *parser) (insertionMode, bool) { p.oe.pop() p.acknowledgeSelfClosingTag() p.framesetOK = false + case "select": + p.reconstructActiveFormattingElements() + p.addElement(p.tok.Data, p.tok.Attr) + p.framesetOK = false + // TODO: detect <select> inside a table. + return inSelectIM, true default: // TODO. p.addElement(p.tok.Data, p.tok.Attr) @@ -671,8 +712,7 @@ func inTableIM(p *parser) (insertionMode, bool) { switch p.tok.Data { case "table": if p.popUntil(tableScopeStopTags, "table") { - // TODO: "reset the insertion mode appropriately" as per 11.2.3.1. - return inBodyIM, false + return p.resetInsertionMode(), true } // Ignore the token. return inTableIM, true @@ -833,6 +873,68 @@ func inCellIM(p *parser) (insertionMode, bool) { return useTheRulesFor(p, inCellIM, inBodyIM) } +// Section 11.2.5.4.16. +func inSelectIM(p *parser) (insertionMode, bool) { + endSelect := false + switch p.tok.Type { + case ErrorToken: + // TODO. + case TextToken: + p.addText(p.tok.Data) + case StartTagToken: + switch p.tok.Data { + case "html": + // TODO. + case "option": + if p.top().Data == "option" { + p.oe.pop() + } + p.addElement(p.tok.Data, p.tok.Attr) + case "optgroup": + // TODO. + case "select": + endSelect = true + case "input", "keygen", "textarea": + // TODO. + case "script": + // TODO. + default: + // Ignore the token. + } + case EndTagToken: + switch p.tok.Data { + case "option": + // TODO. + case "optgroup": + // TODO. + case "select": + endSelect = true + default: + // Ignore the token. + } + case CommentToken: + p.doc.Add(&Node{ + Type: CommentNode, + Data: p.tok.Data, + }) + } + if endSelect { + for i := len(p.oe) - 1; i >= 0; i-- { + switch p.oe[i].Data { + case "select": + p.oe = p.oe[:i] + return p.resetInsertionMode(), true + case "option", "optgroup": + continue + default: + // Ignore the token. + return inSelectIM, true + } + } + } + return inSelectIM, true +} + // Section 11.2.5.4.18. func afterBodyIM(p *parser) (insertionMode, bool) { switch p.tok.Type { diff --git a/src/pkg/html/parse_test.go b/src/pkg/html/parse_test.go index 18b70bf510..2c56ffd6ad 100644 --- a/src/pkg/html/parse_test.go +++ b/src/pkg/html/parse_test.go @@ -123,7 +123,7 @@ func TestParser(t *testing.T) { rc := make(chan io.Reader) go readDat(filename, rc) // TODO(nigeltao): Process all test cases, not just a subset. - for i := 0; i < 29; i++ { + for i := 0; i < 30; i++ { // Parse the #data section. b, err := ioutil.ReadAll(<-rc) if err != nil { |