add NewDocumentFromReader, closes #20

This commit is contained in:
Martin Angers
2013-09-07 10:57:54 -04:00
parent e8c0a63721
commit f065786d41
3 changed files with 68 additions and 5 deletions

View File

@@ -22,6 +22,7 @@ Syntax-wise, it is as close as possible to jQuery, with the same function names
## Changelog
* **v0.3.2** : Add `NewDocumentFromReader()` (thanks jweir) which allows creating a goquery document from an io.Reader.
* **v0.3.1** : Add `NewDocumentFromResponse()` (thanks assassingj) which allows creating a goquery document from an http response.
* **v0.3.0** : Add `EachWithBreak()` which allows to break out of an `Each()` loop by returning false. This function was added instead of changing the existing `Each()` to avoid breaking compatibility.
* **v0.2.1** : Make go-getable, now that [go.net/html is Go1.0-compatible][gonet] (thanks to @matrixik for pointing this out).

23
type.go
View File

@@ -2,6 +2,7 @@ package goquery
import (
"code.google.com/p/go.net/html"
"io"
"net/http"
"net/url"
)
@@ -35,6 +36,19 @@ func NewDocument(url string) (d *Document, e error) {
return NewDocumentFromResponse(res)
}
// NewDocumentFromReader() returns a Document from a generic reader.
// It returns an error as second value if the reader's data cannot be parsed
// as html. It does *not* check if the reader is also an io.Closer, so the
// provided reader is never closed by this call, it is the responsibility
// of the caller to close it if required.
func NewDocumentFromReader(r io.Reader) (d *Document, e error) {
root, e := html.Parse(r)
if e != nil {
return nil, e
}
return newDocument(root, nil), nil
}
// NewDocumentFromResponse() is another Document constructor that takes an http resonse as argument.
// It loads the specified response's document, parses it, and stores the root Document
// node, ready to be manipulated.
@@ -48,16 +62,15 @@ func NewDocumentFromResponse(res *http.Response) (d *Document, e error) {
}
// Create and fill the document
d = newDocument(root, res.Request.URL)
return
return newDocument(root, res.Request.URL), nil
}
// Private constructor, make sure all fields are correctly filled.
func newDocument(root *html.Node, url *url.URL) (d *Document) {
func newDocument(root *html.Node, url *url.URL) *Document {
// Create and fill the document
d = &Document{nil, url, root}
d := &Document{nil, url, root}
d.Selection = newSingleSelection(root, d)
return
return d
}
// Selection represents a collection of nodes matching some criteria. The

View File

@@ -1,6 +1,7 @@
package goquery
import (
"bytes"
"code.google.com/p/go.net/html"
"fmt"
"os"
@@ -99,3 +100,51 @@ func TestNewDocument(t *testing.T) {
}
}
}
func TestNewDocumentFromReader(t *testing.T) {
cases := []struct {
src string
err bool
sel string
cnt int
}{
0: {
src: `
<html>
<head>
<title>Test</title>
<body>
<h1>Hi</h1>
</body>
</html>`,
sel: "h1",
cnt: 1,
},
1: {
// Actually pretty hard to make html.Parse return an error
// based on content...
src: `<html><body><aef<eqf>>>qq></body></ht>`,
},
}
buf := bytes.NewBuffer(nil)
for i, c := range cases {
buf.Reset()
buf.WriteString(c.src)
d, e := NewDocumentFromReader(buf)
if (e != nil) != c.err {
if c.err {
t.Errorf("[%d] - expected error, got none", i)
} else {
t.Errorf("[%d] - expected no error, got %s", i, e)
}
}
if c.sel != "" {
s := d.Find(c.sel)
if s.Length() != c.cnt {
t.Errorf("[%d] - expected %d nodes, found %d", i, c.cnt, s.Length())
}
}
}
}