mirror of
https://github.com/PuerkitoBio/goquery.git
synced 2026-09-20 11:18:40 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d3e3ce5663 | ||
|
|
9841a36e8f | ||
|
|
469d4eab16 | ||
|
|
a03654e5c2 | ||
|
|
faf16ca2df | ||
|
|
4c1c718c62 | ||
|
|
62bfb673c9 | ||
|
|
e3142812ec | ||
|
|
0961921b55 | ||
|
|
695fbfd142 | ||
|
|
91702e55ec | ||
|
|
37bfcfb2ff | ||
|
|
2213b25d2b | ||
|
|
26759cf6df | ||
|
|
01cff33869 | ||
|
|
250e47114e | ||
|
|
9ec8fd3fbf | ||
|
|
32ce829020 | ||
|
|
8f996d0795 | ||
|
|
9c6a69cd4d | ||
|
|
80f14c7111 | ||
|
|
58dcec12a0 | ||
|
|
aadb1cdadc | ||
|
|
9cd3cf0815 | ||
|
|
fa93633a0f | ||
|
|
858507ff1b | ||
|
|
5c48549c05 | ||
|
|
c2d1a0902f | ||
|
|
3951e60495 |
@@ -8,16 +8,16 @@ jobs:
|
||||
test:
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.23.x, 1.24.x]
|
||||
go-version: [1.24.x, 1.25.x]
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ Syntax-wise, it is as close as possible to jQuery, with the same function names
|
||||
|
||||
Required Go version:
|
||||
|
||||
* Starting with version `v1.11.0` of goquery, Go 1.24+ is required due to its dependencies.
|
||||
* Starting with version `v1.10.0` of goquery, Go 1.23+ is required due to the use of function-based iterators.
|
||||
* For `v1.9.0` of goquery, Go 1.18+ is required due to the use of generics.
|
||||
* For previous goquery versions, a Go version of 1.1+ was required because of the `net/html` dependency.
|
||||
@@ -46,6 +47,8 @@ Ongoing goquery development is tested on the latest 2 versions of Go.
|
||||
|
||||
**Note that goquery's API is now stable, and will not break.**
|
||||
|
||||
* **2025-11-16 (v1.11.0)** : Update `go.mod` dependencies, add go1.25 to the test matrix, **goquery now requires Go version 1.24+**.
|
||||
* **2025-04-11 (v1.10.3)** : Update `go.mod` dependencies, small optimization (thanks [@myxzlpltk](https://github.com/myxzlpltk)).
|
||||
* **2025-02-13 (v1.10.2)** : Update `go.mod` dependencies, add go1.24 to the test matrix.
|
||||
* **2024-12-26 (v1.10.1)** : Update `go.mod` dependencies.
|
||||
* **2024-09-06 (v1.10.0)** : Add `EachIter` which provides an iterator that can be used in `for..range` loops on the `*Selection` object. **goquery now requires Go version 1.23+** (thanks [@amikai](https://github.com/amikai)).
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
package goquery
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func BenchmarkMetalReviewExample(b *testing.B) {
|
||||
var n int
|
||||
var buf bytes.Buffer
|
||||
var builder strings.Builder
|
||||
|
||||
b.StopTimer()
|
||||
doc := loadDoc("metalreview.html")
|
||||
@@ -27,12 +27,12 @@ func BenchmarkMetalReviewExample(b *testing.B) {
|
||||
if score, e = strconv.ParseFloat(s.Find(".score").Text(), 64); e != nil {
|
||||
// Not a valid float, ignore score
|
||||
if n <= 4 {
|
||||
buf.WriteString(fmt.Sprintf("Review %d: %s - %s.\n", i, band, title))
|
||||
builder.WriteString(fmt.Sprintf("Review %d: %s - %s.\n", i, band, title))
|
||||
}
|
||||
} else {
|
||||
// Print all, including score
|
||||
if n <= 4 {
|
||||
buf.WriteString(fmt.Sprintf("Review %d: %s - %s (%2.1f).\n", i, band, title, score))
|
||||
builder.WriteString(fmt.Sprintf("Review %d: %s - %s (%2.1f).\n", i, band, title, score))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -2,7 +2,9 @@ module github.com/PuerkitoBio/goquery
|
||||
|
||||
require (
|
||||
github.com/andybalholm/cascadia v1.3.3
|
||||
golang.org/x/net v0.35.0
|
||||
golang.org/x/net v0.47.0
|
||||
)
|
||||
|
||||
go 1.23
|
||||
go 1.24.0
|
||||
|
||||
toolchain go1.24.1
|
||||
|
||||
@@ -22,8 +22,8 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
|
||||
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
|
||||
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
||||
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
||||
+10
-10
@@ -1,7 +1,6 @@
|
||||
package goquery
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
@@ -60,14 +59,14 @@ func (s *Selection) SetAttr(attrName, val string) *Selection {
|
||||
// Text gets the combined text contents of each element in the set of matched
|
||||
// elements, including their descendants.
|
||||
func (s *Selection) Text() string {
|
||||
var buf bytes.Buffer
|
||||
var builder strings.Builder
|
||||
|
||||
// Slightly optimized vs calling Each: no single selection object created
|
||||
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)
|
||||
builder.WriteString(n.Data)
|
||||
}
|
||||
if n.FirstChild != nil {
|
||||
for c := n.FirstChild; c != nil; c = c.NextSibling {
|
||||
@@ -79,7 +78,7 @@ func (s *Selection) Text() string {
|
||||
f(n)
|
||||
}
|
||||
|
||||
return buf.String()
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
// Size is an alias for Length.
|
||||
@@ -97,16 +96,16 @@ func (s *Selection) Length() int {
|
||||
func (s *Selection) Html() (ret string, e error) {
|
||||
// Since there is no .innerHtml, the HTML content must be re-created from
|
||||
// the nodes using html.Render.
|
||||
var buf bytes.Buffer
|
||||
var builder strings.Builder
|
||||
|
||||
if len(s.Nodes) > 0 {
|
||||
for c := s.Nodes[0].FirstChild; c != nil; c = c.NextSibling {
|
||||
e = html.Render(&buf, c)
|
||||
e = html.Render(&builder, c)
|
||||
if e != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
ret = buf.String()
|
||||
ret = builder.String()
|
||||
}
|
||||
|
||||
return
|
||||
@@ -168,7 +167,7 @@ func (s *Selection) RemoveClass(class ...string) *Selection {
|
||||
} else {
|
||||
classes, attr := getClassesAndAttr(n, true)
|
||||
for _, rcl := range rclasses {
|
||||
classes = strings.Replace(classes, " "+rcl+" ", " ", -1)
|
||||
classes = strings.ReplaceAll(classes, " "+rcl+" ", " ")
|
||||
}
|
||||
|
||||
setClasses(n, attr, classes)
|
||||
@@ -192,8 +191,9 @@ func (s *Selection) ToggleClass(class ...string) *Selection {
|
||||
for _, n := range s.Nodes {
|
||||
classes, attr := getClassesAndAttr(n, true)
|
||||
for _, tcl := range tcls {
|
||||
if strings.Contains(classes, " "+tcl+" ") {
|
||||
classes = strings.Replace(classes, " "+tcl+" ", " ", -1)
|
||||
spaceAroundTcl := " " + tcl + " "
|
||||
if strings.Contains(classes, spaceAroundTcl) {
|
||||
classes = strings.ReplaceAll(classes, spaceAroundTcl, " ")
|
||||
} else {
|
||||
classes += tcl + " "
|
||||
}
|
||||
|
||||
+10
-11
@@ -1,8 +1,8 @@
|
||||
package goquery
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/html"
|
||||
)
|
||||
@@ -26,13 +26,12 @@ var nodeNames = []string{
|
||||
// Go's net/html package defines the following node types, listed with
|
||||
// the corresponding returned value from this function:
|
||||
//
|
||||
// ErrorNode : #error
|
||||
// TextNode : #text
|
||||
// DocumentNode : #document
|
||||
// ElementNode : the element's tag name
|
||||
// CommentNode : #comment
|
||||
// DoctypeNode : the name of the document type
|
||||
//
|
||||
// ErrorNode : #error
|
||||
// TextNode : #text
|
||||
// DocumentNode : #document
|
||||
// ElementNode : the element's tag name
|
||||
// CommentNode : #comment
|
||||
// DoctypeNode : the name of the document type
|
||||
func NodeName(s *Selection) string {
|
||||
if s.Length() == 0 {
|
||||
return ""
|
||||
@@ -77,11 +76,11 @@ func Render(w io.Writer, s *Selection) error {
|
||||
// because this is not a jQuery method (in javascript-land, this is
|
||||
// a property provided by the DOM).
|
||||
func OuterHtml(s *Selection) (string, error) {
|
||||
var buf bytes.Buffer
|
||||
if err := Render(&buf, s); err != nil {
|
||||
var builder strings.Builder
|
||||
if err := Render(&builder, s); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return buf.String(), nil
|
||||
return builder.String(), nil
|
||||
}
|
||||
|
||||
// Loop through all container nodes to search for the target node.
|
||||
|
||||
Reference in New Issue
Block a user