func (p *Parser) parseTagName() string {
	reg := regexp.MustCompile("[a-zA-Z0-9]")
	f := func(char string) bool {
		return reg.MatchString(char)
	}
	return p.consumeWhile(f)
}
Parse a tag or attribute name
package htmlPDF
import (
	"fmt"
	"regexp"
)
func ParseHtml(source string) *Node {
	p := new(Parser)
	p.input = source
	p.pos = 0
	nodes := p.parseNodes()
	if len(nodes) > 1 {
		panic("Not one root tag")
	}
	return nodes[0]
}
func (p *Parser) parseNodes() map[int]*Node {
	nodes := map[int]*Node{}
	for {
		p.consumeWhitespace()
		if p.eof() || p.startWith("</") {
			break
		}
		nodes[len(nodes)] = p.parseNode()
	}
	return nodes
}
func (p *Parser) parseNode() *Node {
	if p.nextChar() == "<" {
		return p.parseElement()
	} else {
		return p.parseText()
	}
}
func (p *Parser) parseElement() *Node {
	start := p.consumeChar()
	if start != "<" {
		panic(fmt.Sprintf("%v was not an openig tag <", start))
	}
	tagName := p.parseTagName()
	attrs := p.parseAttributes()
	end := p.consumeChar()
	if end != ">" {
		panic(fmt.Sprintf("%v was not a closing tag <", end))
	}
	children := p.parseNodes()
	start = p.consumeChar()
	if start != "<" {
		panic(fmt.Sprintf("%v was not an openig tag <", start))
	}
	slash := p.consumeChar()
	if slash != "/" {
		panic(fmt.Sprintf("%v was not a tag /", slash))
	}
	closeName := p.parseTagName()
	if closeName != tagName {
		panic(fmt.Sprintf("open tag %v and close tag %v don't equal ", tagName, closeName))
	}
	end = p.consumeChar()
	if end != ">" {
		panic(fmt.Sprintf("%v was not a closing tag <", end))
	}
	return elem(tagName, attrs, children)
}
func (p *Parser) parseText() *Node {
	return text(p.consumeWhile(func(char string) bool {
		return char != "<"
	}))
}