func GetAttribute(node *html.Node, attrName string) string {
	for i := 0; i < len(node.Attr); i++ {
		if node.Attr[i].Key == attrName {
			return node.Attr[i].Val
		}
	}
	return ""
}
GetAttribute returns the value of a specified attribute on
the element. If the given attribute does not exist, the value
returned will be an empty string.
package dom
import (
	"bytes"
	"regexp"
	"strings"
	"github.com/andybalholm/cascadia"
	"golang.org/x/net/html"
)
var (
	rxPunctuation      = regexp.MustCompile(`\s+([.?!,;])\s*(\S*)`)
	rxTempNewline      = regexp.MustCompile(`\s*\|\\/\|\s*`)
	rxDisplayNone      = regexp.MustCompile(`(?i)display:\s*none`)
	rxVisibilityHidden = regexp.MustCompile(`(?i)visibility:\s*(:?hidden|collapse)`)
)
func QuerySelectorAll(doc *html.Node, selectors string) []*html.Node {
	matcher, err := cascadia.ParseGroup(selectors)
	if err != nil {
		return nil
	}
	return cascadia.QueryAll(doc, matcher)
}
func QuerySelector(doc *html.Node, selectors string) *html.Node {
	matcher, err := cascadia.ParseGroup(selectors)
	if err != nil {
		return nil
	}
	return cascadia.Query(doc, matcher)
}
func GetElementByID(doc *html.Node, id string) *html.Node {
	if id == "" {
		return nil
	}
	var results []*html.Node
	var finder func(*html.Node)
	finder = func(node *html.Node) {
		nodeID := GetAttribute(node, "id")
		nodeID = strings.TrimSpace(nodeID)
		if node.Type == html.ElementNode && nodeID == id {
			results = append(results, node)
		}
		for child := node.FirstChild; child != nil; child = child.NextSibling {
			finder(child)
		}
	}
	for child := doc.FirstChild; child != nil; child = child.NextSibling {
		finder(child)
		if len(results) > 0 {
			return results[0]
		}
	}
	return nil
}
func GetElementsByClassName(doc *html.Node, classNames string) []*html.Node {
	classes := map[string]struct{}{}
	for _, class := range strings.Fields(classNames) {
		classes[class] = struct{}{}
	}
	nClasses := len(classes)
	if nClasses == 0 {
		return nil
	}
	var results []*html.Node
	var finder func(*html.Node)
	var allClassExist func(*html.Node) bool
	allClassExist = func(node *html.Node) bool {
		matchCount := 0
		nodeClasses := GetAttribute(node, "class")
		for _, nodeClass := range strings.Fields(nodeClasses) {
			if _, exist := classes[nodeClass]; exist {
				matchCount++
			}
		}
		return matchCount == nClasses
	}
	finder = func(node *html.Node) {
		if node.Type == html.ElementNode && allClassExist(node) {
			results = append(results, node)
		}
		for child := node.FirstChild; child != nil; child = child.NextSibling {
			finder(child)
		}
	}
	for child := doc.FirstChild; child != nil; child = child.NextSibling {
		finder(child)
	}
	return results
}
func GetElementsByTagName(doc *html.Node, tagName string) []*html.Node {
	var results []*html.Node
	var finder func(*html.Node)
	finder = func(node *html.Node) {
		if node.Type == html.ElementNode && (tagName == "*" || node.Data == tagName) {
			results = append(results, node)
		}
		for child := node.FirstChild; child != nil; child = child.NextSibling {
			finder(child)
		}
	}
	for child := doc.FirstChild; child != nil; child = child.NextSibling {
		finder(child)
	}
	return results
}
func CreateElement(tagName string) *html.Node {
	return &html.Node{
		Type: html.ElementNode,
		Data: tagName,
	}
}
func CreateTextNode(data string) *html.Node {
	return &html.Node{
		Type: html.TextNode,
		Data: data,
	}
}
func TagName(node *html.Node) string {
	if node == nil {
		return ""
	}
	if node.Type != html.ElementNode {
		return ""
	}
	return node.Data
}