Compare commits

..
Author SHA1 Message Date
Martin Angers f41c56001f Cut new release 2021-01-11 18:44:58 -05:00
Martin Angers 8a11cc402f Ignore non-element nodes when inserting html in a selection 2021-01-11 18:43:18 -05:00
Martin AngersandGitHub 70a02e53e3 Merge pull request #364 from santosh653/master
AddingPowerSupport_CI/Testing
2020-12-08 08:09:26 -05:00
santosh653andGitHub 3798c63c0d Update .travis.yml
Excluding unsupported versions for Power., ie go <=1.12.x
2020-12-07 23:31:38 -05:00
santosh653andGitHub 705a0066a5 Update .travis.yml
Adding power support & updating the go versions to >=1.13 as lower versions are not supported.,
2020-12-07 06:53:59 -05:00
Martin AngersandGitHub a48bafac4b Merge pull request #362 from vhodges/master
Update README.md, closes #361
2020-11-30 18:58:28 -05:00
Vince HodgesandGitHub af965a4d72 Update README.md 2020-11-30 15:54:55 -08:00
Martin Angers b3706f8903 update readme to prepare for new release 2020-10-08 09:16:43 -04:00
Martin AngersandGitHub 7ebd145bd7 Merge pull request #348 from thiemok/context
Send context to parseHtml. Closes #178 .
2020-10-08 09:10:18 -04:00
Martin Angers 4a687a672f add test cases to check html insertion order 2020-10-08 09:02:13 -04:00
thiemok 94c2530dd8 fix(manipulation): fix node insertion and caching issues
Node caching was still using the node type instead of the node name in a
few places. Updated those to also use the node name as the cache key.

ReplaceWithHtml and PrependHtml inserted parsed nodes in the wrong
order. Kept track of the correct parent to fix this.

Use correct parent flag for SetHtml
2020-10-07 20:04:45 +02:00
4 changed files with 109 additions and 21 deletions
+27
View File
@@ -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
+6 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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)
})
}
}