Compare commits

..
42 Commits
Author SHA1 Message Date
Martin Angers a41cf096e6 update changelog 2018-01-11 08:54:59 -05:00
Martin Angers 7d9aa5c1e6 misc/git: remove excessively verbose lint tools 2018-01-11 08:49:46 -05:00
Martin Angers c56812c109 fix godoc comment to comply with golint 2018-01-11 08:48:49 -05:00
Martin AngersandGitHub cab5e2c9d6 Merge pull request #229 from davidjwilkins/feature-226
Fixes #226 - Added the AddBack, AddBackFiltered, and AddBackMatcher methods.
2018-01-11 08:45:45 -05:00
David Wilkins 802bece6d0 Move deprecated notice to end of comment 2018-01-10 21:36:54 -08:00
David Wilkins 499bd47957 Fixes #226 - Added the AddBack, AddBackFiltered, and AddBackMatcher methods. Changed AndSelf to simply be an alias for AddBack, and added a deprecation notice to AddBack (as with https://api.jquery.com/andself/) 2018-01-09 20:34:18 -08:00
Martin AngersandGitHub bc4e06eb07 Merge pull request #221 from y-yagi/patch-1
Add go1.9 to travis
2017-12-06 07:16:06 -05:00
Yuji YaginumaandGitHub d8ab9abbf4 Add go1.9 to travis 2017-12-06 18:46:13 +09:00
Martin AngersandGitHub 1a71cc719d Merge pull request #215 from kataras/patch-1
README.md: Add colly - Scraping Framework to the Related Projects
2017-10-07 10:12:28 -04:00
Gerasimos (Makis) MaropoulosandGitHub 4b3a6d701e README.md: Add colly - Scraping Framework to the Related Projects 2017-10-07 07:57:40 +03:00
Martin AngersandGitHub 63e7f870c2 Merge pull request #211 from 38elements/fix-typo
Fix typo
2017-09-29 06:56:09 -04:00
38elementsandGitHub 109d3a6a56 Fix typo 2017-09-29 18:51:07 +09:00
Martin Angers ce645ea5e6 use svg travis badge, master branch 2017-08-16 09:38:31 -04:00
Martin Angers 8806ada2a4 update README with "related projects" section instead of just "downstream" 2017-06-23 12:21:02 -04:00
Martin AngersandGitHub 2dc93891ab Merge pull request #183 from andrewstuart/master
Add goquery marshaling library as a downstream project in Readme
2017-05-20 15:45:20 -04:00
Andrew Stuart 4a7586a83f Update readme with some downstream projects 2017-05-15 16:49:20 -07:00
Martin Angers ed7d758e9a add 1.8, test on latest patches 2017-03-24 09:54:48 -04:00
Martin AngersandGitHub c641b87978 Merge pull request #162 from rohanpai/master
Added Sourcegraph Badge
2017-03-08 14:48:52 -05:00
Rohan PaiandGitHub 28076b7c97 Added Sourcegraph Badge 2017-03-08 11:27:24 -08:00
Martin Angers e1271ee34c Merge branch 'glebtv-setHtml' 2017-02-12 11:36:42 -05:00
Martin Angers f5c5de8530 update readme for new release 2017-02-12 11:36:10 -05:00
Martin Angers 46c32cef0e unexport SetNodes, add SetHtml tests 2017-02-12 11:34:10 -05:00
Gleb Tv 755fd592bb implement SetHtml and SetText, fixes #123 2017-02-08 16:27:36 +03:00
Martin AngersandGitHub 3cb3b86568 Update README.md 2016-12-29 22:41:54 -05:00
Martin AngersandGitHub 2ee2e49ac5 Merge pull request #142 from radovskyb/master
Optimizes the *Selection.Text method and reduces allocations.
2016-12-29 22:37:29 -05:00
Benjamin Radovsky c0b805c7dc greatly optimize the *Selection.Text method and highly reduce it's amount of allocations per op. 2016-12-27 17:37:31 +11:00
Martin Angers 152b1a2c8f remove wiki section on big docs, cascadia is now almost as fast as workarounds 2016-08-31 12:22:11 -04:00
Martin Angers 9043fe2599 add tip for large documents 2016-08-30 20:10:13 -04:00
Martin Angers 56a198aba8 add go1.7 to travis 2016-08-28 21:21:01 -04:00
Martin Angers 5dccaa115b optimize winnowNodes and ClosestNodes in the same way 2016-08-28 11:55:36 -04:00
Martin Angers 26f4f54c91 simplify string search expressions, remove unused code 2016-08-28 11:09:29 -04:00
Martin Angers e89fe653fd update README for v1.0.1 2016-08-28 11:06:06 -04:00
Martin Angers ab2bb46123 update pre-commit hook with other static checks 2016-08-28 11:04:26 -04:00
Martin Angers b91267330e add tests and benchmark for appendWithoutDuplicates optimization 2016-08-28 11:03:18 -04:00
Martin Angers d85ad7e2ed remove var declaration 2016-08-27 22:44:10 -04:00
Martin Angers 6841d28c6f comment and explain the appendWithoutDuplicates logic 2016-08-27 22:29:53 -04:00
Martin Angers 7bd630023a reuse the deduplication set map in mapNodes 2016-08-27 22:25:02 -04:00
Martin Angers c7533ba696 maintain a set of existing target nodes to deduplicate
The old implementation used nested loops to check if one of the
new nodes was already in the existing nodes. This commit
maintains a map[*html.Node]bool so that a single loop over
the new elements is required. This is slower for small
slices though, and allocates more. The next step is for
appendWithoutDuplicates to accept a map as argument so
that the set is not recreated on each call from mapNodes.
2016-08-27 18:55:21 -04:00
Martin Angers ad8b3d8222 remove logging from benchmarks, validate expected result instead 2016-08-27 18:37:55 -04:00
Martin Angers 7f4291566c tag v1.0.0, closes #124 2016-07-27 21:43:13 -04:00
Martin Angers f0d75731e0 fix example, closes #120 2016-06-29 08:59:28 -04:00
Martin AngersandGitHub 77cbaef46a Merge pull request #115 from PuerkitoBio/i114
Treat invalid selector strings as a Matcher that doesn't match anything
2016-06-15 09:48:05 -04:00
28 changed files with 903 additions and 178 deletions
+10 -1
View File
@@ -1,7 +1,16 @@
# editor temporary files
*.sublime-*
.DS_Store
*.swp
#*.*#
tags
goquery.test
# direnv config
.env*
# test binaries
*.test
# coverage and profilte outputs
*.out
+9 -6
View File
@@ -1,10 +1,13 @@
language: go
go:
- 1.1
- 1.2
- 1.3
- 1.4
- 1.5
- 1.6
- 1.1.x
- 1.2.x
- 1.3.x
- 1.4.x
- 1.5.x
- 1.6.x
- 1.7.x
- 1.8.x
- 1.9.x
- tip
+32 -5
View File
@@ -1,4 +1,6 @@
# goquery - a little like that j-thing, only in Go [![build status](https://secure.travis-ci.org/PuerkitoBio/goquery.png)](http://travis-ci.org/PuerkitoBio/goquery) [![GoDoc](https://godoc.org/github.com/PuerkitoBio/goquery?status.png)](http://godoc.org/github.com/PuerkitoBio/goquery)
# goquery - a little like that j-thing, only in Go
[![build status](https://secure.travis-ci.org/PuerkitoBio/goquery.svg?branch=master)](http://travis-ci.org/PuerkitoBio/goquery) [![GoDoc](https://godoc.org/github.com/PuerkitoBio/goquery?status.png)](http://godoc.org/github.com/PuerkitoBio/goquery) [![Sourcegraph Badge](https://sourcegraph.com/github.com/PuerkitoBio/goquery/-/badge.svg)](https://sourcegraph.com/github.com/PuerkitoBio/goquery?badge)
goquery brings a syntax and a set of features similar to [jQuery][] to the [Go language][go]. It is based on Go's [net/html package][html] and the CSS Selector library [cascadia][]. Since the net/html parser returns nodes, and not a full-featured DOM tree, jQuery's stateful manipulation functions (like height(), css(), detach()) have been left off.
@@ -6,6 +8,15 @@ Also, because the net/html parser requires UTF-8 encoding, so does goquery: it i
Syntax-wise, it is as close as possible to jQuery, with the same function names when possible, and that warm and fuzzy chainable interface. jQuery being the ultra-popular library that it is, I felt that writing a similar HTML-manipulating library was better to follow its API than to start anew (in the same spirit as Go's `fmt` package), even though some of its methods are less than intuitive (looking at you, [index()][index]...).
## Table of Contents
* [Installation](#installation)
* [Changelog](#changelog)
* [API](#api)
* [Examples](#examples)
* [Related Projects](#related-projects)
* [License](#license)
## Installation
Please note that because of the net/html dependency, goquery requires Go1.1+.
@@ -13,7 +24,7 @@ Please note that because of the net/html dependency, goquery requires Go1.1+.
$ go get github.com/PuerkitoBio/goquery
(optional) To run unit tests:
$ cd $GOPATH/src/github.com/PuerkitoBio/goquery
$ go test
@@ -26,6 +37,11 @@ Please note that because of the net/html dependency, goquery requires Go1.1+.
**Note that goquery's API is now stable, and will not break.**
* **2018-01-11 (v1.2.0)** : Add `AddBack*` and deprecate `AndSelf` (thanks to @davidjwilkins).
* **2017-02-12 (v1.1.0)** : Add `SetHtml` and `SetText` (thanks to @glebtv).
* **2016-12-29 (v1.0.2)** : Optimize allocations for `Selection.Text` (thanks to @radovskyb).
* **2016-08-28 (v1.0.1)** : Optimize performance for large documents.
* **2016-07-27 (v1.0.0)** : Tag version 1.0.0.
* **2016-06-15** : Invalid selector strings internally compile to a `Matcher` implementation that never matches any node (instead of a panic). So for example, `doc.Find("~")` returns an empty `*Selection` object.
* **2016-02-02** : Add `NodeName` utility function similar to the DOM's `nodeName` property. It returns the tag name of the first element in a selection, and other relevant values of non-element nodes (see godoc for details). Add `OuterHtml` utility function similar to the DOM's `outerHTML` property (named `OuterHtml` in small caps for consistency with the existing `Html` method on the `Selection`).
* **2015-04-20** : Add `AttrOr` helper method to return the attribute's value or a default value if absent. Thanks to [piotrkowalczuk][piotr].
@@ -82,13 +98,15 @@ import (
)
func ExampleScrape() {
doc, err := goquery.NewDocument("http://metalsucks.net")
doc, err := goquery.NewDocument("http://metalsucks.net")
if err != nil {
log.Fatal(err)
}
doc.Find(".reviews-wrap article .review-rhs").Each(func(i int, s *goquery.Selection) {
band := s.Find("h3").Text()
// Find the review items
doc.Find(".sidebar-reviews article .content-block").Each(func(i int, s *goquery.Selection) {
// For each item found, get the band and title
band := s.Find("a").Text()
title := s.Find("i").Text()
fmt.Printf("Review %d: %s - %s\n", i, band, title)
})
@@ -99,6 +117,13 @@ func main() {
}
```
## Related Projects
- [Goq][goq], an HTML deserialization and scraping library based on goquery and struct tags.
- [andybalholm/cascadia][cascadia], the CSS selector library used by goquery.
- [suntong/cascadia][cascadiacli], a command-line interface to the cascadia CSS selector library, useful to test selectors.
- [asciimoo/colly](https://github.com/asciimoo/colly), a lightning fast and elegant Scraping Framework
## License
The [BSD 3-Clause license][bsd], the same as the [Go language][golic]. Cascadia's license is [here][caslic].
@@ -106,6 +131,7 @@ The [BSD 3-Clause license][bsd], the same as the [Go language][golic]. Cascadia'
[jquery]: http://jquery.com/
[go]: http://golang.org/
[cascadia]: https://github.com/andybalholm/cascadia
[cascadiacli]: https://github.com/suntong/cascadia
[bsd]: http://opensource.org/licenses/BSD-3-Clause
[golic]: http://golang.org/LICENSE
[caslic]: https://github.com/andybalholm/cascadia/blob/master/LICENSE
@@ -116,3 +142,4 @@ The [BSD 3-Clause license][bsd], the same as the [Go language][golic]. Cascadia'
[wiki]: https://github.com/PuerkitoBio/goquery/wiki/Tips-and-tricks
[thatguystone]: https://github.com/thatguystone
[piotr]: https://github.com/piotrkowalczuk
[goq]: https://github.com/andrewstuart/goq
+85
View File
@@ -0,0 +1,85 @@
BenchmarkFirst-4 30000000 50.7 ns/op 48 B/op 1 allocs/op
BenchmarkLast-4 30000000 50.9 ns/op 48 B/op 1 allocs/op
BenchmarkEq-4 30000000 55.7 ns/op 48 B/op 1 allocs/op
BenchmarkSlice-4 500000000 3.45 ns/op 0 B/op 0 allocs/op
BenchmarkGet-4 2000000000 1.68 ns/op 0 B/op 0 allocs/op
BenchmarkIndex-4 3000000 541 ns/op 248 B/op 10 allocs/op
BenchmarkIndexSelector-4 200000 10749 ns/op 2464 B/op 17 allocs/op
BenchmarkIndexOfNode-4 200000000 6.47 ns/op 0 B/op 0 allocs/op
BenchmarkIndexOfSelection-4 200000000 7.27 ns/op 0 B/op 0 allocs/op
BenchmarkMetalReviewExample-4 10000 138426 ns/op 12240 B/op 319 allocs/op
BenchmarkAdd-4 200000 10192 ns/op 208 B/op 9 allocs/op
BenchmarkAddSelection-4 10000000 158 ns/op 48 B/op 1 allocs/op
BenchmarkAddNodes-4 10000000 156 ns/op 48 B/op 1 allocs/op
BenchmarkAndSelf-4 1000000 1588 ns/op 1008 B/op 5 allocs/op
BenchmarkFilter-4 100000 20427 ns/op 360 B/op 8 allocs/op
BenchmarkNot-4 100000 23508 ns/op 136 B/op 5 allocs/op
BenchmarkFilterFunction-4 50000 34178 ns/op 22976 B/op 755 allocs/op
BenchmarkNotFunction-4 50000 38173 ns/op 29120 B/op 757 allocs/op
BenchmarkFilterNodes-4 50000 34001 ns/op 20960 B/op 749 allocs/op
BenchmarkNotNodes-4 30000 40344 ns/op 29120 B/op 757 allocs/op
BenchmarkFilterSelection-4 50000 33308 ns/op 20960 B/op 749 allocs/op
BenchmarkNotSelection-4 30000 40748 ns/op 29120 B/op 757 allocs/op
BenchmarkHas-4 5000 263346 ns/op 1816 B/op 48 allocs/op
BenchmarkHasNodes-4 10000 160840 ns/op 21184 B/op 752 allocs/op
BenchmarkHasSelection-4 10000 165410 ns/op 21184 B/op 752 allocs/op
BenchmarkEnd-4 2000000000 1.01 ns/op 0 B/op 0 allocs/op
BenchmarkEach-4 300000 4664 ns/op 3304 B/op 118 allocs/op
BenchmarkMap-4 200000 8286 ns/op 5572 B/op 184 allocs/op
BenchmarkEachWithBreak-4 2000000 806 ns/op 560 B/op 20 allocs/op
BenchmarkAttr-4 100000000 21.6 ns/op 0 B/op 0 allocs/op
BenchmarkText-4 200000 8909 ns/op 7536 B/op 110 allocs/op
BenchmarkLength-4 2000000000 0.34 ns/op 0 B/op 0 allocs/op
BenchmarkHtml-4 3000000 422 ns/op 120 B/op 2 allocs/op
BenchmarkIs-4 100000 22615 ns/op 88 B/op 4 allocs/op
BenchmarkIsPositional-4 50000 26655 ns/op 1112 B/op 10 allocs/op
BenchmarkIsFunction-4 1000000 1208 ns/op 784 B/op 28 allocs/op
BenchmarkIsSelection-4 50000 33497 ns/op 20960 B/op 749 allocs/op
BenchmarkIsNodes-4 50000 33572 ns/op 20960 B/op 749 allocs/op
BenchmarkHasClass-4 10000 232802 ns/op 14944 B/op 976 allocs/op
BenchmarkContains-4 200000000 7.33 ns/op 0 B/op 0 allocs/op
BenchmarkFind-4 200000 10715 ns/op 2464 B/op 17 allocs/op
BenchmarkFindWithinSelection-4 50000 35878 ns/op 2176 B/op 78 allocs/op
BenchmarkFindSelection-4 10000 194356 ns/op 2672 B/op 82 allocs/op
BenchmarkFindNodes-4 10000 195510 ns/op 2672 B/op 82 allocs/op
BenchmarkContents-4 1000000 2252 ns/op 864 B/op 34 allocs/op
BenchmarkContentsFiltered-4 500000 3015 ns/op 1016 B/op 39 allocs/op
BenchmarkChildren-4 5000000 364 ns/op 152 B/op 7 allocs/op
BenchmarkChildrenFiltered-4 1000000 2212 ns/op 352 B/op 15 allocs/op
BenchmarkParent-4 50000 24643 ns/op 4048 B/op 381 allocs/op
BenchmarkParentFiltered-4 50000 25967 ns/op 4248 B/op 388 allocs/op
BenchmarkParents-4 30000 50000 ns/op 27776 B/op 830 allocs/op
BenchmarkParentsFiltered-4 30000 53107 ns/op 28360 B/op 838 allocs/op
BenchmarkParentsUntil-4 100000 22423 ns/op 10352 B/op 353 allocs/op
BenchmarkParentsUntilSelection-4 20000 86925 ns/op 51144 B/op 1516 allocs/op
BenchmarkParentsUntilNodes-4 20000 87597 ns/op 51144 B/op 1516 allocs/op
BenchmarkParentsFilteredUntil-4 300000 5568 ns/op 2232 B/op 86 allocs/op
BenchmarkParentsFilteredUntilSelection-4 200000 10966 ns/op 5440 B/op 190 allocs/op
BenchmarkParentsFilteredUntilNodes-4 200000 10919 ns/op 5440 B/op 190 allocs/op
BenchmarkSiblings-4 30000 46018 ns/op 15400 B/op 204 allocs/op
BenchmarkSiblingsFiltered-4 30000 50566 ns/op 16496 B/op 213 allocs/op
BenchmarkNext-4 200000 7921 ns/op 3216 B/op 112 allocs/op
BenchmarkNextFiltered-4 200000 8804 ns/op 3416 B/op 118 allocs/op
BenchmarkNextAll-4 50000 31098 ns/op 9912 B/op 138 allocs/op
BenchmarkNextAllFiltered-4 50000 34677 ns/op 11008 B/op 147 allocs/op
BenchmarkPrev-4 200000 7920 ns/op 3216 B/op 112 allocs/op
BenchmarkPrevFiltered-4 200000 8913 ns/op 3416 B/op 118 allocs/op
BenchmarkPrevAll-4 200000 10845 ns/op 4376 B/op 113 allocs/op
BenchmarkPrevAllFiltered-4 100000 12030 ns/op 4576 B/op 119 allocs/op
BenchmarkNextUntil-4 100000 19193 ns/op 5760 B/op 260 allocs/op
BenchmarkNextUntilSelection-4 50000 34829 ns/op 18480 B/op 542 allocs/op
BenchmarkNextUntilNodes-4 100000 14459 ns/op 7944 B/op 248 allocs/op
BenchmarkPrevUntil-4 20000 66296 ns/op 12856 B/op 448 allocs/op
BenchmarkPrevUntilSelection-4 30000 45037 ns/op 23432 B/op 689 allocs/op
BenchmarkPrevUntilNodes-4 200000 11525 ns/op 6152 B/op 203 allocs/op
BenchmarkNextFilteredUntil-4 100000 12940 ns/op 4512 B/op 173 allocs/op
BenchmarkNextFilteredUntilSelection-4 50000 38924 ns/op 19160 B/op 567 allocs/op
BenchmarkNextFilteredUntilNodes-4 50000 38528 ns/op 19160 B/op 567 allocs/op
BenchmarkPrevFilteredUntil-4 100000 12980 ns/op 4664 B/op 175 allocs/op
BenchmarkPrevFilteredUntilSelection-4 50000 39671 ns/op 19936 B/op 587 allocs/op
BenchmarkPrevFilteredUntilNodes-4 50000 39484 ns/op 19936 B/op 587 allocs/op
BenchmarkClosest-4 500000 3310 ns/op 160 B/op 8 allocs/op
BenchmarkClosestSelection-4 5000000 361 ns/op 96 B/op 6 allocs/op
BenchmarkClosestNodes-4 5000000 359 ns/op 96 B/op 6 allocs/op
PASS
ok github.com/PuerkitoBio/goquery 163.718s
+85
View File
@@ -0,0 +1,85 @@
BenchmarkFirst-4 30000000 50.9 ns/op 48 B/op 1 allocs/op
BenchmarkLast-4 30000000 50.0 ns/op 48 B/op 1 allocs/op
BenchmarkEq-4 30000000 50.5 ns/op 48 B/op 1 allocs/op
BenchmarkSlice-4 500000000 3.53 ns/op 0 B/op 0 allocs/op
BenchmarkGet-4 2000000000 1.66 ns/op 0 B/op 0 allocs/op
BenchmarkIndex-4 2000000 832 ns/op 248 B/op 10 allocs/op
BenchmarkIndexSelector-4 100000 16073 ns/op 3839 B/op 21 allocs/op
BenchmarkIndexOfNode-4 200000000 6.38 ns/op 0 B/op 0 allocs/op
BenchmarkIndexOfSelection-4 200000000 7.14 ns/op 0 B/op 0 allocs/op
BenchmarkMetalReviewExample-4 10000 140737 ns/op 12418 B/op 320 allocs/op
BenchmarkAdd-4 100000 13162 ns/op 974 B/op 10 allocs/op
BenchmarkAddSelection-4 500000 3160 ns/op 814 B/op 2 allocs/op
BenchmarkAddNodes-4 500000 3159 ns/op 814 B/op 2 allocs/op
BenchmarkAndSelf-4 200000 7423 ns/op 2404 B/op 9 allocs/op
BenchmarkFilter-4 100000 19671 ns/op 360 B/op 8 allocs/op
BenchmarkNot-4 100000 22577 ns/op 136 B/op 5 allocs/op
BenchmarkFilterFunction-4 50000 33960 ns/op 22976 B/op 755 allocs/op
BenchmarkNotFunction-4 50000 37909 ns/op 29120 B/op 757 allocs/op
BenchmarkFilterNodes-4 50000 34196 ns/op 20960 B/op 749 allocs/op
BenchmarkNotNodes-4 30000 40446 ns/op 29120 B/op 757 allocs/op
BenchmarkFilterSelection-4 50000 33091 ns/op 20960 B/op 749 allocs/op
BenchmarkNotSelection-4 30000 40609 ns/op 29120 B/op 757 allocs/op
BenchmarkHas-4 5000 262936 ns/op 2371 B/op 50 allocs/op
BenchmarkHasNodes-4 10000 148631 ns/op 21184 B/op 752 allocs/op
BenchmarkHasSelection-4 10000 153117 ns/op 21184 B/op 752 allocs/op
BenchmarkEnd-4 2000000000 1.02 ns/op 0 B/op 0 allocs/op
BenchmarkEach-4 300000 4653 ns/op 3304 B/op 118 allocs/op
BenchmarkMap-4 200000 8257 ns/op 5572 B/op 184 allocs/op
BenchmarkEachWithBreak-4 2000000 806 ns/op 560 B/op 20 allocs/op
BenchmarkAttr-4 100000000 22.0 ns/op 0 B/op 0 allocs/op
BenchmarkText-4 200000 8913 ns/op 7536 B/op 110 allocs/op
BenchmarkLength-4 2000000000 0.35 ns/op 0 B/op 0 allocs/op
BenchmarkHtml-4 5000000 398 ns/op 120 B/op 2 allocs/op
BenchmarkIs-4 100000 22392 ns/op 88 B/op 4 allocs/op
BenchmarkIsPositional-4 50000 26259 ns/op 1112 B/op 10 allocs/op
BenchmarkIsFunction-4 1000000 1212 ns/op 784 B/op 28 allocs/op
BenchmarkIsSelection-4 50000 33222 ns/op 20960 B/op 749 allocs/op
BenchmarkIsNodes-4 50000 33408 ns/op 20960 B/op 749 allocs/op
BenchmarkHasClass-4 10000 233208 ns/op 14944 B/op 976 allocs/op
BenchmarkContains-4 200000000 7.57 ns/op 0 B/op 0 allocs/op
BenchmarkFind-4 100000 16121 ns/op 3839 B/op 21 allocs/op
BenchmarkFindWithinSelection-4 20000 68019 ns/op 11521 B/op 97 allocs/op
BenchmarkFindSelection-4 5000 387582 ns/op 59787 B/op 176 allocs/op
BenchmarkFindNodes-4 5000 389246 ns/op 59797 B/op 176 allocs/op
BenchmarkContents-4 200000 11475 ns/op 2878 B/op 42 allocs/op
BenchmarkContentsFiltered-4 200000 11222 ns/op 2498 B/op 46 allocs/op
BenchmarkChildren-4 2000000 650 ns/op 152 B/op 7 allocs/op
BenchmarkChildrenFiltered-4 500000 2568 ns/op 352 B/op 15 allocs/op
BenchmarkParent-4 2000 702513 ns/op 194478 B/op 828 allocs/op
BenchmarkParentFiltered-4 2000 690778 ns/op 194658 B/op 835 allocs/op
BenchmarkParents-4 10000 124855 ns/op 49869 B/op 868 allocs/op
BenchmarkParentsFiltered-4 10000 128535 ns/op 50456 B/op 876 allocs/op
BenchmarkParentsUntil-4 20000 72982 ns/op 23802 B/op 388 allocs/op
BenchmarkParentsUntilSelection-4 10000 156099 ns/op 72453 B/op 1549 allocs/op
BenchmarkParentsUntilNodes-4 10000 156610 ns/op 72455 B/op 1549 allocs/op
BenchmarkParentsFilteredUntil-4 100000 15549 ns/op 4068 B/op 94 allocs/op
BenchmarkParentsFilteredUntilSelection-4 100000 20564 ns/op 7276 B/op 198 allocs/op
BenchmarkParentsFilteredUntilNodes-4 100000 20635 ns/op 7276 B/op 198 allocs/op
BenchmarkSiblings-4 3000 565114 ns/op 205910 B/op 336 allocs/op
BenchmarkSiblingsFiltered-4 3000 580264 ns/op 206993 B/op 345 allocs/op
BenchmarkNext-4 20000 93177 ns/op 26810 B/op 169 allocs/op
BenchmarkNextFiltered-4 20000 94171 ns/op 27013 B/op 175 allocs/op
BenchmarkNextAll-4 5000 270320 ns/op 89289 B/op 237 allocs/op
BenchmarkNextAllFiltered-4 5000 275283 ns/op 90375 B/op 246 allocs/op
BenchmarkPrev-4 20000 92777 ns/op 26810 B/op 169 allocs/op
BenchmarkPrevFiltered-4 20000 95577 ns/op 27007 B/op 175 allocs/op
BenchmarkPrevAll-4 20000 86339 ns/op 27515 B/op 151 allocs/op
BenchmarkPrevAllFiltered-4 20000 87759 ns/op 27715 B/op 157 allocs/op
BenchmarkNextUntil-4 10000 163930 ns/op 48541 B/op 330 allocs/op
BenchmarkNextUntilSelection-4 30000 56382 ns/op 23880 B/op 556 allocs/op
BenchmarkNextUntilNodes-4 100000 18883 ns/op 8703 B/op 252 allocs/op
BenchmarkPrevUntil-4 3000 484668 ns/op 145402 B/op 611 allocs/op
BenchmarkPrevUntilSelection-4 20000 72125 ns/op 28865 B/op 705 allocs/op
BenchmarkPrevUntilNodes-4 100000 14722 ns/op 6510 B/op 205 allocs/op
BenchmarkNextFilteredUntil-4 50000 39006 ns/op 10990 B/op 192 allocs/op
BenchmarkNextFilteredUntilSelection-4 20000 66048 ns/op 25641 B/op 586 allocs/op
BenchmarkNextFilteredUntilNodes-4 20000 65314 ns/op 25640 B/op 586 allocs/op
BenchmarkPrevFilteredUntil-4 50000 33312 ns/op 9709 B/op 189 allocs/op
BenchmarkPrevFilteredUntilSelection-4 20000 64197 ns/op 24981 B/op 601 allocs/op
BenchmarkPrevFilteredUntilNodes-4 20000 64505 ns/op 24982 B/op 601 allocs/op
BenchmarkClosest-4 500000 4065 ns/op 160 B/op 8 allocs/op
BenchmarkClosestSelection-4 2000000 756 ns/op 96 B/op 6 allocs/op
BenchmarkClosestNodes-4 2000000 753 ns/op 96 B/op 6 allocs/op
PASS
ok github.com/PuerkitoBio/goquery 162.053s
+85
View File
@@ -0,0 +1,85 @@
BenchmarkFirst-4 30000000 51.8 ns/op 48 B/op 1 allocs/op
BenchmarkLast-4 30000000 50.1 ns/op 48 B/op 1 allocs/op
BenchmarkEq-4 30000000 51.4 ns/op 48 B/op 1 allocs/op
BenchmarkSlice-4 500000000 3.52 ns/op 0 B/op 0 allocs/op
BenchmarkGet-4 2000000000 1.65 ns/op 0 B/op 0 allocs/op
BenchmarkIndex-4 2000000 787 ns/op 248 B/op 10 allocs/op
BenchmarkIndexSelector-4 100000 16952 ns/op 3839 B/op 21 allocs/op
BenchmarkIndexOfNode-4 200000000 6.42 ns/op 0 B/op 0 allocs/op
BenchmarkIndexOfSelection-4 200000000 7.12 ns/op 0 B/op 0 allocs/op
BenchmarkMetalReviewExample-4 10000 141994 ns/op 12418 B/op 320 allocs/op
BenchmarkAdd-4 200000 10367 ns/op 208 B/op 9 allocs/op
BenchmarkAddSelection-4 10000000 152 ns/op 48 B/op 1 allocs/op
BenchmarkAddNodes-4 10000000 147 ns/op 48 B/op 1 allocs/op
BenchmarkAndSelf-4 1000000 1647 ns/op 1008 B/op 5 allocs/op
BenchmarkFilter-4 100000 19522 ns/op 360 B/op 8 allocs/op
BenchmarkNot-4 100000 22546 ns/op 136 B/op 5 allocs/op
BenchmarkFilterFunction-4 50000 35087 ns/op 22976 B/op 755 allocs/op
BenchmarkNotFunction-4 50000 39123 ns/op 29120 B/op 757 allocs/op
BenchmarkFilterNodes-4 50000 34890 ns/op 20960 B/op 749 allocs/op
BenchmarkNotNodes-4 30000 41145 ns/op 29120 B/op 757 allocs/op
BenchmarkFilterSelection-4 50000 33735 ns/op 20960 B/op 749 allocs/op
BenchmarkNotSelection-4 30000 41334 ns/op 29120 B/op 757 allocs/op
BenchmarkHas-4 5000 264058 ns/op 2370 B/op 50 allocs/op
BenchmarkHasNodes-4 10000 151718 ns/op 21184 B/op 752 allocs/op
BenchmarkHasSelection-4 10000 156955 ns/op 21184 B/op 752 allocs/op
BenchmarkEnd-4 2000000000 1.01 ns/op 0 B/op 0 allocs/op
BenchmarkEach-4 300000 4660 ns/op 3304 B/op 118 allocs/op
BenchmarkMap-4 200000 8404 ns/op 5572 B/op 184 allocs/op
BenchmarkEachWithBreak-4 2000000 806 ns/op 560 B/op 20 allocs/op
BenchmarkAttr-4 100000000 21.6 ns/op 0 B/op 0 allocs/op
BenchmarkText-4 200000 8911 ns/op 7536 B/op 110 allocs/op
BenchmarkLength-4 2000000000 0.34 ns/op 0 B/op 0 allocs/op
BenchmarkHtml-4 3000000 405 ns/op 120 B/op 2 allocs/op
BenchmarkIs-4 100000 22228 ns/op 88 B/op 4 allocs/op
BenchmarkIsPositional-4 50000 26469 ns/op 1112 B/op 10 allocs/op
BenchmarkIsFunction-4 1000000 1240 ns/op 784 B/op 28 allocs/op
BenchmarkIsSelection-4 50000 33709 ns/op 20960 B/op 749 allocs/op
BenchmarkIsNodes-4 50000 33711 ns/op 20960 B/op 749 allocs/op
BenchmarkHasClass-4 10000 236005 ns/op 14944 B/op 976 allocs/op
BenchmarkContains-4 200000000 7.47 ns/op 0 B/op 0 allocs/op
BenchmarkFind-4 100000 16075 ns/op 3839 B/op 21 allocs/op
BenchmarkFindWithinSelection-4 30000 41418 ns/op 3539 B/op 82 allocs/op
BenchmarkFindSelection-4 10000 209490 ns/op 5616 B/op 89 allocs/op
BenchmarkFindNodes-4 10000 208206 ns/op 5614 B/op 89 allocs/op
BenchmarkContents-4 300000 4751 ns/op 1420 B/op 36 allocs/op
BenchmarkContentsFiltered-4 300000 5454 ns/op 1570 B/op 41 allocs/op
BenchmarkChildren-4 3000000 527 ns/op 152 B/op 7 allocs/op
BenchmarkChildrenFiltered-4 1000000 2484 ns/op 352 B/op 15 allocs/op
BenchmarkParent-4 50000 34724 ns/op 6940 B/op 387 allocs/op
BenchmarkParentFiltered-4 50000 35596 ns/op 7141 B/op 394 allocs/op
BenchmarkParents-4 20000 62094 ns/op 30720 B/op 837 allocs/op
BenchmarkParentsFiltered-4 20000 63223 ns/op 31304 B/op 845 allocs/op
BenchmarkParentsUntil-4 50000 30391 ns/op 11828 B/op 358 allocs/op
BenchmarkParentsUntilSelection-4 20000 99962 ns/op 54075 B/op 1523 allocs/op
BenchmarkParentsUntilNodes-4 20000 98763 ns/op 54073 B/op 1523 allocs/op
BenchmarkParentsFilteredUntil-4 200000 7982 ns/op 2787 B/op 88 allocs/op
BenchmarkParentsFilteredUntilSelection-4 100000 13618 ns/op 5995 B/op 192 allocs/op
BenchmarkParentsFilteredUntilNodes-4 100000 13639 ns/op 5994 B/op 192 allocs/op
BenchmarkSiblings-4 20000 75287 ns/op 28453 B/op 225 allocs/op
BenchmarkSiblingsFiltered-4 20000 80139 ns/op 29543 B/op 234 allocs/op
BenchmarkNext-4 100000 14270 ns/op 4659 B/op 117 allocs/op
BenchmarkNextFiltered-4 100000 15352 ns/op 4860 B/op 123 allocs/op
BenchmarkNextAll-4 20000 60811 ns/op 22771 B/op 157 allocs/op
BenchmarkNextAllFiltered-4 20000 69079 ns/op 23871 B/op 166 allocs/op
BenchmarkPrev-4 100000 14417 ns/op 4659 B/op 117 allocs/op
BenchmarkPrevFiltered-4 100000 15443 ns/op 4859 B/op 123 allocs/op
BenchmarkPrevAll-4 100000 22008 ns/op 7346 B/op 120 allocs/op
BenchmarkPrevAllFiltered-4 100000 23212 ns/op 7544 B/op 126 allocs/op
BenchmarkNextUntil-4 50000 30589 ns/op 8767 B/op 267 allocs/op
BenchmarkNextUntilSelection-4 30000 40875 ns/op 19862 B/op 546 allocs/op
BenchmarkNextUntilNodes-4 100000 15987 ns/op 8134 B/op 249 allocs/op
BenchmarkPrevUntil-4 20000 98799 ns/op 25727 B/op 467 allocs/op
BenchmarkPrevUntilSelection-4 30000 51874 ns/op 24875 B/op 694 allocs/op
BenchmarkPrevUntilNodes-4 100000 12901 ns/op 6334 B/op 204 allocs/op
BenchmarkNextFilteredUntil-4 100000 19869 ns/op 5909 B/op 177 allocs/op
BenchmarkNextFilteredUntilSelection-4 30000 45412 ns/op 20557 B/op 571 allocs/op
BenchmarkNextFilteredUntilNodes-4 30000 45363 ns/op 20557 B/op 571 allocs/op
BenchmarkPrevFilteredUntil-4 100000 19357 ns/op 6033 B/op 179 allocs/op
BenchmarkPrevFilteredUntilSelection-4 30000 46396 ns/op 21305 B/op 591 allocs/op
BenchmarkPrevFilteredUntilNodes-4 30000 46133 ns/op 21305 B/op 591 allocs/op
BenchmarkClosest-4 500000 3448 ns/op 160 B/op 8 allocs/op
BenchmarkClosestSelection-4 3000000 528 ns/op 96 B/op 6 allocs/op
BenchmarkClosestNodes-4 3000000 523 ns/op 96 B/op 6 allocs/op
PASS
ok github.com/PuerkitoBio/goquery 162.012s
+86
View File
@@ -0,0 +1,86 @@
BenchmarkFirst-4 30000000 51.7 ns/op 48 B/op 1 allocs/op
BenchmarkLast-4 30000000 51.9 ns/op 48 B/op 1 allocs/op
BenchmarkEq-4 30000000 50.0 ns/op 48 B/op 1 allocs/op
BenchmarkSlice-4 500000000 3.47 ns/op 0 B/op 0 allocs/op
BenchmarkGet-4 2000000000 1.68 ns/op 0 B/op 0 allocs/op
BenchmarkIndex-4 2000000 804 ns/op 248 B/op 10 allocs/op
BenchmarkIndexSelector-4 100000 16285 ns/op 3839 B/op 21 allocs/op
BenchmarkIndexOfNode-4 200000000 6.50 ns/op 0 B/op 0 allocs/op
BenchmarkIndexOfSelection-4 200000000 7.02 ns/op 0 B/op 0 allocs/op
BenchmarkMetalReviewExample-4 10000 143160 ns/op 12417 B/op 320 allocs/op
BenchmarkAdd-4 200000 10326 ns/op 208 B/op 9 allocs/op
BenchmarkAddSelection-4 10000000 155 ns/op 48 B/op 1 allocs/op
BenchmarkAddNodes-4 10000000 156 ns/op 48 B/op 1 allocs/op
BenchmarkAddNodesBig-4 20000 94439 ns/op 21847 B/op 37 allocs/op
BenchmarkAndSelf-4 1000000 1791 ns/op 1008 B/op 5 allocs/op
BenchmarkFilter-4 100000 19470 ns/op 360 B/op 8 allocs/op
BenchmarkNot-4 100000 22500 ns/op 136 B/op 5 allocs/op
BenchmarkFilterFunction-4 50000 34578 ns/op 22976 B/op 755 allocs/op
BenchmarkNotFunction-4 50000 38703 ns/op 29120 B/op 757 allocs/op
BenchmarkFilterNodes-4 50000 34486 ns/op 20960 B/op 749 allocs/op
BenchmarkNotNodes-4 30000 41094 ns/op 29120 B/op 757 allocs/op
BenchmarkFilterSelection-4 50000 33623 ns/op 20960 B/op 749 allocs/op
BenchmarkNotSelection-4 30000 41483 ns/op 29120 B/op 757 allocs/op
BenchmarkHas-4 5000 266628 ns/op 2371 B/op 50 allocs/op
BenchmarkHasNodes-4 10000 152617 ns/op 21184 B/op 752 allocs/op
BenchmarkHasSelection-4 10000 156682 ns/op 21184 B/op 752 allocs/op
BenchmarkEnd-4 2000000000 1.00 ns/op 0 B/op 0 allocs/op
BenchmarkEach-4 300000 4712 ns/op 3304 B/op 118 allocs/op
BenchmarkMap-4 200000 8434 ns/op 5572 B/op 184 allocs/op
BenchmarkEachWithBreak-4 2000000 819 ns/op 560 B/op 20 allocs/op
BenchmarkAttr-4 100000000 21.7 ns/op 0 B/op 0 allocs/op
BenchmarkText-4 200000 9376 ns/op 7536 B/op 110 allocs/op
BenchmarkLength-4 2000000000 0.35 ns/op 0 B/op 0 allocs/op
BenchmarkHtml-4 5000000 401 ns/op 120 B/op 2 allocs/op
BenchmarkIs-4 100000 22214 ns/op 88 B/op 4 allocs/op
BenchmarkIsPositional-4 50000 26559 ns/op 1112 B/op 10 allocs/op
BenchmarkIsFunction-4 1000000 1228 ns/op 784 B/op 28 allocs/op
BenchmarkIsSelection-4 50000 33471 ns/op 20960 B/op 749 allocs/op
BenchmarkIsNodes-4 50000 34461 ns/op 20960 B/op 749 allocs/op
BenchmarkHasClass-4 10000 232429 ns/op 14944 B/op 976 allocs/op
BenchmarkContains-4 200000000 7.62 ns/op 0 B/op 0 allocs/op
BenchmarkFind-4 100000 16114 ns/op 3839 B/op 21 allocs/op
BenchmarkFindWithinSelection-4 30000 42520 ns/op 3540 B/op 82 allocs/op
BenchmarkFindSelection-4 10000 209801 ns/op 5615 B/op 89 allocs/op
BenchmarkFindNodes-4 10000 209082 ns/op 5614 B/op 89 allocs/op
BenchmarkContents-4 300000 4836 ns/op 1420 B/op 36 allocs/op
BenchmarkContentsFiltered-4 200000 5495 ns/op 1570 B/op 41 allocs/op
BenchmarkChildren-4 3000000 527 ns/op 152 B/op 7 allocs/op
BenchmarkChildrenFiltered-4 500000 2499 ns/op 352 B/op 15 allocs/op
BenchmarkParent-4 50000 34072 ns/op 6942 B/op 387 allocs/op
BenchmarkParentFiltered-4 50000 36077 ns/op 7141 B/op 394 allocs/op
BenchmarkParents-4 20000 64118 ns/op 30719 B/op 837 allocs/op
BenchmarkParentsFiltered-4 20000 63432 ns/op 31303 B/op 845 allocs/op
BenchmarkParentsUntil-4 50000 29589 ns/op 11829 B/op 358 allocs/op
BenchmarkParentsUntilSelection-4 10000 101033 ns/op 54076 B/op 1523 allocs/op
BenchmarkParentsUntilNodes-4 10000 100584 ns/op 54076 B/op 1523 allocs/op
BenchmarkParentsFilteredUntil-4 200000 8061 ns/op 2787 B/op 88 allocs/op
BenchmarkParentsFilteredUntilSelection-4 100000 13848 ns/op 5995 B/op 192 allocs/op
BenchmarkParentsFilteredUntilNodes-4 100000 13766 ns/op 5995 B/op 192 allocs/op
BenchmarkSiblings-4 20000 75135 ns/op 28453 B/op 225 allocs/op
BenchmarkSiblingsFiltered-4 20000 80532 ns/op 29544 B/op 234 allocs/op
BenchmarkNext-4 100000 14200 ns/op 4660 B/op 117 allocs/op
BenchmarkNextFiltered-4 100000 15284 ns/op 4859 B/op 123 allocs/op
BenchmarkNextAll-4 20000 60889 ns/op 22774 B/op 157 allocs/op
BenchmarkNextAllFiltered-4 20000 65125 ns/op 23869 B/op 166 allocs/op
BenchmarkPrev-4 100000 14448 ns/op 4659 B/op 117 allocs/op
BenchmarkPrevFiltered-4 100000 15444 ns/op 4859 B/op 123 allocs/op
BenchmarkPrevAll-4 100000 22019 ns/op 7344 B/op 120 allocs/op
BenchmarkPrevAllFiltered-4 100000 23307 ns/op 7545 B/op 126 allocs/op
BenchmarkNextUntil-4 50000 30287 ns/op 8766 B/op 267 allocs/op
BenchmarkNextUntilSelection-4 30000 41476 ns/op 19862 B/op 546 allocs/op
BenchmarkNextUntilNodes-4 100000 16106 ns/op 8133 B/op 249 allocs/op
BenchmarkPrevUntil-4 20000 98951 ns/op 25728 B/op 467 allocs/op
BenchmarkPrevUntilSelection-4 30000 52390 ns/op 24875 B/op 694 allocs/op
BenchmarkPrevUntilNodes-4 100000 12986 ns/op 6334 B/op 204 allocs/op
BenchmarkNextFilteredUntil-4 100000 19365 ns/op 5908 B/op 177 allocs/op
BenchmarkNextFilteredUntilSelection-4 30000 45334 ns/op 20555 B/op 571 allocs/op
BenchmarkNextFilteredUntilNodes-4 30000 45292 ns/op 20556 B/op 571 allocs/op
BenchmarkPrevFilteredUntil-4 100000 19412 ns/op 6032 B/op 179 allocs/op
BenchmarkPrevFilteredUntilSelection-4 30000 46286 ns/op 21304 B/op 591 allocs/op
BenchmarkPrevFilteredUntilNodes-4 30000 46554 ns/op 21305 B/op 591 allocs/op
BenchmarkClosest-4 500000 3480 ns/op 160 B/op 8 allocs/op
BenchmarkClosestSelection-4 2000000 722 ns/op 96 B/op 6 allocs/op
BenchmarkClosestNodes-4 2000000 719 ns/op 96 B/op 6 allocs/op
PASS
ok github.com/PuerkitoBio/goquery 160.565s
+12 -4
View File
@@ -70,7 +70,9 @@ func BenchmarkIndex(b *testing.B) {
for i := 0; i < b.N; i++ {
j = sel.Index()
}
b.Logf("Index=%d", j)
if j != 3 {
b.Fatalf("want 3, got %d", j)
}
}
func BenchmarkIndexSelector(b *testing.B) {
@@ -82,7 +84,9 @@ func BenchmarkIndexSelector(b *testing.B) {
for i := 0; i < b.N; i++ {
j = sel.IndexSelector("dd")
}
b.Logf("IndexSelector=%d", j)
if j != 4 {
b.Fatalf("want 4, got %d", j)
}
}
func BenchmarkIndexOfNode(b *testing.B) {
@@ -96,7 +100,9 @@ func BenchmarkIndexOfNode(b *testing.B) {
for i := 0; i < b.N; i++ {
j = sel.IndexOfNode(n)
}
b.Logf("IndexOfNode=%d", j)
if j != 2 {
b.Fatalf("want 2, got %d", j)
}
}
func BenchmarkIndexOfSelection(b *testing.B) {
@@ -108,5 +114,7 @@ func BenchmarkIndexOfSelection(b *testing.B) {
for i := 0; i < b.N; i++ {
j = sel.IndexOfSelection(sel2)
}
b.Logf("IndexOfSelection=%d", j)
if j != 2 {
b.Fatalf("want 2, got %d", j)
}
}
-2
View File
@@ -37,6 +37,4 @@ func BenchmarkMetalReviewExample(b *testing.B) {
}
})
}
b.Log(buf.String())
b.Logf("MetalReviewExample=%d", n)
}
+36 -4
View File
@@ -17,7 +17,9 @@ func BenchmarkAdd(b *testing.B) {
sel.Add("h2[title]")
}
}
b.Logf("Add=%d", n)
if n != 43 {
b.Fatalf("want 43, got %d", n)
}
}
func BenchmarkAddSelection(b *testing.B) {
@@ -34,7 +36,9 @@ func BenchmarkAddSelection(b *testing.B) {
sel.AddSelection(sel2)
}
}
b.Logf("AddSelection=%d", n)
if n != 43 {
b.Fatalf("want 43, got %d", n)
}
}
func BenchmarkAddNodes(b *testing.B) {
@@ -52,7 +56,33 @@ func BenchmarkAddNodes(b *testing.B) {
sel.AddNodes(nodes...)
}
}
b.Logf("AddNodes=%d", n)
if n != 43 {
b.Fatalf("want 43, got %d", n)
}
}
func BenchmarkAddNodesBig(b *testing.B) {
var n int
doc := DocW()
sel := doc.Find("li")
// make nodes > 1000
nodes := sel.Nodes
nodes = append(nodes, nodes...)
nodes = append(nodes, nodes...)
sel = doc.Find("xyz")
b.ResetTimer()
for i := 0; i < b.N; i++ {
if n == 0 {
n = sel.AddNodes(nodes...).Length()
} else {
sel.AddNodes(nodes...)
}
}
if n != 373 {
b.Fatalf("want 373, got %d", n)
}
}
func BenchmarkAndSelf(b *testing.B) {
@@ -68,5 +98,7 @@ func BenchmarkAndSelf(b *testing.B) {
sel.AndSelf()
}
}
b.Logf("AndSelf=%d", n)
if n != 44 {
b.Fatalf("want 44, got %d", n)
}
}
+36 -12
View File
@@ -17,7 +17,9 @@ func BenchmarkFilter(b *testing.B) {
sel.Filter(".toclevel-1")
}
}
b.Logf("Filter=%d", n)
if n != 13 {
b.Fatalf("want 13, got %d", n)
}
}
func BenchmarkNot(b *testing.B) {
@@ -33,7 +35,9 @@ func BenchmarkNot(b *testing.B) {
sel.Filter(".toclevel-2")
}
}
b.Logf("Not=%d", n)
if n != 371 {
b.Fatalf("want 371, got %d", n)
}
}
func BenchmarkFilterFunction(b *testing.B) {
@@ -52,7 +56,9 @@ func BenchmarkFilterFunction(b *testing.B) {
sel.FilterFunction(f)
}
}
b.Logf("FilterFunction=%d", n)
if n != 112 {
b.Fatalf("want 112, got %d", n)
}
}
func BenchmarkNotFunction(b *testing.B) {
@@ -71,7 +77,9 @@ func BenchmarkNotFunction(b *testing.B) {
sel.NotFunction(f)
}
}
b.Logf("NotFunction=%d", n)
if n != 261 {
b.Fatalf("want 261, got %d", n)
}
}
func BenchmarkFilterNodes(b *testing.B) {
@@ -89,7 +97,9 @@ func BenchmarkFilterNodes(b *testing.B) {
sel.FilterNodes(nodes...)
}
}
b.Logf("FilterNodes=%d", n)
if n != 2 {
b.Fatalf("want 2, got %d", n)
}
}
func BenchmarkNotNodes(b *testing.B) {
@@ -107,7 +117,9 @@ func BenchmarkNotNodes(b *testing.B) {
sel.NotNodes(nodes...)
}
}
b.Logf("NotNodes=%d", n)
if n != 360 {
b.Fatalf("want 360, got %d", n)
}
}
func BenchmarkFilterSelection(b *testing.B) {
@@ -124,7 +136,9 @@ func BenchmarkFilterSelection(b *testing.B) {
sel.FilterSelection(sel2)
}
}
b.Logf("FilterSelection=%d", n)
if n != 2 {
b.Fatalf("want 2, got %d", n)
}
}
func BenchmarkNotSelection(b *testing.B) {
@@ -141,7 +155,9 @@ func BenchmarkNotSelection(b *testing.B) {
sel.NotSelection(sel2)
}
}
b.Logf("NotSelection=%d", n)
if n != 360 {
b.Fatalf("want 360, got %d", n)
}
}
func BenchmarkHas(b *testing.B) {
@@ -157,7 +173,9 @@ func BenchmarkHas(b *testing.B) {
sel.Has(".editsection")
}
}
b.Logf("Has=%d", n)
if n != 13 {
b.Fatalf("want 13, got %d", n)
}
}
func BenchmarkHasNodes(b *testing.B) {
@@ -175,7 +193,9 @@ func BenchmarkHasNodes(b *testing.B) {
sel.HasNodes(nodes...)
}
}
b.Logf("HasNodes=%d", n)
if n != 15 {
b.Fatalf("want 15, got %d", n)
}
}
func BenchmarkHasSelection(b *testing.B) {
@@ -192,7 +212,9 @@ func BenchmarkHasSelection(b *testing.B) {
sel.HasSelection(sel2)
}
}
b.Logf("HasSelection=%d", n)
if n != 15 {
b.Fatalf("want 15, got %d", n)
}
}
func BenchmarkEnd(b *testing.B) {
@@ -208,5 +230,7 @@ func BenchmarkEnd(b *testing.B) {
sel.End()
}
}
b.Logf("End=%d", n)
if n != 373 {
b.Fatalf("want 373, got %d", n)
}
}
+9 -3
View File
@@ -19,7 +19,9 @@ func BenchmarkEach(b *testing.B) {
n = tmp
}
}
b.Logf("Each=%d", n)
if n != 59 {
b.Fatalf("want 59, got %d", n)
}
}
func BenchmarkMap(b *testing.B) {
@@ -38,7 +40,9 @@ func BenchmarkMap(b *testing.B) {
n = tmp
}
}
b.Logf("Map=%d", n)
if n != 59 {
b.Fatalf("want 59, got %d", n)
}
}
func BenchmarkEachWithBreak(b *testing.B) {
@@ -58,5 +62,7 @@ func BenchmarkEachWithBreak(b *testing.B) {
n = tmp
}
}
b.Logf("Each=%d", n)
if n != 10 {
b.Fatalf("want 10, got %d", n)
}
}
+6 -2
View File
@@ -13,7 +13,9 @@ func BenchmarkAttr(b *testing.B) {
for i := 0; i < b.N; i++ {
s, _ = sel.Attr("id")
}
b.Logf("Attr=%s", s)
if s != "firstHeading" {
b.Fatalf("want firstHeading, got %q", s)
}
}
func BenchmarkText(b *testing.B) {
@@ -34,7 +36,9 @@ func BenchmarkLength(b *testing.B) {
for i := 0; i < b.N; i++ {
n = sel.Length()
}
b.Logf("Length=%d", n)
if n != 14 {
b.Fatalf("want 14, got %d", n)
}
}
func BenchmarkHtml(b *testing.B) {
+21 -7
View File
@@ -13,7 +13,9 @@ func BenchmarkIs(b *testing.B) {
for i := 0; i < b.N; i++ {
y = sel.Is(".toclevel-2")
}
b.Logf("Is=%v", y)
if !y {
b.Fatal("want true")
}
}
func BenchmarkIsPositional(b *testing.B) {
@@ -25,7 +27,9 @@ func BenchmarkIsPositional(b *testing.B) {
for i := 0; i < b.N; i++ {
y = sel.Is("li:nth-child(2)")
}
b.Logf("IsPositional=%v", y)
if !y {
b.Fatal("want true")
}
}
func BenchmarkIsFunction(b *testing.B) {
@@ -40,7 +44,9 @@ func BenchmarkIsFunction(b *testing.B) {
for i := 0; i < b.N; i++ {
y = sel.IsFunction(f)
}
b.Logf("IsFunction=%v", y)
if !y {
b.Fatal("want true")
}
}
func BenchmarkIsSelection(b *testing.B) {
@@ -53,7 +59,9 @@ func BenchmarkIsSelection(b *testing.B) {
for i := 0; i < b.N; i++ {
y = sel.IsSelection(sel2)
}
b.Logf("IsSelection=%v", y)
if !y {
b.Fatal("want true")
}
}
func BenchmarkIsNodes(b *testing.B) {
@@ -67,7 +75,9 @@ func BenchmarkIsNodes(b *testing.B) {
for i := 0; i < b.N; i++ {
y = sel.IsNodes(nodes...)
}
b.Logf("IsNodes=%v", y)
if !y {
b.Fatal("want true")
}
}
func BenchmarkHasClass(b *testing.B) {
@@ -79,7 +89,9 @@ func BenchmarkHasClass(b *testing.B) {
for i := 0; i < b.N; i++ {
y = sel.HasClass("official")
}
b.Logf("HasClass=%v", y)
if !y {
b.Fatal("want true")
}
}
func BenchmarkContains(b *testing.B) {
@@ -93,5 +105,7 @@ func BenchmarkContains(b *testing.B) {
for i := 0; i < b.N; i++ {
y = sel.Contains(node)
}
b.Logf("Contains=%v", y)
if !y {
b.Fatal("want true")
}
}
+129 -43
View File
@@ -15,7 +15,9 @@ func BenchmarkFind(b *testing.B) {
DocB().Find("dd")
}
}
b.Logf("Find=%d", n)
if n != 41 {
b.Fatalf("want 41, got %d", n)
}
}
func BenchmarkFindWithinSelection(b *testing.B) {
@@ -31,7 +33,9 @@ func BenchmarkFindWithinSelection(b *testing.B) {
sel.Find("a[class]")
}
}
b.Logf("FindWithinSelection=%d", n)
if n != 39 {
b.Fatalf("want 39, got %d", n)
}
}
func BenchmarkFindSelection(b *testing.B) {
@@ -48,7 +52,9 @@ func BenchmarkFindSelection(b *testing.B) {
sel.FindSelection(sel2)
}
}
b.Logf("FindSelection=%d", n)
if n != 73 {
b.Fatalf("want 73, got %d", n)
}
}
func BenchmarkFindNodes(b *testing.B) {
@@ -66,7 +72,9 @@ func BenchmarkFindNodes(b *testing.B) {
sel.FindNodes(nodes...)
}
}
b.Logf("FindNodes=%d", n)
if n != 73 {
b.Fatalf("want 73, got %d", n)
}
}
func BenchmarkContents(b *testing.B) {
@@ -82,7 +90,9 @@ func BenchmarkContents(b *testing.B) {
sel.Contents()
}
}
b.Logf("Contents=%d", n)
if n != 16 {
b.Fatalf("want 16, got %d", n)
}
}
func BenchmarkContentsFiltered(b *testing.B) {
@@ -98,7 +108,9 @@ func BenchmarkContentsFiltered(b *testing.B) {
sel.ContentsFiltered("a[href=\"#Examples\"]")
}
}
b.Logf("ContentsFiltered=%d", n)
if n != 1 {
b.Fatalf("want 1, got %d", n)
}
}
func BenchmarkChildren(b *testing.B) {
@@ -114,7 +126,9 @@ func BenchmarkChildren(b *testing.B) {
sel.Children()
}
}
b.Logf("Children=%d", n)
if n != 2 {
b.Fatalf("want 2, got %d", n)
}
}
func BenchmarkChildrenFiltered(b *testing.B) {
@@ -130,7 +144,9 @@ func BenchmarkChildrenFiltered(b *testing.B) {
sel.ChildrenFiltered(".editsection")
}
}
b.Logf("ChildrenFiltered=%d", n)
if n != 2 {
b.Fatalf("want 2, got %d", n)
}
}
func BenchmarkParent(b *testing.B) {
@@ -146,7 +162,9 @@ func BenchmarkParent(b *testing.B) {
sel.Parent()
}
}
b.Logf("Parent=%d", n)
if n != 55 {
b.Fatalf("want 55, got %d", n)
}
}
func BenchmarkParentFiltered(b *testing.B) {
@@ -162,7 +180,9 @@ func BenchmarkParentFiltered(b *testing.B) {
sel.ParentFiltered("ul[id]")
}
}
b.Logf("ParentFiltered=%d", n)
if n != 4 {
b.Fatalf("want 4, got %d", n)
}
}
func BenchmarkParents(b *testing.B) {
@@ -178,7 +198,9 @@ func BenchmarkParents(b *testing.B) {
sel.Parents()
}
}
b.Logf("Parents=%d", n)
if n != 73 {
b.Fatalf("want 73, got %d", n)
}
}
func BenchmarkParentsFiltered(b *testing.B) {
@@ -194,7 +216,9 @@ func BenchmarkParentsFiltered(b *testing.B) {
sel.ParentsFiltered("tr")
}
}
b.Logf("ParentsFiltered=%d", n)
if n != 18 {
b.Fatalf("want 18, got %d", n)
}
}
func BenchmarkParentsUntil(b *testing.B) {
@@ -210,7 +234,9 @@ func BenchmarkParentsUntil(b *testing.B) {
sel.ParentsUntil("table")
}
}
b.Logf("ParentsUntil=%d", n)
if n != 52 {
b.Fatalf("want 52, got %d", n)
}
}
func BenchmarkParentsUntilSelection(b *testing.B) {
@@ -227,7 +253,9 @@ func BenchmarkParentsUntilSelection(b *testing.B) {
sel.ParentsUntilSelection(sel2)
}
}
b.Logf("ParentsUntilSelection=%d", n)
if n != 70 {
b.Fatalf("want 70, got %d", n)
}
}
func BenchmarkParentsUntilNodes(b *testing.B) {
@@ -245,7 +273,9 @@ func BenchmarkParentsUntilNodes(b *testing.B) {
sel.ParentsUntilNodes(nodes...)
}
}
b.Logf("ParentsUntilNodes=%d", n)
if n != 70 {
b.Fatalf("want 70, got %d", n)
}
}
func BenchmarkParentsFilteredUntil(b *testing.B) {
@@ -261,7 +291,9 @@ func BenchmarkParentsFilteredUntil(b *testing.B) {
sel.ParentsFilteredUntil(":nth-child(1)", "ul")
}
}
b.Logf("ParentsFilteredUntil=%d", n)
if n != 2 {
b.Fatalf("want 2, got %d", n)
}
}
func BenchmarkParentsFilteredUntilSelection(b *testing.B) {
@@ -278,7 +310,9 @@ func BenchmarkParentsFilteredUntilSelection(b *testing.B) {
sel.ParentsFilteredUntilSelection(":nth-child(1)", sel2)
}
}
b.Logf("ParentsFilteredUntilSelection=%d", n)
if n != 2 {
b.Fatalf("want 2, got %d", n)
}
}
func BenchmarkParentsFilteredUntilNodes(b *testing.B) {
@@ -296,7 +330,9 @@ func BenchmarkParentsFilteredUntilNodes(b *testing.B) {
sel.ParentsFilteredUntilNodes(":nth-child(1)", nodes...)
}
}
b.Logf("ParentsFilteredUntilNodes=%d", n)
if n != 2 {
b.Fatalf("want 2, got %d", n)
}
}
func BenchmarkSiblings(b *testing.B) {
@@ -312,7 +348,9 @@ func BenchmarkSiblings(b *testing.B) {
sel.Siblings()
}
}
b.Logf("Siblings=%d", n)
if n != 293 {
b.Fatalf("want 293, got %d", n)
}
}
func BenchmarkSiblingsFiltered(b *testing.B) {
@@ -328,7 +366,9 @@ func BenchmarkSiblingsFiltered(b *testing.B) {
sel.SiblingsFiltered("[class]")
}
}
b.Logf("SiblingsFiltered=%d", n)
if n != 46 {
b.Fatalf("want 46, got %d", n)
}
}
func BenchmarkNext(b *testing.B) {
@@ -344,7 +384,9 @@ func BenchmarkNext(b *testing.B) {
sel.Next()
}
}
b.Logf("Next=%d", n)
if n != 49 {
b.Fatalf("want 49, got %d", n)
}
}
func BenchmarkNextFiltered(b *testing.B) {
@@ -360,7 +402,9 @@ func BenchmarkNextFiltered(b *testing.B) {
sel.NextFiltered("[class]")
}
}
b.Logf("NextFiltered=%d", n)
if n != 6 {
b.Fatalf("want 6, got %d", n)
}
}
func BenchmarkNextAll(b *testing.B) {
@@ -376,7 +420,9 @@ func BenchmarkNextAll(b *testing.B) {
sel.NextAll()
}
}
b.Logf("NextAll=%d", n)
if n != 234 {
b.Fatalf("want 234, got %d", n)
}
}
func BenchmarkNextAllFiltered(b *testing.B) {
@@ -392,7 +438,9 @@ func BenchmarkNextAllFiltered(b *testing.B) {
sel.NextAllFiltered("[class]")
}
}
b.Logf("NextAllFiltered=%d", n)
if n != 33 {
b.Fatalf("want 33, got %d", n)
}
}
func BenchmarkPrev(b *testing.B) {
@@ -408,7 +456,9 @@ func BenchmarkPrev(b *testing.B) {
sel.Prev()
}
}
b.Logf("Prev=%d", n)
if n != 49 {
b.Fatalf("want 49, got %d", n)
}
}
func BenchmarkPrevFiltered(b *testing.B) {
@@ -426,7 +476,9 @@ func BenchmarkPrevFiltered(b *testing.B) {
}
// There is one more Prev li with a class, compared to Next li with a class
// (confirmed by looking at the HTML, this is ok)
b.Logf("PrevFiltered=%d", n)
if n != 7 {
b.Fatalf("want 7, got %d", n)
}
}
func BenchmarkPrevAll(b *testing.B) {
@@ -442,7 +494,9 @@ func BenchmarkPrevAll(b *testing.B) {
sel.PrevAll()
}
}
b.Logf("PrevAll=%d", n)
if n != 78 {
b.Fatalf("want 78, got %d", n)
}
}
func BenchmarkPrevAllFiltered(b *testing.B) {
@@ -458,7 +512,9 @@ func BenchmarkPrevAllFiltered(b *testing.B) {
sel.PrevAllFiltered("[class]")
}
}
b.Logf("PrevAllFiltered=%d", n)
if n != 6 {
b.Fatalf("want 6, got %d", n)
}
}
func BenchmarkNextUntil(b *testing.B) {
@@ -474,7 +530,9 @@ func BenchmarkNextUntil(b *testing.B) {
sel.NextUntil(":nth-child(4)")
}
}
b.Logf("NextUntil=%d", n)
if n != 84 {
b.Fatalf("want 84, got %d", n)
}
}
func BenchmarkNextUntilSelection(b *testing.B) {
@@ -491,7 +549,9 @@ func BenchmarkNextUntilSelection(b *testing.B) {
sel.NextUntilSelection(sel2)
}
}
b.Logf("NextUntilSelection=%d", n)
if n != 42 {
b.Fatalf("want 42, got %d", n)
}
}
func BenchmarkNextUntilNodes(b *testing.B) {
@@ -509,7 +569,9 @@ func BenchmarkNextUntilNodes(b *testing.B) {
sel.NextUntilNodes(nodes...)
}
}
b.Logf("NextUntilNodes=%d", n)
if n != 12 {
b.Fatalf("want 12, got %d", n)
}
}
func BenchmarkPrevUntil(b *testing.B) {
@@ -525,7 +587,9 @@ func BenchmarkPrevUntil(b *testing.B) {
sel.PrevUntil(":nth-child(4)")
}
}
b.Logf("PrevUntil=%d", n)
if n != 238 {
b.Fatalf("want 238, got %d", n)
}
}
func BenchmarkPrevUntilSelection(b *testing.B) {
@@ -542,7 +606,9 @@ func BenchmarkPrevUntilSelection(b *testing.B) {
sel.PrevUntilSelection(sel2)
}
}
b.Logf("PrevUntilSelection=%d", n)
if n != 49 {
b.Fatalf("want 49, got %d", n)
}
}
func BenchmarkPrevUntilNodes(b *testing.B) {
@@ -560,7 +626,9 @@ func BenchmarkPrevUntilNodes(b *testing.B) {
sel.PrevUntilNodes(nodes...)
}
}
b.Logf("PrevUntilNodes=%d", n)
if n != 11 {
b.Fatalf("want 11, got %d", n)
}
}
func BenchmarkNextFilteredUntil(b *testing.B) {
@@ -576,7 +644,9 @@ func BenchmarkNextFilteredUntil(b *testing.B) {
sel.NextFilteredUntil("p", "div")
}
}
b.Logf("NextFilteredUntil=%d", n)
if n != 22 {
b.Fatalf("want 22, got %d", n)
}
}
func BenchmarkNextFilteredUntilSelection(b *testing.B) {
@@ -593,7 +663,9 @@ func BenchmarkNextFilteredUntilSelection(b *testing.B) {
sel.NextFilteredUntilSelection("p", sel2)
}
}
b.Logf("NextFilteredUntilSelection=%d", n)
if n != 22 {
b.Fatalf("want 22, got %d", n)
}
}
func BenchmarkNextFilteredUntilNodes(b *testing.B) {
@@ -611,7 +683,9 @@ func BenchmarkNextFilteredUntilNodes(b *testing.B) {
sel.NextFilteredUntilNodes("p", nodes...)
}
}
b.Logf("NextFilteredUntilNodes=%d", n)
if n != 22 {
b.Fatalf("want 22, got %d", n)
}
}
func BenchmarkPrevFilteredUntil(b *testing.B) {
@@ -627,7 +701,9 @@ func BenchmarkPrevFilteredUntil(b *testing.B) {
sel.PrevFilteredUntil("p", "div")
}
}
b.Logf("PrevFilteredUntil=%d", n)
if n != 20 {
b.Fatalf("want 20, got %d", n)
}
}
func BenchmarkPrevFilteredUntilSelection(b *testing.B) {
@@ -644,7 +720,9 @@ func BenchmarkPrevFilteredUntilSelection(b *testing.B) {
sel.PrevFilteredUntilSelection("p", sel2)
}
}
b.Logf("PrevFilteredUntilSelection=%d", n)
if n != 20 {
b.Fatalf("want 20, got %d", n)
}
}
func BenchmarkPrevFilteredUntilNodes(b *testing.B) {
@@ -662,7 +740,9 @@ func BenchmarkPrevFilteredUntilNodes(b *testing.B) {
sel.PrevFilteredUntilNodes("p", nodes...)
}
}
b.Logf("PrevFilteredUntilNodes=%d", n)
if n != 20 {
b.Fatalf("want 20, got %d", n)
}
}
func BenchmarkClosest(b *testing.B) {
@@ -678,7 +758,9 @@ func BenchmarkClosest(b *testing.B) {
sel.Closest(".pvk-content")
}
}
b.Logf("Closest=%d", n)
if n != 2 {
b.Fatalf("want 2, got %d", n)
}
}
func BenchmarkClosestSelection(b *testing.B) {
@@ -695,7 +777,9 @@ func BenchmarkClosestSelection(b *testing.B) {
sel.ClosestSelection(sel2)
}
}
b.Logf("ClosestSelection=%d", n)
if n != 2 {
b.Fatalf("want 2, got %d", n)
}
}
func BenchmarkClosestNodes(b *testing.B) {
@@ -712,5 +796,7 @@ func BenchmarkClosestNodes(b *testing.B) {
sel.ClosestNodes(nodes...)
}
}
b.Logf("ClosestNodes=%d", n)
if n != 2 {
b.Fatalf("want 2, got %d", n)
}
}
+2 -2
View File
@@ -13,7 +13,7 @@ and then:
```
// Load the URL
res, err := http.Get(url)
if e != nil {
if err != nil {
// handle error
}
defer res.Body.Close()
@@ -65,4 +65,4 @@ Thanks to github user @jmoiron.
[otto]: https://github.com/robertkrimen/otto
[exotto]: https://gist.github.com/cryptix/87127f76a94183747b53
[iconv]: http://godoc.org/?q=iconv
[text]: http://godoc.org/code.google.com/p/go.text/encoding
[text]: https://godoc.org/golang.org/x/text/encoding
+2 -2
View File
@@ -16,9 +16,9 @@ func Example() {
}
// Find the review items
doc.Find(".reviews-wrap article .review-rhs").Each(func(i int, s *goquery.Selection) {
doc.Find(".sidebar-reviews article .content-block").Each(func(i int, s *goquery.Selection) {
// For each item found, get the band and title
band := s.Find("h3").Text()
band := s.Find("a").Text()
title := s.Find("i").Text()
fmt.Printf("Review %d: %s - %s\n", i, band, title)
})
+25 -1
View File
@@ -35,12 +35,36 @@ func (s *Selection) Union(sel *Selection) *Selection {
// AddNodes adds the specified nodes to those in the
// current selection and returns a new Selection object.
func (s *Selection) AddNodes(nodes ...*html.Node) *Selection {
return pushStack(s, appendWithoutDuplicates(s.Nodes, nodes))
return pushStack(s, appendWithoutDuplicates(s.Nodes, nodes, nil))
}
// AndSelf adds the previous set of elements on the stack to the current set.
// It returns a new Selection object containing the current Selection combined
// with the previous one.
// Deprecated: This function has been deprecated and is now an alias for AddBack().
func (s *Selection) AndSelf() *Selection {
return s.AddBack()
}
// AddBack adds the previous set of elements on the stack to the current set.
// It returns a new Selection object containing the current Selection combined
// with the previous one.
func (s *Selection) AddBack() *Selection {
return s.AddSelection(s.prevSel)
}
// AddBackFiltered reduces the previous set of elements on the stack to those that
// match the selector string, and adds them to the current set.
// It returns a new Selection object containing the current Selection combined
// with the filtered previous one
func (s *Selection) AddBackFiltered(selector string) *Selection {
return s.AddSelection(s.prevSel.Filter(selector))
}
// AddBackMatcher reduces the previous set of elements on the stack to those that match
// the mateher, and adds them to the curernt set.
// It returns a new Selection object containing the current Selection combined
// with the filtered previous one
func (s *Selection) AddBackMatcher(m Matcher) *Selection {
return s.AddSelection(s.prevSel.FilterMatcher(m))
}
+40
View File
@@ -66,6 +66,24 @@ func TestAddNodesRollback(t *testing.T) {
assertEqual(t, sel, sel2)
}
func TestAddNodesBig(t *testing.T) {
doc := DocW()
sel := doc.Find("li")
assertLength(t, sel.Nodes, 373)
sel2 := doc.Find("xyz")
assertLength(t, sel2.Nodes, 0)
nodes := sel.Nodes
sel2 = sel2.AddNodes(nodes...)
assertLength(t, sel2.Nodes, 373)
nodes2 := append(nodes, nodes...)
sel2 = sel2.End().AddNodes(nodes2...)
assertLength(t, sel2.Nodes, 373)
nodes3 := append(nodes2, nodes...)
sel2 = sel2.End().AddNodes(nodes3...)
assertLength(t, sel2.Nodes, 373)
}
func TestAndSelf(t *testing.T) {
sel := Doc().Find(".span12").Last().AndSelf()
assertLength(t, sel.Nodes, 2)
@@ -76,3 +94,25 @@ func TestAndSelfRollback(t *testing.T) {
sel2 := sel.Find("a").AndSelf().End().End()
assertEqual(t, sel, sel2)
}
func TestAddBack(t *testing.T) {
sel := Doc().Find(".span12").Last().AddBack()
assertLength(t, sel.Nodes, 2)
}
func TestAddBackRollback(t *testing.T) {
sel := Doc().Find(".pvk-content")
sel2 := sel.Find("a").AddBack().End().End()
assertEqual(t, sel, sel2)
}
func TestAddBackFiltered(t *testing.T) {
sel := Doc().Find(".span12, .footer").Find("h1").AddBackFiltered(".footer")
assertLength(t, sel.Nodes, 2)
}
func TestAddBackFilteredRollback(t *testing.T) {
sel := Doc().Find(".span12, .footer")
sel2 := sel.Find("h1").AddBackFiltered(".footer").End().End()
assertEqual(t, sel, sel2)
}
+11 -1
View File
@@ -139,8 +139,18 @@ func winnow(sel *Selection, m Matcher, keep bool) []*html.Node {
// Filter based on an array of nodes, and the indicator to keep (Filter) or
// to get rid of (Not) the matching elements.
func winnowNodes(sel *Selection, nodes []*html.Node, keep bool) []*html.Node {
if len(nodes)+len(sel.Nodes) < minNodesForSet {
return grep(sel, func(i int, s *Selection) bool {
return isInSlice(nodes, s.Get(0)) == keep
})
}
set := make(map[*html.Node]bool)
for _, n := range nodes {
set[n] = true
}
return grep(sel, func(i int, s *Selection) bool {
return isInSlice(nodes, s.Get(0)) == keep
return set[s.Get(0)] == keep
})
}
+24
View File
@@ -270,6 +270,18 @@ func (s *Selection) ReplaceWithNodes(ns ...*html.Node) *Selection {
return s.Remove()
}
// SetHtml sets the html content of each element in the selection to
// specified html string.
func (s *Selection) SetHtml(html string) *Selection {
return setHtmlNodes(s, parseHtml(html)...)
}
// SetText sets the content of each element in the selection to specified content.
// The provided text string is escaped.
func (s *Selection) SetText(text string) *Selection {
return s.SetHtml(html.EscapeString(text))
}
// Unwrap removes the parents of the set of matched elements, leaving the matched
// elements (and their siblings, if any) in their place.
// It returns the original selection.
@@ -481,6 +493,18 @@ func parseHtml(h string) []*html.Node {
return nodes
}
func setHtmlNodes(s *Selection, ns ...*html.Node) *Selection {
for _, n := range s.Nodes {
for c := n.FirstChild; c != nil; c = n.FirstChild {
n.RemoveChild(c)
}
for _, c := range ns {
n.AppendChild(cloneNode(c))
}
}
return s
}
// Get the first child that is an ElementNode
func getFirstChildEl(n *html.Node) *html.Node {
c := n.FirstChild
+60
View File
@@ -278,6 +278,66 @@ func TestReplaceWithHtml(t *testing.T) {
printSel(t, doc.Selection)
}
func TestSetHtml(t *testing.T) {
doc := Doc2Clone()
q := doc.Find("#main, #foot")
q.SetHtml(`<div id="replace">test</div>`)
assertLength(t, doc.Find("#replace").Nodes, 2)
assertLength(t, doc.Find("#main, #foot").Nodes, 2)
if q.Text() != "testtest" {
t.Errorf("Expected text to be %v, found %v", "testtest", q.Text())
}
printSel(t, doc.Selection)
}
func TestSetHtmlNoMatch(t *testing.T) {
doc := Doc2Clone()
q := doc.Find("#notthere")
q.SetHtml(`<div id="replace">test</div>`)
assertLength(t, doc.Find("#replace").Nodes, 0)
printSel(t, doc.Selection)
}
func TestSetHtmlEmpty(t *testing.T) {
doc := Doc2Clone()
q := doc.Find("#main")
q.SetHtml(``)
assertLength(t, doc.Find("#main").Nodes, 1)
assertLength(t, doc.Find("#main").Children().Nodes, 0)
printSel(t, doc.Selection)
}
func TestSetText(t *testing.T) {
doc := Doc2Clone()
q := doc.Find("#main, #foot")
repl := "<div id=\"replace\">test</div>"
q.SetText(repl)
assertLength(t, doc.Find("#replace").Nodes, 0)
assertLength(t, doc.Find("#main, #foot").Nodes, 2)
if q.Text() != (repl + repl) {
t.Errorf("Expected text to be %v, found %v", (repl + repl), q.Text())
}
h, err := q.Html()
if err != nil {
t.Errorf("Error: %v", err)
}
esc := "&lt;div id=&#34;replace&#34;&gt;test&lt;/div&gt;"
if h != esc {
t.Errorf("Expected html to be %v, found %v", esc, h)
}
printSel(t, doc.Selection)
}
func TestReplaceWithSelection(t *testing.T) {
doc := Doc2Clone()
sel := doc.Find("#nf6").ReplaceWithSelection(doc.Find("#nf5"))
+27 -27
View File
@@ -1,37 +1,37 @@
#!/bin/sh
# Copyright 2012 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
# git gofmt pre-commit hook
#
# To use, store as .git/hooks/pre-commit inside your repository and make sure
# it has execute permissions.
#
# This script does not handle file names that contain spaces.
echo ">>> golint"
for dir in $(go list ./... | grep -v /vendor/)
do
golint "${dir}"
done
echo "<<< golint"
echo
# golint is purely informational, it doesn't fail with exit code != 0 if it finds something,
# because it may find a lot of false positives. Just print out its result for information.
echo "lint result (informational only):"
golint .
echo ">>> go vet"
go vet $(go list ./... | grep -v /vendor/)
echo "<<< go vet"
echo
# go vet returns 1 if an error was found. Exit the hook with this exit code.
go vet ./...
vetres=$?
echo ">>> gosimple"
gosimple $(go list ./... | grep -v /vendor/)
echo "<<< gosimple"
echo
# Check for gofmt problems and report if any.
gofiles=$(git diff --cached --name-only --diff-filter=ACM | grep '.go$')
gofiles=$(git diff --cached --name-only --diff-filter=ACM | grep '.go$' | grep -v /vendor/)
[ -z "$gofiles" ] && echo "EXIT $vetres" && exit $vetres
unformatted=$(gofmt -l $gofiles)
[ -z "$unformatted" ] && echo "EXIT $vetres" && exit $vetres
if [ -n "$gofiles" ]; then
unformatted=$(gofmt -l $gofiles)
# Some files are not gofmt'd. Print message and fail.
if [ -n "$unformatted" ]; then
# Some files are not gofmt'd.
echo >&2 "Go files must be formatted with gofmt. Please run:"
for fn in $unformatted; do
echo >&2 " gofmt -w $PWD/$fn"
done
fi
fi
echo
echo >&2 "Go files must be formatted with gofmt. Please run:"
for fn in $unformatted; do
echo >&2 " gofmt -w $PWD/$fn"
done
echo "EXIT 1"
exit 1
+18 -21
View File
@@ -63,9 +63,22 @@ func (s *Selection) Text() string {
var buf bytes.Buffer
// Slightly optimized vs calling Each: no single selection object created
for _, n := range s.Nodes {
buf.WriteString(getNodeText(n))
var f func(*html.Node)
f = func(n *html.Node) {
if n.Type == html.TextNode {
// Keep newlines and spaces, like jQuery
buf.WriteString(n.Data)
}
if n.FirstChild != nil {
for c := n.FirstChild; c != nil; c = c.NextSibling {
f(c)
}
}
}
for _, n := range s.Nodes {
f(n)
}
return buf.String()
}
@@ -112,7 +125,7 @@ func (s *Selection) AddClass(class ...string) *Selection {
for _, n := range s.Nodes {
curClasses, attr := getClassesAndAttr(n, true)
for _, newClass := range tcls {
if strings.Index(curClasses, " "+newClass+" ") == -1 {
if !strings.Contains(curClasses, " "+newClass+" ") {
curClasses += newClass + " "
}
}
@@ -129,7 +142,7 @@ func (s *Selection) HasClass(class string) bool {
class = " " + class + " "
for _, n := range s.Nodes {
classes, _ := getClassesAndAttr(n, false)
if strings.Index(classes, class) > -1 {
if strings.Contains(classes, class) {
return true
}
}
@@ -179,7 +192,7 @@ func (s *Selection) ToggleClass(class ...string) *Selection {
for _, n := range s.Nodes {
classes, attr := getClassesAndAttr(n, true)
for _, tcl := range tcls {
if strings.Index(classes, " "+tcl+" ") != -1 {
if strings.Contains(classes, " "+tcl+" ") {
classes = strings.Replace(classes, " "+tcl+" ", " ", -1)
} else {
classes += tcl + " "
@@ -192,22 +205,6 @@ func (s *Selection) ToggleClass(class ...string) *Selection {
return s
}
// Get the specified node's text content.
func getNodeText(node *html.Node) string {
if node.Type == html.TextNode {
// Keep newlines and spaces, like jQuery
return node.Data
} else if node.FirstChild != nil {
var buf bytes.Buffer
for c := node.FirstChild; c != nil; c = c.NextSibling {
buf.WriteString(getNodeText(c))
}
return buf.String()
}
return ""
}
func getAttributePtr(attrName string, n *html.Node) *html.Attribute {
if n == nil {
return nil
+8 -3
View File
@@ -143,11 +143,15 @@ func (s *Selection) ClosestMatcher(m Matcher) *Selection {
// ClosestNodes gets the first element that matches one of the nodes by testing the
// element itself and traversing up through its ancestors in the DOM tree.
func (s *Selection) ClosestNodes(nodes ...*html.Node) *Selection {
set := make(map[*html.Node]bool)
for _, n := range nodes {
set[n] = true
}
return pushStack(s, mapNodes(s.Nodes, func(i int, n *html.Node) []*html.Node {
// For each node in the selection, test the node itself, then each parent
// until a match is found.
for ; n != nil; n = n.Parent {
if isInSlice(nodes, n) {
if set[n] {
return []*html.Node{n}
}
}
@@ -684,10 +688,11 @@ func getParentNodes(nodes []*html.Node) []*html.Node {
// Returns an array of nodes mapped by calling the callback function once for
// each node in the source nodes.
func mapNodes(nodes []*html.Node, f func(int, *html.Node) []*html.Node) (result []*html.Node) {
set := make(map[*html.Node]bool)
for i, n := range nodes {
if vals := f(i, n); len(vals) > 0 {
result = appendWithoutDuplicates(result, vals)
result = appendWithoutDuplicates(result, vals, set)
}
}
return
return result
}
+10
View File
@@ -26,6 +26,16 @@ func TestFindInvalid(t *testing.T) {
assertLength(t, sel.Nodes, 0)
}
func TestFindBig(t *testing.T) {
doc := DocW()
sel := doc.Find("li")
assertLength(t, sel.Nodes, 373)
sel2 := doc.Find("span")
assertLength(t, sel2.Nodes, 448)
sel3 := sel.FindSelection(sel2)
assertLength(t, sel3.Nodes, 248)
}
func TestChainedFind(t *testing.T) {
sel := Doc().Find("div.hero-unit").Find(".row-fluid")
assertLength(t, sel.Nodes, 4)
+6 -22
View File
@@ -23,45 +23,42 @@ func Doc() *Document {
}
return doc
}
func DocClone() *Document {
return CloneDocument(Doc())
}
func Doc2() *Document {
if doc2 == nil {
doc2 = loadDoc("page2.html")
}
return doc2
}
func Doc2Clone() *Document {
return CloneDocument(Doc2())
}
func Doc3() *Document {
if doc3 == nil {
doc3 = loadDoc("page3.html")
}
return doc3
}
func Doc3Clone() *Document {
return CloneDocument(Doc3())
}
func DocB() *Document {
if docB == nil {
docB = loadDoc("gotesting.html")
}
return docB
}
func DocBClone() *Document {
return CloneDocument(DocB())
}
func DocW() *Document {
if docW == nil {
docW = loadDoc("gowiki.html")
}
return docW
}
func DocWClone() *Document {
return CloneDocument(DocW())
}
func assertLength(t *testing.T, nodes []*html.Node, length int) {
if len(nodes) != length {
@@ -108,19 +105,6 @@ func printSel(t *testing.T, sel *Selection) {
}
}
func shortPrintSel(t *testing.T, sel *Selection) {
sel.Each(func(i int, s *Selection) {
h, _ := OuterHtml(s)
if ix := strings.Index(h, "\n"); ix >= 0 {
h = h[:ix]
}
if len(h) > 100 {
h = h[:100]
}
fmt.Println(i, ">>> ", h)
})
}
func loadDoc(page string) *Document {
var f *os.File
var e error
+29 -10
View File
@@ -6,6 +6,11 @@ import (
"golang.org/x/net/html"
)
// used to determine if a set (map[*html.Node]bool) should be used
// instead of iterating over a slice. The set uses more memory and
// is slower than slice iteration for small N.
const minNodesForSet = 1000
var nodeNames = []string{
html.ErrorNode: "#error",
html.TextNode: "#text",
@@ -62,13 +67,6 @@ func OuterHtml(s *Selection) (string, error) {
return buf.String(), nil
}
func getChildren(n *html.Node) (result []*html.Node) {
for c := n.FirstChild; c != nil; c = c.NextSibling {
result = append(result, c)
}
return result
}
// Loop through all container nodes to search for the target node.
func sliceContains(container []*html.Node, contained *html.Node) bool {
for _, n := range container {
@@ -112,11 +110,32 @@ func indexInSlice(slice []*html.Node, node *html.Node) int {
// Appends the new nodes to the target slice, making sure no duplicate is added.
// There is no check to the original state of the target slice, so it may still
// contain duplicates. The target slice is returned because append() may create
// a new underlying array.
func appendWithoutDuplicates(target []*html.Node, nodes []*html.Node) []*html.Node {
// a new underlying array. If targetSet is nil, a local set is created with the
// target if len(target) + len(nodes) is greater than minNodesForSet.
func appendWithoutDuplicates(target []*html.Node, nodes []*html.Node, targetSet map[*html.Node]bool) []*html.Node {
// if there are not that many nodes, don't use the map, faster to just use nested loops
// (unless a non-nil targetSet is passed, in which case the caller knows better).
if targetSet == nil && len(target)+len(nodes) < minNodesForSet {
for _, n := range nodes {
if !isInSlice(target, n) {
target = append(target, n)
}
}
return target
}
// if a targetSet is passed, then assume it is reliable, otherwise create one
// and initialize it with the current target contents.
if targetSet == nil {
targetSet = make(map[*html.Node]bool, len(target))
for _, n := range target {
targetSet[n] = true
}
}
for _, n := range nodes {
if !isInSlice(target, n) {
if !targetSet[n] {
target = append(target, n)
targetSet[n] = true
}
}