github.com/stackdocker/rkt@v0.10.1-0.20151109095037-1aa827478248/Godeps/_workspace/src/golang.org/x/net/html/parse.go (about)

     1  // Copyright 2010 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package html
     6  
     7  import (
     8  	"errors"
     9  	"fmt"
    10  	"io"
    11  	"strings"
    12  
    13  	a "github.com/coreos/rkt/Godeps/_workspace/src/golang.org/x/net/html/atom"
    14  )
    15  
    16  // A parser implements the HTML5 parsing algorithm:
    17  // https://html.spec.whatwg.org/multipage/syntax.html#tree-construction
    18  type parser struct {
    19  	// tokenizer provides the tokens for the parser.
    20  	tokenizer *Tokenizer
    21  	// tok is the most recently read token.
    22  	tok Token
    23  	// Self-closing tags like <hr/> are treated as start tags, except that
    24  	// hasSelfClosingToken is set while they are being processed.
    25  	hasSelfClosingToken bool
    26  	// doc is the document root element.
    27  	doc *Node
    28  	// The stack of open elements (section 12.2.3.2) and active formatting
    29  	// elements (section 12.2.3.3).
    30  	oe, afe nodeStack
    31  	// Element pointers (section 12.2.3.4).
    32  	head, form *Node
    33  	// Other parsing state flags (section 12.2.3.5).
    34  	scripting, framesetOK bool
    35  	// im is the current insertion mode.
    36  	im insertionMode
    37  	// originalIM is the insertion mode to go back to after completing a text
    38  	// or inTableText insertion mode.
    39  	originalIM insertionMode
    40  	// fosterParenting is whether new elements should be inserted according to
    41  	// the foster parenting rules (section 12.2.5.3).
    42  	fosterParenting bool
    43  	// quirks is whether the parser is operating in "quirks mode."
    44  	quirks bool
    45  	// fragment is whether the parser is parsing an HTML fragment.
    46  	fragment bool
    47  	// context is the context element when parsing an HTML fragment
    48  	// (section 12.4).
    49  	context *Node
    50  }
    51  
    52  func (p *parser) top() *Node {
    53  	if n := p.oe.top(); n != nil {
    54  		return n
    55  	}
    56  	return p.doc
    57  }
    58  
    59  // Stop tags for use in popUntil. These come from section 12.2.3.2.
    60  var (
    61  	defaultScopeStopTags = map[string][]a.Atom{
    62  		"":     {a.Applet, a.Caption, a.Html, a.Table, a.Td, a.Th, a.Marquee, a.Object, a.Template},
    63  		"math": {a.AnnotationXml, a.Mi, a.Mn, a.Mo, a.Ms, a.Mtext},
    64  		"svg":  {a.Desc, a.ForeignObject, a.Title},
    65  	}
    66  )
    67  
    68  type scope int
    69  
    70  const (
    71  	defaultScope scope = iota
    72  	listItemScope
    73  	buttonScope
    74  	tableScope
    75  	tableRowScope
    76  	tableBodyScope
    77  	selectScope
    78  )
    79  
    80  // popUntil pops the stack of open elements at the highest element whose tag
    81  // is in matchTags, provided there is no higher element in the scope's stop
    82  // tags (as defined in section 12.2.3.2). It returns whether or not there was
    83  // such an element. If there was not, popUntil leaves the stack unchanged.
    84  //
    85  // For example, the set of stop tags for table scope is: "html", "table". If
    86  // the stack was:
    87  // ["html", "body", "font", "table", "b", "i", "u"]
    88  // then popUntil(tableScope, "font") would return false, but
    89  // popUntil(tableScope, "i") would return true and the stack would become:
    90  // ["html", "body", "font", "table", "b"]
    91  //
    92  // If an element's tag is in both the stop tags and matchTags, then the stack
    93  // will be popped and the function returns true (provided, of course, there was
    94  // no higher element in the stack that was also in the stop tags). For example,
    95  // popUntil(tableScope, "table") returns true and leaves:
    96  // ["html", "body", "font"]
    97  func (p *parser) popUntil(s scope, matchTags ...a.Atom) bool {
    98  	if i := p.indexOfElementInScope(s, matchTags...); i != -1 {
    99  		p.oe = p.oe[:i]
   100  		return true
   101  	}
   102  	return false
   103  }
   104  
   105  // indexOfElementInScope returns the index in p.oe of the highest element whose
   106  // tag is in matchTags that is in scope. If no matching element is in scope, it
   107  // returns -1.
   108  func (p *parser) indexOfElementInScope(s scope, matchTags ...a.Atom) int {
   109  	for i := len(p.oe) - 1; i >= 0; i-- {
   110  		tagAtom := p.oe[i].DataAtom
   111  		if p.oe[i].Namespace == "" {
   112  			for _, t := range matchTags {
   113  				if t == tagAtom {
   114  					return i
   115  				}
   116  			}
   117  			switch s {
   118  			case defaultScope:
   119  				// No-op.
   120  			case listItemScope:
   121  				if tagAtom == a.Ol || tagAtom == a.Ul {
   122  					return -1
   123  				}
   124  			case buttonScope:
   125  				if tagAtom == a.Button {
   126  					return -1
   127  				}
   128  			case tableScope:
   129  				if tagAtom == a.Html || tagAtom == a.Table {
   130  					return -1
   131  				}
   132  			case selectScope:
   133  				if tagAtom != a.Optgroup && tagAtom != a.Option {
   134  					return -1
   135  				}
   136  			default:
   137  				panic("unreachable")
   138  			}
   139  		}
   140  		switch s {
   141  		case defaultScope, listItemScope, buttonScope:
   142  			for _, t := range defaultScopeStopTags[p.oe[i].Namespace] {
   143  				if t == tagAtom {
   144  					return -1
   145  				}
   146  			}
   147  		}
   148  	}
   149  	return -1
   150  }
   151  
   152  // elementInScope is like popUntil, except that it doesn't modify the stack of
   153  // open elements.
   154  func (p *parser) elementInScope(s scope, matchTags ...a.Atom) bool {
   155  	return p.indexOfElementInScope(s, matchTags...) != -1
   156  }
   157  
   158  // clearStackToContext pops elements off the stack of open elements until a
   159  // scope-defined element is found.
   160  func (p *parser) clearStackToContext(s scope) {
   161  	for i := len(p.oe) - 1; i >= 0; i-- {
   162  		tagAtom := p.oe[i].DataAtom
   163  		switch s {
   164  		case tableScope:
   165  			if tagAtom == a.Html || tagAtom == a.Table {
   166  				p.oe = p.oe[:i+1]
   167  				return
   168  			}
   169  		case tableRowScope:
   170  			if tagAtom == a.Html || tagAtom == a.Tr {
   171  				p.oe = p.oe[:i+1]
   172  				return
   173  			}
   174  		case tableBodyScope:
   175  			if tagAtom == a.Html || tagAtom == a.Tbody || tagAtom == a.Tfoot || tagAtom == a.Thead {
   176  				p.oe = p.oe[:i+1]
   177  				return
   178  			}
   179  		default:
   180  			panic("unreachable")
   181  		}
   182  	}
   183  }
   184  
   185  // generateImpliedEndTags pops nodes off the stack of open elements as long as
   186  // the top node has a tag name of dd, dt, li, option, optgroup, p, rp, or rt.
   187  // If exceptions are specified, nodes with that name will not be popped off.
   188  func (p *parser) generateImpliedEndTags(exceptions ...string) {
   189  	var i int
   190  loop:
   191  	for i = len(p.oe) - 1; i >= 0; i-- {
   192  		n := p.oe[i]
   193  		if n.Type == ElementNode {
   194  			switch n.DataAtom {
   195  			case a.Dd, a.Dt, a.Li, a.Option, a.Optgroup, a.P, a.Rp, a.Rt:
   196  				for _, except := range exceptions {
   197  					if n.Data == except {
   198  						break loop
   199  					}
   200  				}
   201  				continue
   202  			}
   203  		}
   204  		break
   205  	}
   206  
   207  	p.oe = p.oe[:i+1]
   208  }
   209  
   210  // addChild adds a child node n to the top element, and pushes n onto the stack
   211  // of open elements if it is an element node.
   212  func (p *parser) addChild(n *Node) {
   213  	if p.shouldFosterParent() {
   214  		p.fosterParent(n)
   215  	} else {
   216  		p.top().AppendChild(n)
   217  	}
   218  
   219  	if n.Type == ElementNode {
   220  		p.oe = append(p.oe, n)
   221  	}
   222  }
   223  
   224  // shouldFosterParent returns whether the next node to be added should be
   225  // foster parented.
   226  func (p *parser) shouldFosterParent() bool {
   227  	if p.fosterParenting {
   228  		switch p.top().DataAtom {
   229  		case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr:
   230  			return true
   231  		}
   232  	}
   233  	return false
   234  }
   235  
   236  // fosterParent adds a child node according to the foster parenting rules.
   237  // Section 12.2.5.3, "foster parenting".
   238  func (p *parser) fosterParent(n *Node) {
   239  	var table, parent, prev *Node
   240  	var i int
   241  	for i = len(p.oe) - 1; i >= 0; i-- {
   242  		if p.oe[i].DataAtom == a.Table {
   243  			table = p.oe[i]
   244  			break
   245  		}
   246  	}
   247  
   248  	if table == nil {
   249  		// The foster parent is the html element.
   250  		parent = p.oe[0]
   251  	} else {
   252  		parent = table.Parent
   253  	}
   254  	if parent == nil {
   255  		parent = p.oe[i-1]
   256  	}
   257  
   258  	if table != nil {
   259  		prev = table.PrevSibling
   260  	} else {
   261  		prev = parent.LastChild
   262  	}
   263  	if prev != nil && prev.Type == TextNode && n.Type == TextNode {
   264  		prev.Data += n.Data
   265  		return
   266  	}
   267  
   268  	parent.InsertBefore(n, table)
   269  }
   270  
   271  // addText adds text to the preceding node if it is a text node, or else it
   272  // calls addChild with a new text node.
   273  func (p *parser) addText(text string) {
   274  	if text == "" {
   275  		return
   276  	}
   277  
   278  	if p.shouldFosterParent() {
   279  		p.fosterParent(&Node{
   280  			Type: TextNode,
   281  			Data: text,
   282  		})
   283  		return
   284  	}
   285  
   286  	t := p.top()
   287  	if n := t.LastChild; n != nil && n.Type == TextNode {
   288  		n.Data += text
   289  		return
   290  	}
   291  	p.addChild(&Node{
   292  		Type: TextNode,
   293  		Data: text,
   294  	})
   295  }
   296  
   297  // addElement adds a child element based on the current token.
   298  func (p *parser) addElement() {
   299  	p.addChild(&Node{
   300  		Type:     ElementNode,
   301  		DataAtom: p.tok.DataAtom,
   302  		Data:     p.tok.Data,
   303  		Attr:     p.tok.Attr,
   304  	})
   305  }
   306  
   307  // Section 12.2.3.3.
   308  func (p *parser) addFormattingElement() {
   309  	tagAtom, attr := p.tok.DataAtom, p.tok.Attr
   310  	p.addElement()
   311  
   312  	// Implement the Noah's Ark clause, but with three per family instead of two.
   313  	identicalElements := 0
   314  findIdenticalElements:
   315  	for i := len(p.afe) - 1; i >= 0; i-- {
   316  		n := p.afe[i]
   317  		if n.Type == scopeMarkerNode {
   318  			break
   319  		}
   320  		if n.Type != ElementNode {
   321  			continue
   322  		}
   323  		if n.Namespace != "" {
   324  			continue
   325  		}
   326  		if n.DataAtom != tagAtom {
   327  			continue
   328  		}
   329  		if len(n.Attr) != len(attr) {
   330  			continue
   331  		}
   332  	compareAttributes:
   333  		for _, t0 := range n.Attr {
   334  			for _, t1 := range attr {
   335  				if t0.Key == t1.Key && t0.Namespace == t1.Namespace && t0.Val == t1.Val {
   336  					// Found a match for this attribute, continue with the next attribute.
   337  					continue compareAttributes
   338  				}
   339  			}
   340  			// If we get here, there is no attribute that matches a.
   341  			// Therefore the element is not identical to the new one.
   342  			continue findIdenticalElements
   343  		}
   344  
   345  		identicalElements++
   346  		if identicalElements >= 3 {
   347  			p.afe.remove(n)
   348  		}
   349  	}
   350  
   351  	p.afe = append(p.afe, p.top())
   352  }
   353  
   354  // Section 12.2.3.3.
   355  func (p *parser) clearActiveFormattingElements() {
   356  	for {
   357  		n := p.afe.pop()
   358  		if len(p.afe) == 0 || n.Type == scopeMarkerNode {
   359  			return
   360  		}
   361  	}
   362  }
   363  
   364  // Section 12.2.3.3.
   365  func (p *parser) reconstructActiveFormattingElements() {
   366  	n := p.afe.top()
   367  	if n == nil {
   368  		return
   369  	}
   370  	if n.Type == scopeMarkerNode || p.oe.index(n) != -1 {
   371  		return
   372  	}
   373  	i := len(p.afe) - 1
   374  	for n.Type != scopeMarkerNode && p.oe.index(n) == -1 {
   375  		if i == 0 {
   376  			i = -1
   377  			break
   378  		}
   379  		i--
   380  		n = p.afe[i]
   381  	}
   382  	for {
   383  		i++
   384  		clone := p.afe[i].clone()
   385  		p.addChild(clone)
   386  		p.afe[i] = clone
   387  		if i == len(p.afe)-1 {
   388  			break
   389  		}
   390  	}
   391  }
   392  
   393  // Section 12.2.4.
   394  func (p *parser) acknowledgeSelfClosingTag() {
   395  	p.hasSelfClosingToken = false
   396  }
   397  
   398  // An insertion mode (section 12.2.3.1) is the state transition function from
   399  // a particular state in the HTML5 parser's state machine. It updates the
   400  // parser's fields depending on parser.tok (where ErrorToken means EOF).
   401  // It returns whether the token was consumed.
   402  type insertionMode func(*parser) bool
   403  
   404  // setOriginalIM sets the insertion mode to return to after completing a text or
   405  // inTableText insertion mode.
   406  // Section 12.2.3.1, "using the rules for".
   407  func (p *parser) setOriginalIM() {
   408  	if p.originalIM != nil {
   409  		panic("html: bad parser state: originalIM was set twice")
   410  	}
   411  	p.originalIM = p.im
   412  }
   413  
   414  // Section 12.2.3.1, "reset the insertion mode".
   415  func (p *parser) resetInsertionMode() {
   416  	for i := len(p.oe) - 1; i >= 0; i-- {
   417  		n := p.oe[i]
   418  		if i == 0 && p.context != nil {
   419  			n = p.context
   420  		}
   421  
   422  		switch n.DataAtom {
   423  		case a.Select:
   424  			p.im = inSelectIM
   425  		case a.Td, a.Th:
   426  			p.im = inCellIM
   427  		case a.Tr:
   428  			p.im = inRowIM
   429  		case a.Tbody, a.Thead, a.Tfoot:
   430  			p.im = inTableBodyIM
   431  		case a.Caption:
   432  			p.im = inCaptionIM
   433  		case a.Colgroup:
   434  			p.im = inColumnGroupIM
   435  		case a.Table:
   436  			p.im = inTableIM
   437  		case a.Head:
   438  			p.im = inBodyIM
   439  		case a.Body:
   440  			p.im = inBodyIM
   441  		case a.Frameset:
   442  			p.im = inFramesetIM
   443  		case a.Html:
   444  			p.im = beforeHeadIM
   445  		default:
   446  			continue
   447  		}
   448  		return
   449  	}
   450  	p.im = inBodyIM
   451  }
   452  
   453  const whitespace = " \t\r\n\f"
   454  
   455  // Section 12.2.5.4.1.
   456  func initialIM(p *parser) bool {
   457  	switch p.tok.Type {
   458  	case TextToken:
   459  		p.tok.Data = strings.TrimLeft(p.tok.Data, whitespace)
   460  		if len(p.tok.Data) == 0 {
   461  			// It was all whitespace, so ignore it.
   462  			return true
   463  		}
   464  	case CommentToken:
   465  		p.doc.AppendChild(&Node{
   466  			Type: CommentNode,
   467  			Data: p.tok.Data,
   468  		})
   469  		return true
   470  	case DoctypeToken:
   471  		n, quirks := parseDoctype(p.tok.Data)
   472  		p.doc.AppendChild(n)
   473  		p.quirks = quirks
   474  		p.im = beforeHTMLIM
   475  		return true
   476  	}
   477  	p.quirks = true
   478  	p.im = beforeHTMLIM
   479  	return false
   480  }
   481  
   482  // Section 12.2.5.4.2.
   483  func beforeHTMLIM(p *parser) bool {
   484  	switch p.tok.Type {
   485  	case DoctypeToken:
   486  		// Ignore the token.
   487  		return true
   488  	case TextToken:
   489  		p.tok.Data = strings.TrimLeft(p.tok.Data, whitespace)
   490  		if len(p.tok.Data) == 0 {
   491  			// It was all whitespace, so ignore it.
   492  			return true
   493  		}
   494  	case StartTagToken:
   495  		if p.tok.DataAtom == a.Html {
   496  			p.addElement()
   497  			p.im = beforeHeadIM
   498  			return true
   499  		}
   500  	case EndTagToken:
   501  		switch p.tok.DataAtom {
   502  		case a.Head, a.Body, a.Html, a.Br:
   503  			p.parseImpliedToken(StartTagToken, a.Html, a.Html.String())
   504  			return false
   505  		default:
   506  			// Ignore the token.
   507  			return true
   508  		}
   509  	case CommentToken:
   510  		p.doc.AppendChild(&Node{
   511  			Type: CommentNode,
   512  			Data: p.tok.Data,
   513  		})
   514  		return true
   515  	}
   516  	p.parseImpliedToken(StartTagToken, a.Html, a.Html.String())
   517  	return false
   518  }
   519  
   520  // Section 12.2.5.4.3.
   521  func beforeHeadIM(p *parser) bool {
   522  	switch p.tok.Type {
   523  	case TextToken:
   524  		p.tok.Data = strings.TrimLeft(p.tok.Data, whitespace)
   525  		if len(p.tok.Data) == 0 {
   526  			// It was all whitespace, so ignore it.
   527  			return true
   528  		}
   529  	case StartTagToken:
   530  		switch p.tok.DataAtom {
   531  		case a.Head:
   532  			p.addElement()
   533  			p.head = p.top()
   534  			p.im = inHeadIM
   535  			return true
   536  		case a.Html:
   537  			return inBodyIM(p)
   538  		}
   539  	case EndTagToken:
   540  		switch p.tok.DataAtom {
   541  		case a.Head, a.Body, a.Html, a.Br:
   542  			p.parseImpliedToken(StartTagToken, a.Head, a.Head.String())
   543  			return false
   544  		default:
   545  			// Ignore the token.
   546  			return true
   547  		}
   548  	case CommentToken:
   549  		p.addChild(&Node{
   550  			Type: CommentNode,
   551  			Data: p.tok.Data,
   552  		})
   553  		return true
   554  	case DoctypeToken:
   555  		// Ignore the token.
   556  		return true
   557  	}
   558  
   559  	p.parseImpliedToken(StartTagToken, a.Head, a.Head.String())
   560  	return false
   561  }
   562  
   563  // Section 12.2.5.4.4.
   564  func inHeadIM(p *parser) bool {
   565  	switch p.tok.Type {
   566  	case TextToken:
   567  		s := strings.TrimLeft(p.tok.Data, whitespace)
   568  		if len(s) < len(p.tok.Data) {
   569  			// Add the initial whitespace to the current node.
   570  			p.addText(p.tok.Data[:len(p.tok.Data)-len(s)])
   571  			if s == "" {
   572  				return true
   573  			}
   574  			p.tok.Data = s
   575  		}
   576  	case StartTagToken:
   577  		switch p.tok.DataAtom {
   578  		case a.Html:
   579  			return inBodyIM(p)
   580  		case a.Base, a.Basefont, a.Bgsound, a.Command, a.Link, a.Meta:
   581  			p.addElement()
   582  			p.oe.pop()
   583  			p.acknowledgeSelfClosingTag()
   584  			return true
   585  		case a.Script, a.Title, a.Noscript, a.Noframes, a.Style:
   586  			p.addElement()
   587  			p.setOriginalIM()
   588  			p.im = textIM
   589  			return true
   590  		case a.Head:
   591  			// Ignore the token.
   592  			return true
   593  		}
   594  	case EndTagToken:
   595  		switch p.tok.DataAtom {
   596  		case a.Head:
   597  			n := p.oe.pop()
   598  			if n.DataAtom != a.Head {
   599  				panic("html: bad parser state: <head> element not found, in the in-head insertion mode")
   600  			}
   601  			p.im = afterHeadIM
   602  			return true
   603  		case a.Body, a.Html, a.Br:
   604  			p.parseImpliedToken(EndTagToken, a.Head, a.Head.String())
   605  			return false
   606  		default:
   607  			// Ignore the token.
   608  			return true
   609  		}
   610  	case CommentToken:
   611  		p.addChild(&Node{
   612  			Type: CommentNode,
   613  			Data: p.tok.Data,
   614  		})
   615  		return true
   616  	case DoctypeToken:
   617  		// Ignore the token.
   618  		return true
   619  	}
   620  
   621  	p.parseImpliedToken(EndTagToken, a.Head, a.Head.String())
   622  	return false
   623  }
   624  
   625  // Section 12.2.5.4.6.
   626  func afterHeadIM(p *parser) bool {
   627  	switch p.tok.Type {
   628  	case TextToken:
   629  		s := strings.TrimLeft(p.tok.Data, whitespace)
   630  		if len(s) < len(p.tok.Data) {
   631  			// Add the initial whitespace to the current node.
   632  			p.addText(p.tok.Data[:len(p.tok.Data)-len(s)])
   633  			if s == "" {
   634  				return true
   635  			}
   636  			p.tok.Data = s
   637  		}
   638  	case StartTagToken:
   639  		switch p.tok.DataAtom {
   640  		case a.Html:
   641  			return inBodyIM(p)
   642  		case a.Body:
   643  			p.addElement()
   644  			p.framesetOK = false
   645  			p.im = inBodyIM
   646  			return true
   647  		case a.Frameset:
   648  			p.addElement()
   649  			p.im = inFramesetIM
   650  			return true
   651  		case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Title:
   652  			p.oe = append(p.oe, p.head)
   653  			defer p.oe.remove(p.head)
   654  			return inHeadIM(p)
   655  		case a.Head:
   656  			// Ignore the token.
   657  			return true
   658  		}
   659  	case EndTagToken:
   660  		switch p.tok.DataAtom {
   661  		case a.Body, a.Html, a.Br:
   662  			// Drop down to creating an implied <body> tag.
   663  		default:
   664  			// Ignore the token.
   665  			return true
   666  		}
   667  	case CommentToken:
   668  		p.addChild(&Node{
   669  			Type: CommentNode,
   670  			Data: p.tok.Data,
   671  		})
   672  		return true
   673  	case DoctypeToken:
   674  		// Ignore the token.
   675  		return true
   676  	}
   677  
   678  	p.parseImpliedToken(StartTagToken, a.Body, a.Body.String())
   679  	p.framesetOK = true
   680  	return false
   681  }
   682  
   683  // copyAttributes copies attributes of src not found on dst to dst.
   684  func copyAttributes(dst *Node, src Token) {
   685  	if len(src.Attr) == 0 {
   686  		return
   687  	}
   688  	attr := map[string]string{}
   689  	for _, t := range dst.Attr {
   690  		attr[t.Key] = t.Val
   691  	}
   692  	for _, t := range src.Attr {
   693  		if _, ok := attr[t.Key]; !ok {
   694  			dst.Attr = append(dst.Attr, t)
   695  			attr[t.Key] = t.Val
   696  		}
   697  	}
   698  }
   699  
   700  // Section 12.2.5.4.7.
   701  func inBodyIM(p *parser) bool {
   702  	switch p.tok.Type {
   703  	case TextToken:
   704  		d := p.tok.Data
   705  		switch n := p.oe.top(); n.DataAtom {
   706  		case a.Pre, a.Listing:
   707  			if n.FirstChild == nil {
   708  				// Ignore a newline at the start of a <pre> block.
   709  				if d != "" && d[0] == '\r' {
   710  					d = d[1:]
   711  				}
   712  				if d != "" && d[0] == '\n' {
   713  					d = d[1:]
   714  				}
   715  			}
   716  		}
   717  		d = strings.Replace(d, "\x00", "", -1)
   718  		if d == "" {
   719  			return true
   720  		}
   721  		p.reconstructActiveFormattingElements()
   722  		p.addText(d)
   723  		if p.framesetOK && strings.TrimLeft(d, whitespace) != "" {
   724  			// There were non-whitespace characters inserted.
   725  			p.framesetOK = false
   726  		}
   727  	case StartTagToken:
   728  		switch p.tok.DataAtom {
   729  		case a.Html:
   730  			copyAttributes(p.oe[0], p.tok)
   731  		case a.Base, a.Basefont, a.Bgsound, a.Command, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Title:
   732  			return inHeadIM(p)
   733  		case a.Body:
   734  			if len(p.oe) >= 2 {
   735  				body := p.oe[1]
   736  				if body.Type == ElementNode && body.DataAtom == a.Body {
   737  					p.framesetOK = false
   738  					copyAttributes(body, p.tok)
   739  				}
   740  			}
   741  		case a.Frameset:
   742  			if !p.framesetOK || len(p.oe) < 2 || p.oe[1].DataAtom != a.Body {
   743  				// Ignore the token.
   744  				return true
   745  			}
   746  			body := p.oe[1]
   747  			if body.Parent != nil {
   748  				body.Parent.RemoveChild(body)
   749  			}
   750  			p.oe = p.oe[:1]
   751  			p.addElement()
   752  			p.im = inFramesetIM
   753  			return true
   754  		case a.Address, a.Article, a.Aside, a.Blockquote, a.Center, a.Details, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Menu, a.Nav, a.Ol, a.P, a.Section, a.Summary, a.Ul:
   755  			p.popUntil(buttonScope, a.P)
   756  			p.addElement()
   757  		case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6:
   758  			p.popUntil(buttonScope, a.P)
   759  			switch n := p.top(); n.DataAtom {
   760  			case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6:
   761  				p.oe.pop()
   762  			}
   763  			p.addElement()
   764  		case a.Pre, a.Listing:
   765  			p.popUntil(buttonScope, a.P)
   766  			p.addElement()
   767  			// The newline, if any, will be dealt with by the TextToken case.
   768  			p.framesetOK = false
   769  		case a.Form:
   770  			if p.form == nil {
   771  				p.popUntil(buttonScope, a.P)
   772  				p.addElement()
   773  				p.form = p.top()
   774  			}
   775  		case a.Li:
   776  			p.framesetOK = false
   777  			for i := len(p.oe) - 1; i >= 0; i-- {
   778  				node := p.oe[i]
   779  				switch node.DataAtom {
   780  				case a.Li:
   781  					p.oe = p.oe[:i]
   782  				case a.Address, a.Div, a.P:
   783  					continue
   784  				default:
   785  					if !isSpecialElement(node) {
   786  						continue
   787  					}
   788  				}
   789  				break
   790  			}
   791  			p.popUntil(buttonScope, a.P)
   792  			p.addElement()
   793  		case a.Dd, a.Dt:
   794  			p.framesetOK = false
   795  			for i := len(p.oe) - 1; i >= 0; i-- {
   796  				node := p.oe[i]
   797  				switch node.DataAtom {
   798  				case a.Dd, a.Dt:
   799  					p.oe = p.oe[:i]
   800  				case a.Address, a.Div, a.P:
   801  					continue
   802  				default:
   803  					if !isSpecialElement(node) {
   804  						continue
   805  					}
   806  				}
   807  				break
   808  			}
   809  			p.popUntil(buttonScope, a.P)
   810  			p.addElement()
   811  		case a.Plaintext:
   812  			p.popUntil(buttonScope, a.P)
   813  			p.addElement()
   814  		case a.Button:
   815  			p.popUntil(defaultScope, a.Button)
   816  			p.reconstructActiveFormattingElements()
   817  			p.addElement()
   818  			p.framesetOK = false
   819  		case a.A:
   820  			for i := len(p.afe) - 1; i >= 0 && p.afe[i].Type != scopeMarkerNode; i-- {
   821  				if n := p.afe[i]; n.Type == ElementNode && n.DataAtom == a.A {
   822  					p.inBodyEndTagFormatting(a.A)
   823  					p.oe.remove(n)
   824  					p.afe.remove(n)
   825  					break
   826  				}
   827  			}
   828  			p.reconstructActiveFormattingElements()
   829  			p.addFormattingElement()
   830  		case a.B, a.Big, a.Code, a.Em, a.Font, a.I, a.S, a.Small, a.Strike, a.Strong, a.Tt, a.U:
   831  			p.reconstructActiveFormattingElements()
   832  			p.addFormattingElement()
   833  		case a.Nobr:
   834  			p.reconstructActiveFormattingElements()
   835  			if p.elementInScope(defaultScope, a.Nobr) {
   836  				p.inBodyEndTagFormatting(a.Nobr)
   837  				p.reconstructActiveFormattingElements()
   838  			}
   839  			p.addFormattingElement()
   840  		case a.Applet, a.Marquee, a.Object:
   841  			p.reconstructActiveFormattingElements()
   842  			p.addElement()
   843  			p.afe = append(p.afe, &scopeMarker)
   844  			p.framesetOK = false
   845  		case a.Table:
   846  			if !p.quirks {
   847  				p.popUntil(buttonScope, a.P)
   848  			}
   849  			p.addElement()
   850  			p.framesetOK = false
   851  			p.im = inTableIM
   852  			return true
   853  		case a.Area, a.Br, a.Embed, a.Img, a.Input, a.Keygen, a.Wbr:
   854  			p.reconstructActiveFormattingElements()
   855  			p.addElement()
   856  			p.oe.pop()
   857  			p.acknowledgeSelfClosingTag()
   858  			if p.tok.DataAtom == a.Input {
   859  				for _, t := range p.tok.Attr {
   860  					if t.Key == "type" {
   861  						if strings.ToLower(t.Val) == "hidden" {
   862  							// Skip setting framesetOK = false
   863  							return true
   864  						}
   865  					}
   866  				}
   867  			}
   868  			p.framesetOK = false
   869  		case a.Param, a.Source, a.Track:
   870  			p.addElement()
   871  			p.oe.pop()
   872  			p.acknowledgeSelfClosingTag()
   873  		case a.Hr:
   874  			p.popUntil(buttonScope, a.P)
   875  			p.addElement()
   876  			p.oe.pop()
   877  			p.acknowledgeSelfClosingTag()
   878  			p.framesetOK = false
   879  		case a.Image:
   880  			p.tok.DataAtom = a.Img
   881  			p.tok.Data = a.Img.String()
   882  			return false
   883  		case a.Isindex:
   884  			if p.form != nil {
   885  				// Ignore the token.
   886  				return true
   887  			}
   888  			action := ""
   889  			prompt := "This is a searchable index. Enter search keywords: "
   890  			attr := []Attribute{{Key: "name", Val: "isindex"}}
   891  			for _, t := range p.tok.Attr {
   892  				switch t.Key {
   893  				case "action":
   894  					action = t.Val
   895  				case "name":
   896  					// Ignore the attribute.
   897  				case "prompt":
   898  					prompt = t.Val
   899  				default:
   900  					attr = append(attr, t)
   901  				}
   902  			}
   903  			p.acknowledgeSelfClosingTag()
   904  			p.popUntil(buttonScope, a.P)
   905  			p.parseImpliedToken(StartTagToken, a.Form, a.Form.String())
   906  			if action != "" {
   907  				p.form.Attr = []Attribute{{Key: "action", Val: action}}
   908  			}
   909  			p.parseImpliedToken(StartTagToken, a.Hr, a.Hr.String())
   910  			p.parseImpliedToken(StartTagToken, a.Label, a.Label.String())
   911  			p.addText(prompt)
   912  			p.addChild(&Node{
   913  				Type:     ElementNode,
   914  				DataAtom: a.Input,
   915  				Data:     a.Input.String(),
   916  				Attr:     attr,
   917  			})
   918  			p.oe.pop()
   919  			p.parseImpliedToken(EndTagToken, a.Label, a.Label.String())
   920  			p.parseImpliedToken(StartTagToken, a.Hr, a.Hr.String())
   921  			p.parseImpliedToken(EndTagToken, a.Form, a.Form.String())
   922  		case a.Textarea:
   923  			p.addElement()
   924  			p.setOriginalIM()
   925  			p.framesetOK = false
   926  			p.im = textIM
   927  		case a.Xmp:
   928  			p.popUntil(buttonScope, a.P)
   929  			p.reconstructActiveFormattingElements()
   930  			p.framesetOK = false
   931  			p.addElement()
   932  			p.setOriginalIM()
   933  			p.im = textIM
   934  		case a.Iframe:
   935  			p.framesetOK = false
   936  			p.addElement()
   937  			p.setOriginalIM()
   938  			p.im = textIM
   939  		case a.Noembed, a.Noscript:
   940  			p.addElement()
   941  			p.setOriginalIM()
   942  			p.im = textIM
   943  		case a.Select:
   944  			p.reconstructActiveFormattingElements()
   945  			p.addElement()
   946  			p.framesetOK = false
   947  			p.im = inSelectIM
   948  			return true
   949  		case a.Optgroup, a.Option:
   950  			if p.top().DataAtom == a.Option {
   951  				p.oe.pop()
   952  			}
   953  			p.reconstructActiveFormattingElements()
   954  			p.addElement()
   955  		case a.Rp, a.Rt:
   956  			if p.elementInScope(defaultScope, a.Ruby) {
   957  				p.generateImpliedEndTags()
   958  			}
   959  			p.addElement()
   960  		case a.Math, a.Svg:
   961  			p.reconstructActiveFormattingElements()
   962  			if p.tok.DataAtom == a.Math {
   963  				adjustAttributeNames(p.tok.Attr, mathMLAttributeAdjustments)
   964  			} else {
   965  				adjustAttributeNames(p.tok.Attr, svgAttributeAdjustments)
   966  			}
   967  			adjustForeignAttributes(p.tok.Attr)
   968  			p.addElement()
   969  			p.top().Namespace = p.tok.Data
   970  			if p.hasSelfClosingToken {
   971  				p.oe.pop()
   972  				p.acknowledgeSelfClosingTag()
   973  			}
   974  			return true
   975  		case a.Caption, a.Col, a.Colgroup, a.Frame, a.Head, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
   976  			// Ignore the token.
   977  		default:
   978  			p.reconstructActiveFormattingElements()
   979  			p.addElement()
   980  		}
   981  	case EndTagToken:
   982  		switch p.tok.DataAtom {
   983  		case a.Body:
   984  			if p.elementInScope(defaultScope, a.Body) {
   985  				p.im = afterBodyIM
   986  			}
   987  		case a.Html:
   988  			if p.elementInScope(defaultScope, a.Body) {
   989  				p.parseImpliedToken(EndTagToken, a.Body, a.Body.String())
   990  				return false
   991  			}
   992  			return true
   993  		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:
   994  			p.popUntil(defaultScope, p.tok.DataAtom)
   995  		case a.Form:
   996  			node := p.form
   997  			p.form = nil
   998  			i := p.indexOfElementInScope(defaultScope, a.Form)
   999  			if node == nil || i == -1 || p.oe[i] != node {
  1000  				// Ignore the token.
  1001  				return true
  1002  			}
  1003  			p.generateImpliedEndTags()
  1004  			p.oe.remove(node)
  1005  		case a.P:
  1006  			if !p.elementInScope(buttonScope, a.P) {
  1007  				p.parseImpliedToken(StartTagToken, a.P, a.P.String())
  1008  			}
  1009  			p.popUntil(buttonScope, a.P)
  1010  		case a.Li:
  1011  			p.popUntil(listItemScope, a.Li)
  1012  		case a.Dd, a.Dt:
  1013  			p.popUntil(defaultScope, p.tok.DataAtom)
  1014  		case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6:
  1015  			p.popUntil(defaultScope, a.H1, a.H2, a.H3, a.H4, a.H5, a.H6)
  1016  		case a.A, a.B, a.Big, a.Code, a.Em, a.Font, a.I, a.Nobr, a.S, a.Small, a.Strike, a.Strong, a.Tt, a.U:
  1017  			p.inBodyEndTagFormatting(p.tok.DataAtom)
  1018  		case a.Applet, a.Marquee, a.Object:
  1019  			if p.popUntil(defaultScope, p.tok.DataAtom) {
  1020  				p.clearActiveFormattingElements()
  1021  			}
  1022  		case a.Br:
  1023  			p.tok.Type = StartTagToken
  1024  			return false
  1025  		default:
  1026  			p.inBodyEndTagOther(p.tok.DataAtom)
  1027  		}
  1028  	case CommentToken:
  1029  		p.addChild(&Node{
  1030  			Type: CommentNode,
  1031  			Data: p.tok.Data,
  1032  		})
  1033  	}
  1034  
  1035  	return true
  1036  }
  1037  
  1038  func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom) {
  1039  	// This is the "adoption agency" algorithm, described at
  1040  	// https://html.spec.whatwg.org/multipage/syntax.html#adoptionAgency
  1041  
  1042  	// TODO: this is a fairly literal line-by-line translation of that algorithm.
  1043  	// Once the code successfully parses the comprehensive test suite, we should
  1044  	// refactor this code to be more idiomatic.
  1045  
  1046  	// Steps 1-4. The outer loop.
  1047  	for i := 0; i < 8; i++ {
  1048  		// Step 5. Find the formatting element.
  1049  		var formattingElement *Node
  1050  		for j := len(p.afe) - 1; j >= 0; j-- {
  1051  			if p.afe[j].Type == scopeMarkerNode {
  1052  				break
  1053  			}
  1054  			if p.afe[j].DataAtom == tagAtom {
  1055  				formattingElement = p.afe[j]
  1056  				break
  1057  			}
  1058  		}
  1059  		if formattingElement == nil {
  1060  			p.inBodyEndTagOther(tagAtom)
  1061  			return
  1062  		}
  1063  		feIndex := p.oe.index(formattingElement)
  1064  		if feIndex == -1 {
  1065  			p.afe.remove(formattingElement)
  1066  			return
  1067  		}
  1068  		if !p.elementInScope(defaultScope, tagAtom) {
  1069  			// Ignore the tag.
  1070  			return
  1071  		}
  1072  
  1073  		// Steps 9-10. Find the furthest block.
  1074  		var furthestBlock *Node
  1075  		for _, e := range p.oe[feIndex:] {
  1076  			if isSpecialElement(e) {
  1077  				furthestBlock = e
  1078  				break
  1079  			}
  1080  		}
  1081  		if furthestBlock == nil {
  1082  			e := p.oe.pop()
  1083  			for e != formattingElement {
  1084  				e = p.oe.pop()
  1085  			}
  1086  			p.afe.remove(e)
  1087  			return
  1088  		}
  1089  
  1090  		// Steps 11-12. Find the common ancestor and bookmark node.
  1091  		commonAncestor := p.oe[feIndex-1]
  1092  		bookmark := p.afe.index(formattingElement)
  1093  
  1094  		// Step 13. The inner loop. Find the lastNode to reparent.
  1095  		lastNode := furthestBlock
  1096  		node := furthestBlock
  1097  		x := p.oe.index(node)
  1098  		// Steps 13.1-13.2
  1099  		for j := 0; j < 3; j++ {
  1100  			// Step 13.3.
  1101  			x--
  1102  			node = p.oe[x]
  1103  			// Step 13.4 - 13.5.
  1104  			if p.afe.index(node) == -1 {
  1105  				p.oe.remove(node)
  1106  				continue
  1107  			}
  1108  			// Step 13.6.
  1109  			if node == formattingElement {
  1110  				break
  1111  			}
  1112  			// Step 13.7.
  1113  			clone := node.clone()
  1114  			p.afe[p.afe.index(node)] = clone
  1115  			p.oe[p.oe.index(node)] = clone
  1116  			node = clone
  1117  			// Step 13.8.
  1118  			if lastNode == furthestBlock {
  1119  				bookmark = p.afe.index(node) + 1
  1120  			}
  1121  			// Step 13.9.
  1122  			if lastNode.Parent != nil {
  1123  				lastNode.Parent.RemoveChild(lastNode)
  1124  			}
  1125  			node.AppendChild(lastNode)
  1126  			// Step 13.10.
  1127  			lastNode = node
  1128  		}
  1129  
  1130  		// Step 14. Reparent lastNode to the common ancestor,
  1131  		// or for misnested table nodes, to the foster parent.
  1132  		if lastNode.Parent != nil {
  1133  			lastNode.Parent.RemoveChild(lastNode)
  1134  		}
  1135  		switch commonAncestor.DataAtom {
  1136  		case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr:
  1137  			p.fosterParent(lastNode)
  1138  		default:
  1139  			commonAncestor.AppendChild(lastNode)
  1140  		}
  1141  
  1142  		// Steps 15-17. Reparent nodes from the furthest block's children
  1143  		// to a clone of the formatting element.
  1144  		clone := formattingElement.clone()
  1145  		reparentChildren(clone, furthestBlock)
  1146  		furthestBlock.AppendChild(clone)
  1147  
  1148  		// Step 18. Fix up the list of active formatting elements.
  1149  		if oldLoc := p.afe.index(formattingElement); oldLoc != -1 && oldLoc < bookmark {
  1150  			// Move the bookmark with the rest of the list.
  1151  			bookmark--
  1152  		}
  1153  		p.afe.remove(formattingElement)
  1154  		p.afe.insert(bookmark, clone)
  1155  
  1156  		// Step 19. Fix up the stack of open elements.
  1157  		p.oe.remove(formattingElement)
  1158  		p.oe.insert(p.oe.index(furthestBlock)+1, clone)
  1159  	}
  1160  }
  1161  
  1162  // inBodyEndTagOther performs the "any other end tag" algorithm for inBodyIM.
  1163  // "Any other end tag" handling from 12.2.5.5 The rules for parsing tokens in foreign content
  1164  // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inforeign
  1165  func (p *parser) inBodyEndTagOther(tagAtom a.Atom) {
  1166  	for i := len(p.oe) - 1; i >= 0; i-- {
  1167  		if p.oe[i].DataAtom == tagAtom {
  1168  			p.oe = p.oe[:i]
  1169  			break
  1170  		}
  1171  		if isSpecialElement(p.oe[i]) {
  1172  			break
  1173  		}
  1174  	}
  1175  }
  1176  
  1177  // Section 12.2.5.4.8.
  1178  func textIM(p *parser) bool {
  1179  	switch p.tok.Type {
  1180  	case ErrorToken:
  1181  		p.oe.pop()
  1182  	case TextToken:
  1183  		d := p.tok.Data
  1184  		if n := p.oe.top(); n.DataAtom == a.Textarea && n.FirstChild == nil {
  1185  			// Ignore a newline at the start of a <textarea> block.
  1186  			if d != "" && d[0] == '\r' {
  1187  				d = d[1:]
  1188  			}
  1189  			if d != "" && d[0] == '\n' {
  1190  				d = d[1:]
  1191  			}
  1192  		}
  1193  		if d == "" {
  1194  			return true
  1195  		}
  1196  		p.addText(d)
  1197  		return true
  1198  	case EndTagToken:
  1199  		p.oe.pop()
  1200  	}
  1201  	p.im = p.originalIM
  1202  	p.originalIM = nil
  1203  	return p.tok.Type == EndTagToken
  1204  }
  1205  
  1206  // Section 12.2.5.4.9.
  1207  func inTableIM(p *parser) bool {
  1208  	switch p.tok.Type {
  1209  	case ErrorToken:
  1210  		// Stop parsing.
  1211  		return true
  1212  	case TextToken:
  1213  		p.tok.Data = strings.Replace(p.tok.Data, "\x00", "", -1)
  1214  		switch p.oe.top().DataAtom {
  1215  		case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr:
  1216  			if strings.Trim(p.tok.Data, whitespace) == "" {
  1217  				p.addText(p.tok.Data)
  1218  				return true
  1219  			}
  1220  		}
  1221  	case StartTagToken:
  1222  		switch p.tok.DataAtom {
  1223  		case a.Caption:
  1224  			p.clearStackToContext(tableScope)
  1225  			p.afe = append(p.afe, &scopeMarker)
  1226  			p.addElement()
  1227  			p.im = inCaptionIM
  1228  			return true
  1229  		case a.Colgroup:
  1230  			p.clearStackToContext(tableScope)
  1231  			p.addElement()
  1232  			p.im = inColumnGroupIM
  1233  			return true
  1234  		case a.Col:
  1235  			p.parseImpliedToken(StartTagToken, a.Colgroup, a.Colgroup.String())
  1236  			return false
  1237  		case a.Tbody, a.Tfoot, a.Thead:
  1238  			p.clearStackToContext(tableScope)
  1239  			p.addElement()
  1240  			p.im = inTableBodyIM
  1241  			return true
  1242  		case a.Td, a.Th, a.Tr:
  1243  			p.parseImpliedToken(StartTagToken, a.Tbody, a.Tbody.String())
  1244  			return false
  1245  		case a.Table:
  1246  			if p.popUntil(tableScope, a.Table) {
  1247  				p.resetInsertionMode()
  1248  				return false
  1249  			}
  1250  			// Ignore the token.
  1251  			return true
  1252  		case a.Style, a.Script:
  1253  			return inHeadIM(p)
  1254  		case a.Input:
  1255  			for _, t := range p.tok.Attr {
  1256  				if t.Key == "type" && strings.ToLower(t.Val) == "hidden" {
  1257  					p.addElement()
  1258  					p.oe.pop()
  1259  					return true
  1260  				}
  1261  			}
  1262  			// Otherwise drop down to the default action.
  1263  		case a.Form:
  1264  			if p.form != nil {
  1265  				// Ignore the token.
  1266  				return true
  1267  			}
  1268  			p.addElement()
  1269  			p.form = p.oe.pop()
  1270  		case a.Select:
  1271  			p.reconstructActiveFormattingElements()
  1272  			switch p.top().DataAtom {
  1273  			case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr:
  1274  				p.fosterParenting = true
  1275  			}
  1276  			p.addElement()
  1277  			p.fosterParenting = false
  1278  			p.framesetOK = false
  1279  			p.im = inSelectInTableIM
  1280  			return true
  1281  		}
  1282  	case EndTagToken:
  1283  		switch p.tok.DataAtom {
  1284  		case a.Table:
  1285  			if p.popUntil(tableScope, a.Table) {
  1286  				p.resetInsertionMode()
  1287  				return true
  1288  			}
  1289  			// Ignore the token.
  1290  			return true
  1291  		case a.Body, a.Caption, a.Col, a.Colgroup, a.Html, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
  1292  			// Ignore the token.
  1293  			return true
  1294  		}
  1295  	case CommentToken:
  1296  		p.addChild(&Node{
  1297  			Type: CommentNode,
  1298  			Data: p.tok.Data,
  1299  		})
  1300  		return true
  1301  	case DoctypeToken:
  1302  		// Ignore the token.
  1303  		return true
  1304  	}
  1305  
  1306  	p.fosterParenting = true
  1307  	defer func() { p.fosterParenting = false }()
  1308  
  1309  	return inBodyIM(p)
  1310  }
  1311  
  1312  // Section 12.2.5.4.11.
  1313  func inCaptionIM(p *parser) bool {
  1314  	switch p.tok.Type {
  1315  	case StartTagToken:
  1316  		switch p.tok.DataAtom {
  1317  		case a.Caption, a.Col, a.Colgroup, a.Tbody, a.Td, a.Tfoot, a.Thead, a.Tr:
  1318  			if p.popUntil(tableScope, a.Caption) {
  1319  				p.clearActiveFormattingElements()
  1320  				p.im = inTableIM
  1321  				return false
  1322  			} else {
  1323  				// Ignore the token.
  1324  				return true
  1325  			}
  1326  		case a.Select:
  1327  			p.reconstructActiveFormattingElements()
  1328  			p.addElement()
  1329  			p.framesetOK = false
  1330  			p.im = inSelectInTableIM
  1331  			return true
  1332  		}
  1333  	case EndTagToken:
  1334  		switch p.tok.DataAtom {
  1335  		case a.Caption:
  1336  			if p.popUntil(tableScope, a.Caption) {
  1337  				p.clearActiveFormattingElements()
  1338  				p.im = inTableIM
  1339  			}
  1340  			return true
  1341  		case a.Table:
  1342  			if p.popUntil(tableScope, a.Caption) {
  1343  				p.clearActiveFormattingElements()
  1344  				p.im = inTableIM
  1345  				return false
  1346  			} else {
  1347  				// Ignore the token.
  1348  				return true
  1349  			}
  1350  		case a.Body, a.Col, a.Colgroup, a.Html, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
  1351  			// Ignore the token.
  1352  			return true
  1353  		}
  1354  	}
  1355  	return inBodyIM(p)
  1356  }
  1357  
  1358  // Section 12.2.5.4.12.
  1359  func inColumnGroupIM(p *parser) bool {
  1360  	switch p.tok.Type {
  1361  	case TextToken:
  1362  		s := strings.TrimLeft(p.tok.Data, whitespace)
  1363  		if len(s) < len(p.tok.Data) {
  1364  			// Add the initial whitespace to the current node.
  1365  			p.addText(p.tok.Data[:len(p.tok.Data)-len(s)])
  1366  			if s == "" {
  1367  				return true
  1368  			}
  1369  			p.tok.Data = s
  1370  		}
  1371  	case CommentToken:
  1372  		p.addChild(&Node{
  1373  			Type: CommentNode,
  1374  			Data: p.tok.Data,
  1375  		})
  1376  		return true
  1377  	case DoctypeToken:
  1378  		// Ignore the token.
  1379  		return true
  1380  	case StartTagToken:
  1381  		switch p.tok.DataAtom {
  1382  		case a.Html:
  1383  			return inBodyIM(p)
  1384  		case a.Col:
  1385  			p.addElement()
  1386  			p.oe.pop()
  1387  			p.acknowledgeSelfClosingTag()
  1388  			return true
  1389  		}
  1390  	case EndTagToken:
  1391  		switch p.tok.DataAtom {
  1392  		case a.Colgroup:
  1393  			if p.oe.top().DataAtom != a.Html {
  1394  				p.oe.pop()
  1395  				p.im = inTableIM
  1396  			}
  1397  			return true
  1398  		case a.Col:
  1399  			// Ignore the token.
  1400  			return true
  1401  		}
  1402  	}
  1403  	if p.oe.top().DataAtom != a.Html {
  1404  		p.oe.pop()
  1405  		p.im = inTableIM
  1406  		return false
  1407  	}
  1408  	return true
  1409  }
  1410  
  1411  // Section 12.2.5.4.13.
  1412  func inTableBodyIM(p *parser) bool {
  1413  	switch p.tok.Type {
  1414  	case StartTagToken:
  1415  		switch p.tok.DataAtom {
  1416  		case a.Tr:
  1417  			p.clearStackToContext(tableBodyScope)
  1418  			p.addElement()
  1419  			p.im = inRowIM
  1420  			return true
  1421  		case a.Td, a.Th:
  1422  			p.parseImpliedToken(StartTagToken, a.Tr, a.Tr.String())
  1423  			return false
  1424  		case a.Caption, a.Col, a.Colgroup, a.Tbody, a.Tfoot, a.Thead:
  1425  			if p.popUntil(tableScope, a.Tbody, a.Thead, a.Tfoot) {
  1426  				p.im = inTableIM
  1427  				return false
  1428  			}
  1429  			// Ignore the token.
  1430  			return true
  1431  		}
  1432  	case EndTagToken:
  1433  		switch p.tok.DataAtom {
  1434  		case a.Tbody, a.Tfoot, a.Thead:
  1435  			if p.elementInScope(tableScope, p.tok.DataAtom) {
  1436  				p.clearStackToContext(tableBodyScope)
  1437  				p.oe.pop()
  1438  				p.im = inTableIM
  1439  			}
  1440  			return true
  1441  		case a.Table:
  1442  			if p.popUntil(tableScope, a.Tbody, a.Thead, a.Tfoot) {
  1443  				p.im = inTableIM
  1444  				return false
  1445  			}
  1446  			// Ignore the token.
  1447  			return true
  1448  		case a.Body, a.Caption, a.Col, a.Colgroup, a.Html, a.Td, a.Th, a.Tr:
  1449  			// Ignore the token.
  1450  			return true
  1451  		}
  1452  	case CommentToken:
  1453  		p.addChild(&Node{
  1454  			Type: CommentNode,
  1455  			Data: p.tok.Data,
  1456  		})
  1457  		return true
  1458  	}
  1459  
  1460  	return inTableIM(p)
  1461  }
  1462  
  1463  // Section 12.2.5.4.14.
  1464  func inRowIM(p *parser) bool {
  1465  	switch p.tok.Type {
  1466  	case StartTagToken:
  1467  		switch p.tok.DataAtom {
  1468  		case a.Td, a.Th:
  1469  			p.clearStackToContext(tableRowScope)
  1470  			p.addElement()
  1471  			p.afe = append(p.afe, &scopeMarker)
  1472  			p.im = inCellIM
  1473  			return true
  1474  		case a.Caption, a.Col, a.Colgroup, a.Tbody, a.Tfoot, a.Thead, a.Tr:
  1475  			if p.popUntil(tableScope, a.Tr) {
  1476  				p.im = inTableBodyIM
  1477  				return false
  1478  			}
  1479  			// Ignore the token.
  1480  			return true
  1481  		}
  1482  	case EndTagToken:
  1483  		switch p.tok.DataAtom {
  1484  		case a.Tr:
  1485  			if p.popUntil(tableScope, a.Tr) {
  1486  				p.im = inTableBodyIM
  1487  				return true
  1488  			}
  1489  			// Ignore the token.
  1490  			return true
  1491  		case a.Table:
  1492  			if p.popUntil(tableScope, a.Tr) {
  1493  				p.im = inTableBodyIM
  1494  				return false
  1495  			}
  1496  			// Ignore the token.
  1497  			return true
  1498  		case a.Tbody, a.Tfoot, a.Thead:
  1499  			if p.elementInScope(tableScope, p.tok.DataAtom) {
  1500  				p.parseImpliedToken(EndTagToken, a.Tr, a.Tr.String())
  1501  				return false
  1502  			}
  1503  			// Ignore the token.
  1504  			return true
  1505  		case a.Body, a.Caption, a.Col, a.Colgroup, a.Html, a.Td, a.Th:
  1506  			// Ignore the token.
  1507  			return true
  1508  		}
  1509  	}
  1510  
  1511  	return inTableIM(p)
  1512  }
  1513  
  1514  // Section 12.2.5.4.15.
  1515  func inCellIM(p *parser) bool {
  1516  	switch p.tok.Type {
  1517  	case StartTagToken:
  1518  		switch p.tok.DataAtom {
  1519  		case a.Caption, a.Col, a.Colgroup, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
  1520  			if p.popUntil(tableScope, a.Td, a.Th) {
  1521  				// Close the cell and reprocess.
  1522  				p.clearActiveFormattingElements()
  1523  				p.im = inRowIM
  1524  				return false
  1525  			}
  1526  			// Ignore the token.
  1527  			return true
  1528  		case a.Select:
  1529  			p.reconstructActiveFormattingElements()
  1530  			p.addElement()
  1531  			p.framesetOK = false
  1532  			p.im = inSelectInTableIM
  1533  			return true
  1534  		}
  1535  	case EndTagToken:
  1536  		switch p.tok.DataAtom {
  1537  		case a.Td, a.Th:
  1538  			if !p.popUntil(tableScope, p.tok.DataAtom) {
  1539  				// Ignore the token.
  1540  				return true
  1541  			}
  1542  			p.clearActiveFormattingElements()
  1543  			p.im = inRowIM
  1544  			return true
  1545  		case a.Body, a.Caption, a.Col, a.Colgroup, a.Html:
  1546  			// Ignore the token.
  1547  			return true
  1548  		case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr:
  1549  			if !p.elementInScope(tableScope, p.tok.DataAtom) {
  1550  				// Ignore the token.
  1551  				return true
  1552  			}
  1553  			// Close the cell and reprocess.
  1554  			p.popUntil(tableScope, a.Td, a.Th)
  1555  			p.clearActiveFormattingElements()
  1556  			p.im = inRowIM
  1557  			return false
  1558  		}
  1559  	}
  1560  	return inBodyIM(p)
  1561  }
  1562  
  1563  // Section 12.2.5.4.16.
  1564  func inSelectIM(p *parser) bool {
  1565  	switch p.tok.Type {
  1566  	case ErrorToken:
  1567  		// Stop parsing.
  1568  		return true
  1569  	case TextToken:
  1570  		p.addText(strings.Replace(p.tok.Data, "\x00", "", -1))
  1571  	case StartTagToken:
  1572  		switch p.tok.DataAtom {
  1573  		case a.Html:
  1574  			return inBodyIM(p)
  1575  		case a.Option:
  1576  			if p.top().DataAtom == a.Option {
  1577  				p.oe.pop()
  1578  			}
  1579  			p.addElement()
  1580  		case a.Optgroup:
  1581  			if p.top().DataAtom == a.Option {
  1582  				p.oe.pop()
  1583  			}
  1584  			if p.top().DataAtom == a.Optgroup {
  1585  				p.oe.pop()
  1586  			}
  1587  			p.addElement()
  1588  		case a.Select:
  1589  			p.tok.Type = EndTagToken
  1590  			return false
  1591  		case a.Input, a.Keygen, a.Textarea:
  1592  			if p.elementInScope(selectScope, a.Select) {
  1593  				p.parseImpliedToken(EndTagToken, a.Select, a.Select.String())
  1594  				return false
  1595  			}
  1596  			// In order to properly ignore <textarea>, we need to change the tokenizer mode.
  1597  			p.tokenizer.NextIsNotRawText()
  1598  			// Ignore the token.
  1599  			return true
  1600  		case a.Script:
  1601  			return inHeadIM(p)
  1602  		}
  1603  	case EndTagToken:
  1604  		switch p.tok.DataAtom {
  1605  		case a.Option:
  1606  			if p.top().DataAtom == a.Option {
  1607  				p.oe.pop()
  1608  			}
  1609  		case a.Optgroup:
  1610  			i := len(p.oe) - 1
  1611  			if p.oe[i].DataAtom == a.Option {
  1612  				i--
  1613  			}
  1614  			if p.oe[i].DataAtom == a.Optgroup {
  1615  				p.oe = p.oe[:i]
  1616  			}
  1617  		case a.Select:
  1618  			if p.popUntil(selectScope, a.Select) {
  1619  				p.resetInsertionMode()
  1620  			}
  1621  		}
  1622  	case CommentToken:
  1623  		p.addChild(&Node{
  1624  			Type: CommentNode,
  1625  			Data: p.tok.Data,
  1626  		})
  1627  	case DoctypeToken:
  1628  		// Ignore the token.
  1629  		return true
  1630  	}
  1631  
  1632  	return true
  1633  }
  1634  
  1635  // Section 12.2.5.4.17.
  1636  func inSelectInTableIM(p *parser) bool {
  1637  	switch p.tok.Type {
  1638  	case StartTagToken, EndTagToken:
  1639  		switch p.tok.DataAtom {
  1640  		case a.Caption, a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr, a.Td, a.Th:
  1641  			if p.tok.Type == StartTagToken || p.elementInScope(tableScope, p.tok.DataAtom) {
  1642  				p.parseImpliedToken(EndTagToken, a.Select, a.Select.String())
  1643  				return false
  1644  			} else {
  1645  				// Ignore the token.
  1646  				return true
  1647  			}
  1648  		}
  1649  	}
  1650  	return inSelectIM(p)
  1651  }
  1652  
  1653  // Section 12.2.5.4.18.
  1654  func afterBodyIM(p *parser) bool {
  1655  	switch p.tok.Type {
  1656  	case ErrorToken:
  1657  		// Stop parsing.
  1658  		return true
  1659  	case TextToken:
  1660  		s := strings.TrimLeft(p.tok.Data, whitespace)
  1661  		if len(s) == 0 {
  1662  			// It was all whitespace.
  1663  			return inBodyIM(p)
  1664  		}
  1665  	case StartTagToken:
  1666  		if p.tok.DataAtom == a.Html {
  1667  			return inBodyIM(p)
  1668  		}
  1669  	case EndTagToken:
  1670  		if p.tok.DataAtom == a.Html {
  1671  			if !p.fragment {
  1672  				p.im = afterAfterBodyIM
  1673  			}
  1674  			return true
  1675  		}
  1676  	case CommentToken:
  1677  		// The comment is attached to the <html> element.
  1678  		if len(p.oe) < 1 || p.oe[0].DataAtom != a.Html {
  1679  			panic("html: bad parser state: <html> element not found, in the after-body insertion mode")
  1680  		}
  1681  		p.oe[0].AppendChild(&Node{
  1682  			Type: CommentNode,
  1683  			Data: p.tok.Data,
  1684  		})
  1685  		return true
  1686  	}
  1687  	p.im = inBodyIM
  1688  	return false
  1689  }
  1690  
  1691  // Section 12.2.5.4.19.
  1692  func inFramesetIM(p *parser) bool {
  1693  	switch p.tok.Type {
  1694  	case CommentToken:
  1695  		p.addChild(&Node{
  1696  			Type: CommentNode,
  1697  			Data: p.tok.Data,
  1698  		})
  1699  	case TextToken:
  1700  		// Ignore all text but whitespace.
  1701  		s := strings.Map(func(c rune) rune {
  1702  			switch c {
  1703  			case ' ', '\t', '\n', '\f', '\r':
  1704  				return c
  1705  			}
  1706  			return -1
  1707  		}, p.tok.Data)
  1708  		if s != "" {
  1709  			p.addText(s)
  1710  		}
  1711  	case StartTagToken:
  1712  		switch p.tok.DataAtom {
  1713  		case a.Html:
  1714  			return inBodyIM(p)
  1715  		case a.Frameset:
  1716  			p.addElement()
  1717  		case a.Frame:
  1718  			p.addElement()
  1719  			p.oe.pop()
  1720  			p.acknowledgeSelfClosingTag()
  1721  		case a.Noframes:
  1722  			return inHeadIM(p)
  1723  		}
  1724  	case EndTagToken:
  1725  		switch p.tok.DataAtom {
  1726  		case a.Frameset:
  1727  			if p.oe.top().DataAtom != a.Html {
  1728  				p.oe.pop()
  1729  				if p.oe.top().DataAtom != a.Frameset {
  1730  					p.im = afterFramesetIM
  1731  					return true
  1732  				}
  1733  			}
  1734  		}
  1735  	default:
  1736  		// Ignore the token.
  1737  	}
  1738  	return true
  1739  }
  1740  
  1741  // Section 12.2.5.4.20.
  1742  func afterFramesetIM(p *parser) bool {
  1743  	switch p.tok.Type {
  1744  	case CommentToken:
  1745  		p.addChild(&Node{
  1746  			Type: CommentNode,
  1747  			Data: p.tok.Data,
  1748  		})
  1749  	case TextToken:
  1750  		// Ignore all text but whitespace.
  1751  		s := strings.Map(func(c rune) rune {
  1752  			switch c {
  1753  			case ' ', '\t', '\n', '\f', '\r':
  1754  				return c
  1755  			}
  1756  			return -1
  1757  		}, p.tok.Data)
  1758  		if s != "" {
  1759  			p.addText(s)
  1760  		}
  1761  	case StartTagToken:
  1762  		switch p.tok.DataAtom {
  1763  		case a.Html:
  1764  			return inBodyIM(p)
  1765  		case a.Noframes:
  1766  			return inHeadIM(p)
  1767  		}
  1768  	case EndTagToken:
  1769  		switch p.tok.DataAtom {
  1770  		case a.Html:
  1771  			p.im = afterAfterFramesetIM
  1772  			return true
  1773  		}
  1774  	default:
  1775  		// Ignore the token.
  1776  	}
  1777  	return true
  1778  }
  1779  
  1780  // Section 12.2.5.4.21.
  1781  func afterAfterBodyIM(p *parser) bool {
  1782  	switch p.tok.Type {
  1783  	case ErrorToken:
  1784  		// Stop parsing.
  1785  		return true
  1786  	case TextToken:
  1787  		s := strings.TrimLeft(p.tok.Data, whitespace)
  1788  		if len(s) == 0 {
  1789  			// It was all whitespace.
  1790  			return inBodyIM(p)
  1791  		}
  1792  	case StartTagToken:
  1793  		if p.tok.DataAtom == a.Html {
  1794  			return inBodyIM(p)
  1795  		}
  1796  	case CommentToken:
  1797  		p.doc.AppendChild(&Node{
  1798  			Type: CommentNode,
  1799  			Data: p.tok.Data,
  1800  		})
  1801  		return true
  1802  	case DoctypeToken:
  1803  		return inBodyIM(p)
  1804  	}
  1805  	p.im = inBodyIM
  1806  	return false
  1807  }
  1808  
  1809  // Section 12.2.5.4.22.
  1810  func afterAfterFramesetIM(p *parser) bool {
  1811  	switch p.tok.Type {
  1812  	case CommentToken:
  1813  		p.doc.AppendChild(&Node{
  1814  			Type: CommentNode,
  1815  			Data: p.tok.Data,
  1816  		})
  1817  	case TextToken:
  1818  		// Ignore all text but whitespace.
  1819  		s := strings.Map(func(c rune) rune {
  1820  			switch c {
  1821  			case ' ', '\t', '\n', '\f', '\r':
  1822  				return c
  1823  			}
  1824  			return -1
  1825  		}, p.tok.Data)
  1826  		if s != "" {
  1827  			p.tok.Data = s
  1828  			return inBodyIM(p)
  1829  		}
  1830  	case StartTagToken:
  1831  		switch p.tok.DataAtom {
  1832  		case a.Html:
  1833  			return inBodyIM(p)
  1834  		case a.Noframes:
  1835  			return inHeadIM(p)
  1836  		}
  1837  	case DoctypeToken:
  1838  		return inBodyIM(p)
  1839  	default:
  1840  		// Ignore the token.
  1841  	}
  1842  	return true
  1843  }
  1844  
  1845  const whitespaceOrNUL = whitespace + "\x00"
  1846  
  1847  // Section 12.2.5.5.
  1848  func parseForeignContent(p *parser) bool {
  1849  	switch p.tok.Type {
  1850  	case TextToken:
  1851  		if p.framesetOK {
  1852  			p.framesetOK = strings.TrimLeft(p.tok.Data, whitespaceOrNUL) == ""
  1853  		}
  1854  		p.tok.Data = strings.Replace(p.tok.Data, "\x00", "\ufffd", -1)
  1855  		p.addText(p.tok.Data)
  1856  	case CommentToken:
  1857  		p.addChild(&Node{
  1858  			Type: CommentNode,
  1859  			Data: p.tok.Data,
  1860  		})
  1861  	case StartTagToken:
  1862  		b := breakout[p.tok.Data]
  1863  		if p.tok.DataAtom == a.Font {
  1864  		loop:
  1865  			for _, attr := range p.tok.Attr {
  1866  				switch attr.Key {
  1867  				case "color", "face", "size":
  1868  					b = true
  1869  					break loop
  1870  				}
  1871  			}
  1872  		}
  1873  		if b {
  1874  			for i := len(p.oe) - 1; i >= 0; i-- {
  1875  				n := p.oe[i]
  1876  				if n.Namespace == "" || htmlIntegrationPoint(n) || mathMLTextIntegrationPoint(n) {
  1877  					p.oe = p.oe[:i+1]
  1878  					break
  1879  				}
  1880  			}
  1881  			return false
  1882  		}
  1883  		switch p.top().Namespace {
  1884  		case "math":
  1885  			adjustAttributeNames(p.tok.Attr, mathMLAttributeAdjustments)
  1886  		case "svg":
  1887  			// Adjust SVG tag names. The tokenizer lower-cases tag names, but
  1888  			// SVG wants e.g. "foreignObject" with a capital second "O".
  1889  			if x := svgTagNameAdjustments[p.tok.Data]; x != "" {
  1890  				p.tok.DataAtom = a.Lookup([]byte(x))
  1891  				p.tok.Data = x
  1892  			}
  1893  			adjustAttributeNames(p.tok.Attr, svgAttributeAdjustments)
  1894  		default:
  1895  			panic("html: bad parser state: unexpected namespace")
  1896  		}
  1897  		adjustForeignAttributes(p.tok.Attr)
  1898  		namespace := p.top().Namespace
  1899  		p.addElement()
  1900  		p.top().Namespace = namespace
  1901  		if namespace != "" {
  1902  			// Don't let the tokenizer go into raw text mode in foreign content
  1903  			// (e.g. in an SVG <title> tag).
  1904  			p.tokenizer.NextIsNotRawText()
  1905  		}
  1906  		if p.hasSelfClosingToken {
  1907  			p.oe.pop()
  1908  			p.acknowledgeSelfClosingTag()
  1909  		}
  1910  	case EndTagToken:
  1911  		for i := len(p.oe) - 1; i >= 0; i-- {
  1912  			if p.oe[i].Namespace == "" {
  1913  				return p.im(p)
  1914  			}
  1915  			if strings.EqualFold(p.oe[i].Data, p.tok.Data) {
  1916  				p.oe = p.oe[:i]
  1917  				break
  1918  			}
  1919  		}
  1920  		return true
  1921  	default:
  1922  		// Ignore the token.
  1923  	}
  1924  	return true
  1925  }
  1926  
  1927  // Section 12.2.5.
  1928  func (p *parser) inForeignContent() bool {
  1929  	if len(p.oe) == 0 {
  1930  		return false
  1931  	}
  1932  	n := p.oe[len(p.oe)-1]
  1933  	if n.Namespace == "" {
  1934  		return false
  1935  	}
  1936  	if mathMLTextIntegrationPoint(n) {
  1937  		if p.tok.Type == StartTagToken && p.tok.DataAtom != a.Mglyph && p.tok.DataAtom != a.Malignmark {
  1938  			return false
  1939  		}
  1940  		if p.tok.Type == TextToken {
  1941  			return false
  1942  		}
  1943  	}
  1944  	if n.Namespace == "math" && n.DataAtom == a.AnnotationXml && p.tok.Type == StartTagToken && p.tok.DataAtom == a.Svg {
  1945  		return false
  1946  	}
  1947  	if htmlIntegrationPoint(n) && (p.tok.Type == StartTagToken || p.tok.Type == TextToken) {
  1948  		return false
  1949  	}
  1950  	if p.tok.Type == ErrorToken {
  1951  		return false
  1952  	}
  1953  	return true
  1954  }
  1955  
  1956  // parseImpliedToken parses a token as though it had appeared in the parser's
  1957  // input.
  1958  func (p *parser) parseImpliedToken(t TokenType, dataAtom a.Atom, data string) {
  1959  	realToken, selfClosing := p.tok, p.hasSelfClosingToken
  1960  	p.tok = Token{
  1961  		Type:     t,
  1962  		DataAtom: dataAtom,
  1963  		Data:     data,
  1964  	}
  1965  	p.hasSelfClosingToken = false
  1966  	p.parseCurrentToken()
  1967  	p.tok, p.hasSelfClosingToken = realToken, selfClosing
  1968  }
  1969  
  1970  // parseCurrentToken runs the current token through the parsing routines
  1971  // until it is consumed.
  1972  func (p *parser) parseCurrentToken() {
  1973  	if p.tok.Type == SelfClosingTagToken {
  1974  		p.hasSelfClosingToken = true
  1975  		p.tok.Type = StartTagToken
  1976  	}
  1977  
  1978  	consumed := false
  1979  	for !consumed {
  1980  		if p.inForeignContent() {
  1981  			consumed = parseForeignContent(p)
  1982  		} else {
  1983  			consumed = p.im(p)
  1984  		}
  1985  	}
  1986  
  1987  	if p.hasSelfClosingToken {
  1988  		// This is a parse error, but ignore it.
  1989  		p.hasSelfClosingToken = false
  1990  	}
  1991  }
  1992  
  1993  func (p *parser) parse() error {
  1994  	// Iterate until EOF. Any other error will cause an early return.
  1995  	var err error
  1996  	for err != io.EOF {
  1997  		// CDATA sections are allowed only in foreign content.
  1998  		n := p.oe.top()
  1999  		p.tokenizer.AllowCDATA(n != nil && n.Namespace != "")
  2000  		// Read and parse the next token.
  2001  		p.tokenizer.Next()
  2002  		p.tok = p.tokenizer.Token()
  2003  		if p.tok.Type == ErrorToken {
  2004  			err = p.tokenizer.Err()
  2005  			if err != nil && err != io.EOF {
  2006  				return err
  2007  			}
  2008  		}
  2009  		p.parseCurrentToken()
  2010  	}
  2011  	return nil
  2012  }
  2013  
  2014  // Parse returns the parse tree for the HTML from the given Reader.
  2015  // The input is assumed to be UTF-8 encoded.
  2016  func Parse(r io.Reader) (*Node, error) {
  2017  	p := &parser{
  2018  		tokenizer: NewTokenizer(r),
  2019  		doc: &Node{
  2020  			Type: DocumentNode,
  2021  		},
  2022  		scripting:  true,
  2023  		framesetOK: true,
  2024  		im:         initialIM,
  2025  	}
  2026  	err := p.parse()
  2027  	if err != nil {
  2028  		return nil, err
  2029  	}
  2030  	return p.doc, nil
  2031  }
  2032  
  2033  // ParseFragment parses a fragment of HTML and returns the nodes that were
  2034  // found. If the fragment is the InnerHTML for an existing element, pass that
  2035  // element in context.
  2036  func ParseFragment(r io.Reader, context *Node) ([]*Node, error) {
  2037  	contextTag := ""
  2038  	if context != nil {
  2039  		if context.Type != ElementNode {
  2040  			return nil, errors.New("html: ParseFragment of non-element Node")
  2041  		}
  2042  		// The next check isn't just context.DataAtom.String() == context.Data because
  2043  		// it is valid to pass an element whose tag isn't a known atom. For example,
  2044  		// DataAtom == 0 and Data = "tagfromthefuture" is perfectly consistent.
  2045  		if context.DataAtom != a.Lookup([]byte(context.Data)) {
  2046  			return nil, fmt.Errorf("html: inconsistent Node: DataAtom=%q, Data=%q", context.DataAtom, context.Data)
  2047  		}
  2048  		contextTag = context.DataAtom.String()
  2049  	}
  2050  	p := &parser{
  2051  		tokenizer: NewTokenizerFragment(r, contextTag),
  2052  		doc: &Node{
  2053  			Type: DocumentNode,
  2054  		},
  2055  		scripting: true,
  2056  		fragment:  true,
  2057  		context:   context,
  2058  	}
  2059  
  2060  	root := &Node{
  2061  		Type:     ElementNode,
  2062  		DataAtom: a.Html,
  2063  		Data:     a.Html.String(),
  2064  	}
  2065  	p.doc.AppendChild(root)
  2066  	p.oe = nodeStack{root}
  2067  	p.resetInsertionMode()
  2068  
  2069  	for n := context; n != nil; n = n.Parent {
  2070  		if n.Type == ElementNode && n.DataAtom == a.Form {
  2071  			p.form = n
  2072  			break
  2073  		}
  2074  	}
  2075  
  2076  	err := p.parse()
  2077  	if err != nil {
  2078  		return nil, err
  2079  	}
  2080  
  2081  	parent := p.doc
  2082  	if context != nil {
  2083  		parent = root
  2084  	}
  2085  
  2086  	var result []*Node
  2087  	for c := parent.FirstChild; c != nil; {
  2088  		next := c.NextSibling
  2089  		parent.RemoveChild(c)
  2090  		result = append(result, c)
  2091  		c = next
  2092  	}
  2093  	return result, nil
  2094  }