html: implement ParseWithOptions and ParseFragmentWithOptions
This commit newly introduces a type for configuring a parser
called ParseOption, and implements two functions depending on it.
Along with that, this introduces ParseOptionEnableScripting to
enable setting of the scripting flag.
Fixes golang/go#16318
Change-Id: Ie7fd7d8ce286e22e7f57182fc2ce353bce578db6
Reviewed-on: https://go-review.googlesource.com/c/net/+/174157
Reviewed-by: Nigel Tao <nigeltao@golang.org>
diff --git a/html/parse.go b/html/parse.go
index e0bfc1f..992cff2 100644
--- a/html/parse.go
+++ b/html/parse.go
@@ -2300,6 +2300,33 @@
//
// The input is assumed to be UTF-8 encoded.
func Parse(r io.Reader) (*Node, error) {
+ return ParseWithOptions(r)
+}
+
+// ParseFragment parses a fragment of HTML and returns the nodes that were
+// found. If the fragment is the InnerHTML for an existing element, pass that
+// element in context.
+//
+// It has the same intricacies as Parse.
+func ParseFragment(r io.Reader, context *Node) ([]*Node, error) {
+ return ParseFragmentWithOptions(r, context)
+}
+
+// ParseOption configures a parser.
+type ParseOption func(p *parser)
+
+// ParseOptionEnableScripting configures the scripting flag.
+// https://html.spec.whatwg.org/multipage/webappapis.html#enabling-and-disabling-scripting
+//
+// By default, scripting is enabled.
+func ParseOptionEnableScripting(enable bool) ParseOption {
+ return func(p *parser) {
+ p.scripting = enable
+ }
+}
+
+// ParseWithOptions is like Parse, with options.
+func ParseWithOptions(r io.Reader, opts ...ParseOption) (*Node, error) {
p := &parser{
tokenizer: NewTokenizer(r),
doc: &Node{
@@ -2309,6 +2336,11 @@
framesetOK: true,
im: initialIM,
}
+
+ for _, f := range opts {
+ f(p)
+ }
+
err := p.parse()
if err != nil {
return nil, err
@@ -2316,12 +2348,8 @@
return p.doc, nil
}
-// ParseFragment parses a fragment of HTML and returns the nodes that were
-// found. If the fragment is the InnerHTML for an existing element, pass that
-// element in context.
-//
-// It has the same intricacies as Parse.
-func ParseFragment(r io.Reader, context *Node) ([]*Node, error) {
+// ParseFragmentWithOptions is like ParseFragment, with options.
+func ParseFragmentWithOptions(r io.Reader, context *Node, opts ...ParseOption) ([]*Node, error) {
contextTag := ""
if context != nil {
if context.Type != ElementNode {
@@ -2345,6 +2373,10 @@
context: context,
}
+ for _, f := range opts {
+ f(p)
+ }
+
root := &Node{
Type: ElementNode,
DataAtom: a.Html,
diff --git a/html/parse_test.go b/html/parse_test.go
index b49181c..b16d69a 100644
--- a/html/parse_test.go
+++ b/html/parse_test.go
@@ -228,7 +228,7 @@
t.Fatal(err)
}
- err = testParseCase(text, want, context, Parse)
+ err = testParseCase(text, want, context)
if err != nil {
t.Errorf("%s test #%d %q, %s", tf, i, text, err)
@@ -250,22 +250,7 @@
| <img>
| src="https://golang.org/doc/gopher/doc.png"
`
- err := testParseCase(text, want, "", func(r io.Reader) (*Node, error) {
- p := &parser{
- tokenizer: NewTokenizer(r),
- doc: &Node{
- Type: DocumentNode,
- },
- scripting: false,
- framesetOK: true,
- im: initialIM,
- }
- err := p.parse()
- if err != nil {
- return nil, err
- }
- return p.doc, nil
- })
+ err := testParseCase(text, want, "", ParseOptionEnableScripting(false))
if err != nil {
t.Errorf("test with scripting is disabled, %q, %s", text, err)
@@ -276,7 +261,7 @@
// pass, it returns an error that explains the failure.
// text is the HTML to be parsed, want is a dump of the correct parse tree,
// and context is the name of the context node, if any.
-func testParseCase(text, want, context string, parseFunc func(r io.Reader) (*Node, error)) (err error) {
+func testParseCase(text, want, context string, opts ...ParseOption) (err error) {
defer func() {
if x := recover(); x != nil {
switch e := x.(type) {
@@ -290,7 +275,7 @@
var doc *Node
if context == "" {
- doc, err = parseFunc(strings.NewReader(text))
+ doc, err = ParseWithOptions(strings.NewReader(text), opts...)
if err != nil {
return err
}
@@ -300,7 +285,7 @@
DataAtom: atom.Lookup([]byte(context)),
Data: context,
}
- nodes, err := ParseFragment(strings.NewReader(text), contextNode)
+ nodes, err := ParseFragmentWithOptions(strings.NewReader(text), contextNode, opts...)
if err != nil {
return err
}