diff --git a/utilities.go b/utilities.go index 3e11b1d..d4a1b50 100644 --- a/utilities.go +++ b/utilities.go @@ -2,6 +2,7 @@ package goquery import ( "bytes" + "io" "golang.org/x/net/html" ) @@ -57,6 +58,19 @@ func nodeName(node *html.Node) string { } } +// Render renders the html of the first element from selector and writes it to the writer. +// It behaves similar to OuterHtml but takes io.Writer as input. +func Render(w io.Writer, s *Selection) error { + if s.Length() == 0 { + return nil + } + n := s.Get(0) + if err := html.Render(w, n); err != nil { + return err + } + return nil +} + // OuterHtml returns the outer HTML rendering of the first item in // the selection - that is, the HTML including the first element's // tag and attributes. @@ -66,12 +80,7 @@ func nodeName(node *html.Node) string { // a property provided by the DOM). func OuterHtml(s *Selection) (string, error) { var buf bytes.Buffer - - if s.Length() == 0 { - return "", nil - } - n := s.Get(0) - if err := html.Render(&buf, n); err != nil { + if err := Render(&buf, s); err != nil { return "", err } return buf.String(), nil diff --git a/utilities_test.go b/utilities_test.go index c8e9d54..88a468d 100644 --- a/utilities_test.go +++ b/utilities_test.go @@ -24,6 +24,49 @@ var allNodes = ` ` +func assertMatchNodes(t testing.TB, doc *Document) { + t.Helper() + + n0 := doc.Nodes[0] + nDT := n0.FirstChild + sMeta := doc.Find("meta") + sP := doc.Find("p") + nP := sP.Get(0) + nComment := nP.FirstChild + nText := nComment.NextSibling + sHeaders := doc.Find(".header") + + cases := []struct { + node *html.Node + sel *Selection + want string + }{ + {nDT, nil, ""}, // render makes DOCTYPE all caps + {nil, sMeta, ``}, // and auto-closes the meta + {nil, sP, `

+ This is some text. +

`}, + {nComment, nil, ""}, + {nText, nil, ` + This is some text. + `}, + {nil, sHeaders, `

`}, + } + for i, c := range cases { + if c.sel == nil { + c.sel = newSingleSelection(c.node, doc) + } + got, err := OuterHtml(c.sel) + if err != nil { + t.Fatal(err) + } + + if got != c.want { + t.Errorf("%d: want %q, got %q", i, c.want, got) + } + } +} + func TestNodeName(t *testing.T) { doc, err := NewDocumentFromReader(strings.NewReader(allNodes)) if err != nil { @@ -81,48 +124,18 @@ func TestNodeNameMultiSel(t *testing.T) { } } +func TestRender(t *testing.T) { + doc, err := NewDocumentFromReader(strings.NewReader(allNodes)) + if err != nil { + t.Fatal(err) + } + assertMatchNodes(t, doc) +} + func TestOuterHtml(t *testing.T) { doc, err := NewDocumentFromReader(strings.NewReader(allNodes)) if err != nil { t.Fatal(err) } - - n0 := doc.Nodes[0] - nDT := n0.FirstChild - sMeta := doc.Find("meta") - sP := doc.Find("p") - nP := sP.Get(0) - nComment := nP.FirstChild - nText := nComment.NextSibling - sHeaders := doc.Find(".header") - - cases := []struct { - node *html.Node - sel *Selection - want string - }{ - {nDT, nil, ""}, // render makes DOCTYPE all caps - {nil, sMeta, ``}, // and auto-closes the meta - {nil, sP, `

- This is some text. -

`}, - {nComment, nil, ""}, - {nText, nil, ` - This is some text. - `}, - {nil, sHeaders, `

`}, - } - for i, c := range cases { - if c.sel == nil { - c.sel = newSingleSelection(c.node, doc) - } - got, err := OuterHtml(c.sel) - if err != nil { - t.Fatal(err) - } - - if got != c.want { - t.Errorf("%d: want %q, got %q", i, c.want, got) - } - } + assertMatchNodes(t, doc) }