package main // Small helpers over golang.org/x/net/html for walking the SKK pedigree markup. import ( "strings" "golang.org/x/net/html" ) func attr(n *html.Node, key string) string { for _, a := range n.Attr { if a.Key == key { return a.Val } } return "" } // findByID returns the first element in the tree with the given id attribute. func findByID(n *html.Node, id string) *html.Node { if n.Type == html.ElementNode && attr(n, "id") == id { return n } for c := n.FirstChild; c != nil; c = c.NextSibling { if got := findByID(c, id); got != nil { return got } } return nil } // descendants returns every element with the given tag anywhere under n, in // document order. func descendants(n *html.Node, tag string) []*html.Node { var out []*html.Node var walk func(*html.Node) walk = func(x *html.Node) { for c := x.FirstChild; c != nil; c = c.NextSibling { if c.Type == html.ElementNode && c.Data == tag { out = append(out, c) } walk(c) } } walk(n) return out } // directChildElements returns the immediate element children of n with the tag. func directChildElements(n *html.Node, tag string) []*html.Node { var out []*html.Node for c := n.FirstChild; c != nil; c = c.NextSibling { if c.Type == html.ElementNode && c.Data == tag { out = append(out, c) } } return out } // findElement returns the first descendant element with the given tag. func findElement(n *html.Node, tag string) *html.Node { els := descendants(n, tag) if len(els) == 0 { return nil } return els[0] } // text concatenates all text under n. func text(n *html.Node) string { var sb strings.Builder var walk func(*html.Node) walk = func(x *html.Node) { if x.Type == html.TextNode { sb.WriteString(x.Data) } for c := x.FirstChild; c != nil; c = c.NextSibling { walk(c) } } walk(n) return sb.String() } // normalizeText trims and collapses internal whitespace. func normalizeText(s string) string { return strings.TrimSpace(wsRE.ReplaceAllString(s, " ")) } // findBoldSpan returns the normalized text of the first bold (how subject // cells carry the registration number), or "". func findBoldSpan(n *html.Node) string { for _, sp := range descendants(n, "span") { if strings.Contains(strings.ReplaceAll(attr(sp, "style"), " ", ""), "font-weight:bold") { if t := normalizeText(text(sp)); t != "" { return t } } } return "" }