rel2abs.go (view raw)
1package rel2abs
2
3import (
4 "bytes"
5 "fmt"
6 "net/url"
7
8 "golang.org/x/net/html"
9)
10
11func rel2abs(n *html.Node, nurl *url.URL) error {
12 if n.Type == html.ElementNode && n.Data == "a" {
13 for _, a := range n.Attr {
14 if a.Key == "href" {
15 rel, err := url.Parse(a.Val)
16 if err != nil {
17 return fmt.Errorf("relative url: %w\n", err)
18 }
19
20 a.Val = nurl.ResolveReference(rel).String()
21 }
22 }
23 for c := n.FirstChild; c != nil; c = c.NextSibling {
24 rel2abs(c, nurl)
25 }
26 }
27 return nil
28}
29
30// Converts all relative URLs in htmlContent to absolute URLs,
31// resolved against a base URL.
32// Example, with base as http://example.com/foo:
33// <a href="#fn-1">
34// becomes
35// <a href="http://example.com/foo#fn-1">
36func Rel2Abs(htmlContent []byte, base string) ([]byte, error) {
37 doc, err := html.Parse(bytes.NewReader(htmlContent))
38 if err != nil {
39 return nil, fmt.Errorf("html parse: %w\n", err)
40 }
41
42 nurl, err := url.Parse(base)
43 if err != nil {
44 return nil, fmt.Errorf("url parse: %w\n", err)
45 }
46 rel2abs(doc, nurl)
47 buf := bytes.Buffer{}
48 html.Render(&buf, doc)
49 return buf.Bytes(), nil
50}