mirror of
https://github.com/PuerkitoBio/goquery.git
synced 2024-04-21 12:31:36 +00:00
Compare commits
11
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f41c56001f | ||
|
|
8a11cc402f | ||
|
|
70a02e53e3 | ||
|
|
3798c63c0d | ||
|
|
705a0066a5 | ||
|
|
a48bafac4b | ||
|
|
af965a4d72 | ||
|
|
b3706f8903 | ||
|
|
7ebd145bd7 | ||
|
|
4a687a672f | ||
|
|
94c2530dd8 |
+27
@@ -1,3 +1,6 @@
|
||||
arch:
|
||||
- amd64
|
||||
- ppc64le
|
||||
language: go
|
||||
|
||||
go:
|
||||
@@ -15,3 +18,27 @@ go:
|
||||
- 1.13.x
|
||||
- tip
|
||||
|
||||
jobs:
|
||||
exclude:
|
||||
- arch: ppc64le
|
||||
go: 1.2.x
|
||||
- arch: ppc64le
|
||||
go: 1.3.x
|
||||
- arch: ppc64le
|
||||
go: 1.4.x
|
||||
- arch: ppc64le
|
||||
go: 1.5.x
|
||||
- arch: ppc64le
|
||||
go: 1.6.x
|
||||
- arch: ppc64le
|
||||
go: 1.7.x
|
||||
- arch: ppc64le
|
||||
go: 1.8.x
|
||||
- arch: ppc64le
|
||||
go: 1.9.x
|
||||
- arch: ppc64le
|
||||
go: 1.10.x
|
||||
- arch: ppc64le
|
||||
go: 1.11.x
|
||||
- arch: ppc64le
|
||||
go: 1.12.x
|
||||
|
||||
@@ -37,6 +37,8 @@ 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.**
|
||||
|
||||
* **2021-01-11 (v1.6.1)** : Fix panic when calling `{Prepend,Append,Set}Html` on a `Selection` that contains non-Element nodes.
|
||||
* **2020-10-08 (v1.6.0)** : Parse html in context of the container node for all functions that deal with html strings (`AfterHtml`, `AppendHtml`, etc.). Thanks to [@thiemok][thiemok] and [@davidjwilkins][djw] for their work on this.
|
||||
* **2020-02-04 (v1.5.1)** : Update module dependencies.
|
||||
* **2018-11-15 (v1.5.0)** : Go module support (thanks @Zaba505).
|
||||
* **2018-06-07 (v1.4.1)** : Add `NewDocumentFromReader` examples.
|
||||
@@ -143,9 +145,10 @@ func main() {
|
||||
- [gnulnx/goperf](https://github.com/gnulnx/goperf), a website performance test tool that also fetches static assets.
|
||||
- [MontFerret/ferret](https://github.com/MontFerret/ferret), declarative web scraping.
|
||||
- [tacusci/berrycms](https://github.com/tacusci/berrycms), a modern simple to use CMS with easy to write plugins
|
||||
- [Dataflow kit](https://github.com/slotix/dataflowkit), Web Scraping framework for Gophers.
|
||||
- [Dataflow kit](https://github.com/slotix/dataflowkit), Web Scraping framework for Gophers.
|
||||
- [Geziyor](https://github.com/geziyor/geziyor), a fast web crawling & scraping framework for Go. Supports JS rendering.
|
||||
- [Pagser](https://github.com/foolin/pagser), a simple, easy, extensible, configurable HTML parser to struct based on goquery and struct tags.
|
||||
- [stitcherd](https://github.com/vhodges/stitcherd), A server for doing server side includes using css selectors and DOM updates.
|
||||
|
||||
## Support
|
||||
|
||||
@@ -182,3 +185,5 @@ The [BSD 3-Clause license][bsd], the same as the [Go language][golic]. Cascadia'
|
||||
[thatguystone]: https://github.com/thatguystone
|
||||
[piotr]: https://github.com/piotrkowalczuk
|
||||
[goq]: https://github.com/andrewstuart/goq
|
||||
[thiemok]: https://github.com/thiemok
|
||||
[djw]: https://github.com/davidjwilkins
|
||||
|
||||
+16
-10
@@ -41,9 +41,10 @@ func (s *Selection) AfterSelection(sel *Selection) *Selection {
|
||||
// This follows the same rules as Selection.Append.
|
||||
func (s *Selection) AfterHtml(htmlStr string) *Selection {
|
||||
return s.eachNodeHtml(htmlStr, true, func(node *html.Node, nodes []*html.Node) {
|
||||
nextSibling := node.NextSibling
|
||||
for _, n := range nodes {
|
||||
if node.Parent != nil {
|
||||
node.Parent.InsertBefore(n, node.NextSibling)
|
||||
node.Parent.InsertBefore(n, nextSibling)
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -202,8 +203,9 @@ func (s *Selection) PrependSelection(sel *Selection) *Selection {
|
||||
// PrependHtml parses the html and prepends it to the set of matched elements.
|
||||
func (s *Selection) PrependHtml(htmlStr string) *Selection {
|
||||
return s.eachNodeHtml(htmlStr, false, func(node *html.Node, nodes []*html.Node) {
|
||||
firstChild := node.FirstChild
|
||||
for _, n := range nodes {
|
||||
node.InsertBefore(n, node.FirstChild)
|
||||
node.InsertBefore(n, firstChild)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -283,9 +285,10 @@ func (s *Selection) ReplaceWithSelection(sel *Selection) *Selection {
|
||||
// This follows the same rules as Selection.Append.
|
||||
func (s *Selection) ReplaceWithHtml(htmlStr string) *Selection {
|
||||
s.eachNodeHtml(htmlStr, true, func(node *html.Node, nodes []*html.Node) {
|
||||
nextSibling := node.NextSibling
|
||||
for _, n := range nodes {
|
||||
if node.Parent != nil {
|
||||
node.Parent.InsertBefore(n, node.NextSibling)
|
||||
node.Parent.InsertBefore(n, nextSibling)
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -310,7 +313,7 @@ func (s *Selection) SetHtml(htmlStr string) *Selection {
|
||||
context.RemoveChild(c)
|
||||
}
|
||||
}
|
||||
return s.eachNodeHtml(htmlStr, true, func(node *html.Node, nodes []*html.Node) {
|
||||
return s.eachNodeHtml(htmlStr, false, func(node *html.Node, nodes []*html.Node) {
|
||||
for _, n := range nodes {
|
||||
node.AppendChild(n)
|
||||
}
|
||||
@@ -371,7 +374,7 @@ func (s *Selection) WrapSelection(sel *Selection) *Selection {
|
||||
//
|
||||
// It returns the original set of elements.
|
||||
func (s *Selection) WrapHtml(htmlStr string) *Selection {
|
||||
nodesMap := make(map[html.NodeType][]*html.Node)
|
||||
nodesMap := make(map[string][]*html.Node)
|
||||
for _, context := range s.Nodes {
|
||||
var parent *html.Node
|
||||
if context.Parent != nil {
|
||||
@@ -379,10 +382,10 @@ func (s *Selection) WrapHtml(htmlStr string) *Selection {
|
||||
} else {
|
||||
parent = &html.Node{Type: html.ElementNode}
|
||||
}
|
||||
nodes, found := nodesMap[parent.Type]
|
||||
nodes, found := nodesMap[nodeName(parent)]
|
||||
if !found {
|
||||
nodes = parseHtmlWithContext(htmlStr, parent)
|
||||
nodesMap[parent.Type] = nodes
|
||||
nodesMap[nodeName(parent)] = nodes
|
||||
}
|
||||
newSingleSelection(context, s.document).wrapAllNodes(cloneNodes(nodes)...)
|
||||
}
|
||||
@@ -519,12 +522,12 @@ func (s *Selection) WrapInnerSelection(sel *Selection) *Selection {
|
||||
//
|
||||
// It returns the original set of elements.
|
||||
func (s *Selection) WrapInnerHtml(htmlStr string) *Selection {
|
||||
nodesMap := make(map[html.NodeType][]*html.Node)
|
||||
nodesMap := make(map[string][]*html.Node)
|
||||
for _, context := range s.Nodes {
|
||||
nodes, found := nodesMap[context.Type]
|
||||
nodes, found := nodesMap[nodeName(context)]
|
||||
if !found {
|
||||
nodes = parseHtmlWithContext(htmlStr, context)
|
||||
nodesMap[context.Type] = nodes
|
||||
nodesMap[nodeName(context)] = nodes
|
||||
}
|
||||
newSingleSelection(context, s.document).wrapInnerNodes(cloneNodes(nodes)...)
|
||||
}
|
||||
@@ -658,6 +661,9 @@ func (s *Selection) eachNodeHtml(htmlStr string, isParent bool, mergeFn func(n *
|
||||
if isParent {
|
||||
context = n.Parent
|
||||
} else {
|
||||
if n.Type != html.ElementNode {
|
||||
continue
|
||||
}
|
||||
context = n
|
||||
}
|
||||
if context != nil {
|
||||
|
||||
+60
-10
@@ -1,6 +1,7 @@
|
||||
package goquery
|
||||
|
||||
import (
|
||||
"log"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -70,8 +71,9 @@ func TestAfterHtmlContext(t *testing.T) {
|
||||
</table>
|
||||
</body>
|
||||
</html>`)
|
||||
doc.Find("table tr td").AfterHtml("<td>Test</td>")
|
||||
assertLength(t, doc.Find("table tr td").Nodes, 4)
|
||||
doc.Find("table tr td").AfterHtml("<td class='c1'>Test</td><td class='c2'>Again</td>")
|
||||
assertLength(t, doc.Find("table tr td").Nodes, 6)
|
||||
assertClass(t, doc.Find("table tr td").Last(), "c2")
|
||||
printSel(t, doc.Selection)
|
||||
}
|
||||
|
||||
@@ -146,10 +148,10 @@ func TestAppendHtmlContext(t *testing.T) {
|
||||
</table>
|
||||
</body>
|
||||
</html>`)
|
||||
doc.Find("table tr").AppendHtml("<td class='new-node'>new node</td>")
|
||||
doc.Find("table tr").AppendHtml("<td class='c1'>new1</td><td class='c2'>new2</td>")
|
||||
|
||||
assertLength(t, doc.Find("table td").Nodes, 4)
|
||||
assertClass(t, doc.Find("table td").Last(), "new-node")
|
||||
assertLength(t, doc.Find("table td").Nodes, 6)
|
||||
assertClass(t, doc.Find("table td").Last(), "c2")
|
||||
printSel(t, doc.Selection)
|
||||
}
|
||||
|
||||
@@ -205,10 +207,10 @@ func TestBeforeHtmlContext(t *testing.T) {
|
||||
</table>
|
||||
</body>
|
||||
</html>`)
|
||||
doc.Find("table tr td:first-child").BeforeHtml("<td class='new-node'>new node</td>")
|
||||
doc.Find("table tr td:first-child").BeforeHtml("<td class='c1'>new1</td><td class='c2'>new2</td>")
|
||||
|
||||
assertLength(t, doc.Find("table td").Nodes, 4)
|
||||
assertClass(t, doc.Find("table td").First(), "new-node")
|
||||
assertLength(t, doc.Find("table td").Nodes, 6)
|
||||
assertClass(t, doc.Find("table td").First(), "c1")
|
||||
printSel(t, doc.Selection)
|
||||
}
|
||||
|
||||
@@ -374,10 +376,11 @@ func TestReplaceWithHtmlContext(t *testing.T) {
|
||||
</table>
|
||||
</body>
|
||||
</html>`)
|
||||
doc.Find("table th").ReplaceWithHtml("<td>Test</td><td>Replace</td>")
|
||||
doc.Find("table th").ReplaceWithHtml("<td class='c1'>Test</td><td class='c2'>Replace</td>")
|
||||
|
||||
assertLength(t, doc.Find("table th").Nodes, 0)
|
||||
assertLength(t, doc.Find("table tr td").Nodes, 4)
|
||||
assertClass(t, doc.Find("table tr td").First(), "c1")
|
||||
printSel(t, doc.Selection)
|
||||
}
|
||||
|
||||
@@ -434,7 +437,7 @@ func TestSetHtmlContext(t *testing.T) {
|
||||
|
||||
assertLength(t, doc.Find("table th").Nodes, 0)
|
||||
assertLength(t, doc.Find("table td").Nodes, 4)
|
||||
assertLength(t, doc.Find("table t2").Nodes, 2)
|
||||
assertLength(t, doc.Find("table tr").Nodes, 2)
|
||||
printSel(t, doc.Selection)
|
||||
}
|
||||
|
||||
@@ -687,3 +690,50 @@ func TestParsingRespectsVaryingContext(t *testing.T) {
|
||||
oBothA)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHtmlWithNonElementNode(t *testing.T) {
|
||||
const data = `
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
This is <span>some</span><b>text</b>.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
`
|
||||
|
||||
cases := map[string]func(*Selection, string) *Selection{
|
||||
"AfterHtml": (*Selection).AfterHtml,
|
||||
"AppendHtml": (*Selection).AppendHtml,
|
||||
"BeforeHtml": (*Selection).BeforeHtml,
|
||||
"PrependHtml": (*Selection).PrependHtml,
|
||||
"ReplaceWithHtml": (*Selection).ReplaceWithHtml,
|
||||
"SetHtml": (*Selection).SetHtml,
|
||||
}
|
||||
for nm, fn := range cases {
|
||||
// this test is only to make sure that the HTML parsing/manipulation
|
||||
// methods do not raise panics when executed over Selections that contain
|
||||
// non-Element nodes.
|
||||
t.Run(nm, func(t *testing.T) {
|
||||
doc := loadString(t, data)
|
||||
sel := doc.Find("p").Contents()
|
||||
func() {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
fn(sel, "<div></div>")
|
||||
}()
|
||||
|
||||
// print the resulting document in verbose mode
|
||||
h, err := OuterHtml(doc.Selection)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
t.Log(h)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user