mirror of
https://github.com/PuerkitoBio/goquery.git
synced 2024-04-21 12:31:36 +00:00
Compare commits
13
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7f4291566c | ||
|
|
f0d75731e0 | ||
|
|
77cbaef46a | ||
|
|
2441483128 | ||
|
|
2ab590df05 | ||
|
|
9cc531274b | ||
|
|
2cd8b4e49a | ||
|
|
aeecb06b1e | ||
|
|
2e29ea41f0 | ||
|
|
5cc721859e | ||
|
|
4126223a86 | ||
|
|
81e6517758 | ||
|
|
bb16855614 |
@@ -0,0 +1 @@
|
||||
testdata/* linguist-vendored
|
||||
@@ -4,4 +4,7 @@ go:
|
||||
- 1.1
|
||||
- 1.2
|
||||
- 1.3
|
||||
- 1.4
|
||||
- 1.5
|
||||
- 1.6
|
||||
- tip
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2012-2014, Martin Angers & Contributors
|
||||
Copyright (c) 2012-2016, Martin Angers & Contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
# goquery - a little like that j-thing, only in Go
|
||||
|
||||
[](http://travis-ci.org/PuerkitoBio/goquery)
|
||||
|
||||
[](http://godoc.org/github.com/PuerkitoBio/goquery)
|
||||
# goquery - a little like that j-thing, only in Go [](http://travis-ci.org/PuerkitoBio/goquery) [](http://godoc.org/github.com/PuerkitoBio/goquery)
|
||||
|
||||
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.
|
||||
|
||||
@@ -30,6 +26,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.**
|
||||
|
||||
* **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].
|
||||
* **2015-02-04** : Add more manipulation functions - Prepend* - thanks again to [Andrew Stone][thatguystone].
|
||||
@@ -61,13 +59,18 @@ Utility functions that are not in jQuery but are useful in Go are implemented as
|
||||
|
||||
The complete [godoc reference documentation can be found here][doc].
|
||||
|
||||
Please note that Cascadia's selectors do not necessarily match all supported selectors of jQuery (Sizzle). See the [cascadia project][cascadia] for details.
|
||||
Please note that Cascadia's selectors do not necessarily match all supported selectors of jQuery (Sizzle). See the [cascadia project][cascadia] for details. Invalid selector strings compile to a `Matcher` that fails to match any node. Behaviour of the various functions that take a selector string as argument follows from that fact, e.g. (where `~` is an invalid selector string):
|
||||
|
||||
* `Find("~")` returns an empty selection because the selector string doesn't match anything.
|
||||
* `Add("~")` returns a new selection that holds the same nodes as the original selection, because it didn't add any node (selector string didn't match anything).
|
||||
* `ParentsFiltered("~")` returns an empty selection because the selector string doesn't match anything.
|
||||
* `ParentsUntil("~")` returns all parents of the selection because the selector string didn't match any element to stop before the top element.
|
||||
|
||||
## Examples
|
||||
|
||||
See some tips and tricks in the [wiki][].
|
||||
|
||||
Taken (and adapted as if executed from outside the goquery package) from example_test.go:
|
||||
Adapted from example_test.go:
|
||||
|
||||
```Go
|
||||
package main
|
||||
@@ -85,8 +88,10 @@ func ExampleScrape() {
|
||||
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)
|
||||
})
|
||||
|
||||
@@ -14,6 +14,11 @@ func TestFirstEmpty(t *testing.T) {
|
||||
assertLength(t, sel.Nodes, 0)
|
||||
}
|
||||
|
||||
func TestFirstInvalid(t *testing.T) {
|
||||
sel := Doc().Find("").First()
|
||||
assertLength(t, sel.Nodes, 0)
|
||||
}
|
||||
|
||||
func TestFirstRollback(t *testing.T) {
|
||||
sel := Doc().Find(".pvk-content")
|
||||
sel2 := sel.First().End()
|
||||
@@ -36,6 +41,11 @@ func TestLastEmpty(t *testing.T) {
|
||||
assertLength(t, sel.Nodes, 0)
|
||||
}
|
||||
|
||||
func TestLastInvalid(t *testing.T) {
|
||||
sel := Doc().Find("").Last()
|
||||
assertLength(t, sel.Nodes, 0)
|
||||
}
|
||||
|
||||
func TestLastRollback(t *testing.T) {
|
||||
sel := Doc().Find(".pvk-content")
|
||||
sel2 := sel.Last().End()
|
||||
@@ -63,6 +73,11 @@ func TestEqEmpty(t *testing.T) {
|
||||
assertLength(t, sel.Nodes, 0)
|
||||
}
|
||||
|
||||
func TestEqInvalid(t *testing.T) {
|
||||
sel := Doc().Find("").Eq(0)
|
||||
assertLength(t, sel.Nodes, 0)
|
||||
}
|
||||
|
||||
func TestEqInvalidPositive(t *testing.T) {
|
||||
sel := Doc().Find(".pvk-content").Eq(3)
|
||||
assertLength(t, sel.Nodes, 0)
|
||||
@@ -85,6 +100,16 @@ func TestSlice(t *testing.T) {
|
||||
assertLength(t, sel.Nodes, 2)
|
||||
}
|
||||
|
||||
func TestSliceEmpty(t *testing.T) {
|
||||
defer assertPanic(t)
|
||||
Doc().Find("x").Slice(0, 2)
|
||||
}
|
||||
|
||||
func TestSliceInvalid(t *testing.T) {
|
||||
defer assertPanic(t)
|
||||
Doc().Find("").Slice(0, 2)
|
||||
}
|
||||
|
||||
func TestSliceOutOfBounds(t *testing.T) {
|
||||
defer assertPanic(t)
|
||||
Doc().Find(".pvk-content").Slice(2, 12)
|
||||
@@ -157,6 +182,13 @@ func TestIndexSelector(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestIndexSelectorInvalid(t *testing.T) {
|
||||
sel := Doc().Find(".hero-unit")
|
||||
if i := sel.IndexSelector(""); i != -1 {
|
||||
t.Errorf("Expected index of -1, got %v.", i)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIndexOfNode(t *testing.T) {
|
||||
sel := Doc().Find("div.pvk-gutter")
|
||||
if i := sel.IndexOfNode(sel.Nodes[1]); i != 1 {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2012-2014, Martin Angers & Contributors
|
||||
// Copyright (c) 2012-2016, Martin Angers & Contributors
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
|
||||
+8
-10
@@ -1,26 +1,24 @@
|
||||
package goquery
|
||||
package goquery_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
// In real use, this import would be required (not in this example, since it
|
||||
// is part of the goquery package)
|
||||
//"github.com/PuerkitoBio/goquery"
|
||||
"github.com/PuerkitoBio/goquery"
|
||||
)
|
||||
|
||||
// This example scrapes the reviews shown on the home page of metalsucks.net.
|
||||
func ExampleScrape_MetalSucks() {
|
||||
// Load the HTML document (in real use, the type would be *goquery.Document)
|
||||
doc, err := NewDocument("http://metalsucks.net")
|
||||
func Example() {
|
||||
// Load the HTML document
|
||||
doc, err := goquery.NewDocument("http://metalsucks.net")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Find the review items (the type of the Selection would be *goquery.Selection)
|
||||
doc.Find(".reviews-wrap article .review-rhs").Each(func(i int, s *Selection) {
|
||||
// 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("h3").Text()
|
||||
band := s.Find("a").Text()
|
||||
title := s.Find("i").Text()
|
||||
fmt.Printf("Review %d: %s - %s\n", i, band, title)
|
||||
})
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
package goquery
|
||||
|
||||
import (
|
||||
"github.com/andybalholm/cascadia"
|
||||
"golang.org/x/net/html"
|
||||
)
|
||||
import "golang.org/x/net/html"
|
||||
|
||||
// Add adds the selector string's matching nodes to those in the current
|
||||
// selection and returns a new Selection object.
|
||||
// The selector string is run in the context of the document of the current
|
||||
// Selection object.
|
||||
func (s *Selection) Add(selector string) *Selection {
|
||||
return s.AddNodes(findWithMatcher([]*html.Node{s.document.rootNode}, cascadia.MustCompile(selector))...)
|
||||
return s.AddNodes(findWithMatcher([]*html.Node{s.document.rootNode}, compileMatcher(selector))...)
|
||||
}
|
||||
|
||||
// AddMatcher adds the matcher's matching nodes to those in the current
|
||||
|
||||
@@ -9,6 +9,16 @@ func TestAdd(t *testing.T) {
|
||||
assertLength(t, sel.Nodes, 19)
|
||||
}
|
||||
|
||||
func TestAddInvalid(t *testing.T) {
|
||||
sel1 := Doc().Find("div.row-fluid")
|
||||
sel2 := sel1.Add("")
|
||||
assertLength(t, sel1.Nodes, 9)
|
||||
assertLength(t, sel2.Nodes, 9)
|
||||
if sel1 == sel2 {
|
||||
t.Errorf("selections should not be the same")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddRollback(t *testing.T) {
|
||||
sel := Doc().Find(".pvk-content")
|
||||
sel2 := sel.Add("a").End()
|
||||
|
||||
@@ -1,19 +1,16 @@
|
||||
package goquery
|
||||
|
||||
import (
|
||||
"github.com/andybalholm/cascadia"
|
||||
"golang.org/x/net/html"
|
||||
)
|
||||
import "golang.org/x/net/html"
|
||||
|
||||
// Filter reduces the set of matched elements to those that match the selector string.
|
||||
// It returns a new Selection object for this subset of matching elements.
|
||||
func (s *Selection) Filter(selector string) *Selection {
|
||||
return s.FilterMatcher(cascadia.MustCompile(selector))
|
||||
return s.FilterMatcher(compileMatcher(selector))
|
||||
}
|
||||
|
||||
// FilterMatcher reduces the set of matched elements to those that match
|
||||
// the given matcher.
|
||||
// It returns a new Selection object for this subset of matching elements.
|
||||
// the given matcher. It returns a new Selection object for this subset
|
||||
// of matching elements.
|
||||
func (s *Selection) FilterMatcher(m Matcher) *Selection {
|
||||
return pushStack(s, winnow(s, m, true))
|
||||
}
|
||||
@@ -21,7 +18,7 @@ func (s *Selection) FilterMatcher(m Matcher) *Selection {
|
||||
// Not removes elements from the Selection that match the selector string.
|
||||
// It returns a new Selection object with the matching elements removed.
|
||||
func (s *Selection) Not(selector string) *Selection {
|
||||
return s.NotMatcher(cascadia.MustCompile(selector))
|
||||
return s.NotMatcher(compileMatcher(selector))
|
||||
}
|
||||
|
||||
// NotMatcher removes elements from the Selection that match the given matcher.
|
||||
|
||||
@@ -14,6 +14,11 @@ func TestFilterNone(t *testing.T) {
|
||||
assertLength(t, sel.Nodes, 0)
|
||||
}
|
||||
|
||||
func TestFilterInvalid(t *testing.T) {
|
||||
sel := Doc().Find(".span12").Filter("")
|
||||
assertLength(t, sel.Nodes, 0)
|
||||
}
|
||||
|
||||
func TestFilterRollback(t *testing.T) {
|
||||
sel := Doc().Find(".pvk-content")
|
||||
sel2 := sel.Filter(".alert").End()
|
||||
@@ -74,6 +79,11 @@ func TestNot(t *testing.T) {
|
||||
assertLength(t, sel.Nodes, 1)
|
||||
}
|
||||
|
||||
func TestNotInvalid(t *testing.T) {
|
||||
sel := Doc().Find(".span12").Not("")
|
||||
assertLength(t, sel.Nodes, 2)
|
||||
}
|
||||
|
||||
func TestNotRollback(t *testing.T) {
|
||||
sel := Doc().Find(".span12")
|
||||
sel2 := sel.Not(".alert").End()
|
||||
@@ -145,6 +155,11 @@ func TestHas(t *testing.T) {
|
||||
// Has() returns the high-level .container-fluid div, and the one that is the immediate parent of center-content
|
||||
}
|
||||
|
||||
func TestHasInvalid(t *testing.T) {
|
||||
sel := Doc().Find(".container-fluid").Has("")
|
||||
assertLength(t, sel.Nodes, 0)
|
||||
}
|
||||
|
||||
func TestHasRollback(t *testing.T) {
|
||||
sel := Doc().Find(".container-fluid")
|
||||
sel2 := sel.Has(".center-content").End()
|
||||
|
||||
+8
-2
@@ -1,7 +1,10 @@
|
||||
package goquery
|
||||
|
||||
// Each iterates over a Selection object, executing a function for each
|
||||
// matched element. It returns the current Selection object.
|
||||
// matched element. It returns the current Selection object. The function
|
||||
// f is called for each element in the selection with the index of the
|
||||
// element in that selection starting at 0, and a *Selection that contains
|
||||
// only that element.
|
||||
func (s *Selection) Each(f func(int, *Selection)) *Selection {
|
||||
for i, n := range s.Nodes {
|
||||
f(i, newSingleSelection(n, s.document))
|
||||
@@ -23,7 +26,10 @@ func (s *Selection) EachWithBreak(f func(int, *Selection) bool) *Selection {
|
||||
}
|
||||
|
||||
// Map passes each element in the current matched set through a function,
|
||||
// producing a slice of string holding the returned values.
|
||||
// producing a slice of string holding the returned values. The function
|
||||
// f is called for each element in the selection with the index of the
|
||||
// element in that selection starting at 0, and a *Selection that contains
|
||||
// only that element.
|
||||
func (s *Selection) Map(f func(int, *Selection) string) (result []string) {
|
||||
for i, n := range s.Nodes {
|
||||
result = append(result, f(i, newSingleSelection(n, s.document)))
|
||||
|
||||
+9
-10
@@ -3,7 +3,6 @@ package goquery
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/andybalholm/cascadia"
|
||||
"golang.org/x/net/html"
|
||||
)
|
||||
|
||||
@@ -15,7 +14,7 @@ import (
|
||||
//
|
||||
// This follows the same rules as Selection.Append.
|
||||
func (s *Selection) After(selector string) *Selection {
|
||||
return s.AfterMatcher(cascadia.MustCompile(selector))
|
||||
return s.AfterMatcher(compileMatcher(selector))
|
||||
}
|
||||
|
||||
// AfterMatcher applies the matcher from the root document and inserts the matched elements
|
||||
@@ -66,7 +65,7 @@ func (s *Selection) AfterNodes(ns ...*html.Node) *Selection {
|
||||
// appended to all target locations except the last one, which will be moved
|
||||
// as noted in (2).
|
||||
func (s *Selection) Append(selector string) *Selection {
|
||||
return s.AppendMatcher(cascadia.MustCompile(selector))
|
||||
return s.AppendMatcher(compileMatcher(selector))
|
||||
}
|
||||
|
||||
// AppendMatcher appends the elements specified by the matcher to the end of each element
|
||||
@@ -103,7 +102,7 @@ func (s *Selection) AppendNodes(ns ...*html.Node) *Selection {
|
||||
//
|
||||
// This follows the same rules as Selection.Append.
|
||||
func (s *Selection) Before(selector string) *Selection {
|
||||
return s.BeforeMatcher(cascadia.MustCompile(selector))
|
||||
return s.BeforeMatcher(compileMatcher(selector))
|
||||
}
|
||||
|
||||
// BeforeMatcher inserts the matched elements before each element in the set of matched elements.
|
||||
@@ -165,7 +164,7 @@ func (s *Selection) Empty() *Selection {
|
||||
// Prepend prepends the elements specified by the selector to each element in
|
||||
// the set of matched elements, following the same rules as Append.
|
||||
func (s *Selection) Prepend(selector string) *Selection {
|
||||
return s.PrependMatcher(cascadia.MustCompile(selector))
|
||||
return s.PrependMatcher(compileMatcher(selector))
|
||||
}
|
||||
|
||||
// PrependMatcher prepends the elements specified by the matcher to each
|
||||
@@ -216,7 +215,7 @@ func (s *Selection) Remove() *Selection {
|
||||
// RemoveFiltered removes the set of matched elements by selector.
|
||||
// It returns the Selection of removed nodes.
|
||||
func (s *Selection) RemoveFiltered(selector string) *Selection {
|
||||
return s.RemoveMatcher(cascadia.MustCompile(selector))
|
||||
return s.RemoveMatcher(compileMatcher(selector))
|
||||
}
|
||||
|
||||
// RemoveMatcher removes the set of matched elements.
|
||||
@@ -231,7 +230,7 @@ func (s *Selection) RemoveMatcher(m Matcher) *Selection {
|
||||
//
|
||||
// This follows the same rules as Selection.Append.
|
||||
func (s *Selection) ReplaceWith(selector string) *Selection {
|
||||
return s.ReplaceWithMatcher(cascadia.MustCompile(selector))
|
||||
return s.ReplaceWithMatcher(compileMatcher(selector))
|
||||
}
|
||||
|
||||
// ReplaceWithMatcher replaces each element in the set of matched elements with
|
||||
@@ -293,7 +292,7 @@ func (s *Selection) Unwrap() *Selection {
|
||||
//
|
||||
// It returns the original set of elements.
|
||||
func (s *Selection) Wrap(selector string) *Selection {
|
||||
return s.WrapMatcher(cascadia.MustCompile(selector))
|
||||
return s.WrapMatcher(compileMatcher(selector))
|
||||
}
|
||||
|
||||
// WrapMatcher wraps each element in the set of matched elements inside the
|
||||
@@ -345,7 +344,7 @@ func (s *Selection) wrapNodes(ns ...*html.Node) *Selection {
|
||||
//
|
||||
// It returns the original set of elements.
|
||||
func (s *Selection) WrapAll(selector string) *Selection {
|
||||
return s.WrapAllMatcher(cascadia.MustCompile(selector))
|
||||
return s.WrapAllMatcher(compileMatcher(selector))
|
||||
}
|
||||
|
||||
// WrapAllMatcher wraps a single HTML structure, matched by the given Matcher,
|
||||
@@ -415,7 +414,7 @@ func (s *Selection) WrapAllNode(n *html.Node) *Selection {
|
||||
//
|
||||
// It returns the original set of elements.
|
||||
func (s *Selection) WrapInner(selector string) *Selection {
|
||||
return s.WrapInnerMatcher(cascadia.MustCompile(selector))
|
||||
return s.WrapInnerMatcher(compileMatcher(selector))
|
||||
}
|
||||
|
||||
// WrapInnerMatcher wraps an HTML structure, matched by the given selector,
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
package goquery
|
||||
|
||||
import (
|
||||
"github.com/andybalholm/cascadia"
|
||||
"golang.org/x/net/html"
|
||||
)
|
||||
import "golang.org/x/net/html"
|
||||
|
||||
// Is checks the current matched set of elements against a selector and
|
||||
// returns true if at least one of these elements matches.
|
||||
func (s *Selection) Is(selector string) bool {
|
||||
if len(s.Nodes) > 0 {
|
||||
return s.IsMatcher(cascadia.MustCompile(selector))
|
||||
return s.IsMatcher(compileMatcher(selector))
|
||||
}
|
||||
|
||||
return false
|
||||
|
||||
@@ -11,6 +11,13 @@ func TestIs(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsInvalid(t *testing.T) {
|
||||
sel := Doc().Find(".footer p:nth-child(1)")
|
||||
if sel.Is("") {
|
||||
t.Error("Is should not succeed with invalid selector string")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsPositional(t *testing.T) {
|
||||
sel := Doc().Find(".footer p:nth-child(2)")
|
||||
if !sel.Is("p:nth-child(2)") {
|
||||
|
||||
+23
-26
@@ -1,9 +1,6 @@
|
||||
package goquery
|
||||
|
||||
import (
|
||||
"github.com/andybalholm/cascadia"
|
||||
"golang.org/x/net/html"
|
||||
)
|
||||
import "golang.org/x/net/html"
|
||||
|
||||
type siblingType int
|
||||
|
||||
@@ -24,7 +21,7 @@ const (
|
||||
// elements, filtered by a selector. It returns a new Selection object
|
||||
// containing these matched elements.
|
||||
func (s *Selection) Find(selector string) *Selection {
|
||||
return pushStack(s, findWithMatcher(s.Nodes, cascadia.MustCompile(selector)))
|
||||
return pushStack(s, findWithMatcher(s.Nodes, compileMatcher(selector)))
|
||||
}
|
||||
|
||||
// FindMatcher gets the descendants of each element in the current set of matched
|
||||
@@ -93,7 +90,7 @@ func (s *Selection) Children() *Selection {
|
||||
// filtered by the specified selector. It returns a new
|
||||
// Selection object containing these elements.
|
||||
func (s *Selection) ChildrenFiltered(selector string) *Selection {
|
||||
return filterAndPush(s, getChildrenNodes(s.Nodes, siblingAll), cascadia.MustCompile(selector))
|
||||
return filterAndPush(s, getChildrenNodes(s.Nodes, siblingAll), compileMatcher(selector))
|
||||
}
|
||||
|
||||
// ChildrenMatcher gets the child elements of each element in the Selection,
|
||||
@@ -112,7 +109,7 @@ func (s *Selection) Parent() *Selection {
|
||||
// ParentFiltered gets the parent of each element in the Selection filtered by a
|
||||
// selector. It returns a new Selection object containing the matched elements.
|
||||
func (s *Selection) ParentFiltered(selector string) *Selection {
|
||||
return filterAndPush(s, getParentNodes(s.Nodes), cascadia.MustCompile(selector))
|
||||
return filterAndPush(s, getParentNodes(s.Nodes), compileMatcher(selector))
|
||||
}
|
||||
|
||||
// ParentMatcher gets the parent of each element in the Selection filtered by a
|
||||
@@ -124,7 +121,7 @@ func (s *Selection) ParentMatcher(m Matcher) *Selection {
|
||||
// Closest gets the first element that matches the selector by testing the
|
||||
// element itself and traversing up through its ancestors in the DOM tree.
|
||||
func (s *Selection) Closest(selector string) *Selection {
|
||||
cs := cascadia.MustCompile(selector)
|
||||
cs := compileMatcher(selector)
|
||||
return s.ClosestMatcher(cs)
|
||||
}
|
||||
|
||||
@@ -177,7 +174,7 @@ func (s *Selection) Parents() *Selection {
|
||||
// ParentsFiltered gets the ancestors of each element in the current
|
||||
// Selection. It returns a new Selection object with the matched elements.
|
||||
func (s *Selection) ParentsFiltered(selector string) *Selection {
|
||||
return filterAndPush(s, getParentsNodes(s.Nodes, nil, nil), cascadia.MustCompile(selector))
|
||||
return filterAndPush(s, getParentsNodes(s.Nodes, nil, nil), compileMatcher(selector))
|
||||
}
|
||||
|
||||
// ParentsMatcher gets the ancestors of each element in the current
|
||||
@@ -190,7 +187,7 @@ func (s *Selection) ParentsMatcher(m Matcher) *Selection {
|
||||
// not including the element matched by the selector. It returns a new Selection
|
||||
// object containing the matched elements.
|
||||
func (s *Selection) ParentsUntil(selector string) *Selection {
|
||||
return pushStack(s, getParentsNodes(s.Nodes, cascadia.MustCompile(selector), nil))
|
||||
return pushStack(s, getParentsNodes(s.Nodes, compileMatcher(selector), nil))
|
||||
}
|
||||
|
||||
// ParentsUntilMatcher gets the ancestors of each element in the Selection, up to but
|
||||
@@ -221,7 +218,7 @@ func (s *Selection) ParentsUntilNodes(nodes ...*html.Node) *Selection {
|
||||
// results based on a selector string. It returns a new Selection
|
||||
// object containing the matched elements.
|
||||
func (s *Selection) ParentsFilteredUntil(filterSelector, untilSelector string) *Selection {
|
||||
return filterAndPush(s, getParentsNodes(s.Nodes, cascadia.MustCompile(untilSelector), nil), cascadia.MustCompile(filterSelector))
|
||||
return filterAndPush(s, getParentsNodes(s.Nodes, compileMatcher(untilSelector), nil), compileMatcher(filterSelector))
|
||||
}
|
||||
|
||||
// ParentsFilteredUntilMatcher is like ParentsUntilMatcher, with the option to filter the
|
||||
@@ -234,7 +231,7 @@ func (s *Selection) ParentsFilteredUntilMatcher(filter, until Matcher) *Selectio
|
||||
// option to filter the results based on a selector string. It returns a new
|
||||
// Selection object containing the matched elements.
|
||||
func (s *Selection) ParentsFilteredUntilSelection(filterSelector string, sel *Selection) *Selection {
|
||||
return s.ParentsMatcherUntilSelection(cascadia.MustCompile(filterSelector), sel)
|
||||
return s.ParentsMatcherUntilSelection(compileMatcher(filterSelector), sel)
|
||||
}
|
||||
|
||||
// ParentsMatcherUntilSelection is like ParentsUntilSelection, with the
|
||||
@@ -251,7 +248,7 @@ func (s *Selection) ParentsMatcherUntilSelection(filter Matcher, sel *Selection)
|
||||
// option to filter the results based on a selector string. It returns a new
|
||||
// Selection object containing the matched elements.
|
||||
func (s *Selection) ParentsFilteredUntilNodes(filterSelector string, nodes ...*html.Node) *Selection {
|
||||
return filterAndPush(s, getParentsNodes(s.Nodes, nil, nodes), cascadia.MustCompile(filterSelector))
|
||||
return filterAndPush(s, getParentsNodes(s.Nodes, nil, nodes), compileMatcher(filterSelector))
|
||||
}
|
||||
|
||||
// ParentsMatcherUntilNodes is like ParentsUntilNodes, with the
|
||||
@@ -271,7 +268,7 @@ func (s *Selection) Siblings() *Selection {
|
||||
// filtered by a selector. It returns a new Selection object containing the
|
||||
// matched elements.
|
||||
func (s *Selection) SiblingsFiltered(selector string) *Selection {
|
||||
return filterAndPush(s, getSiblingNodes(s.Nodes, siblingAll, nil, nil), cascadia.MustCompile(selector))
|
||||
return filterAndPush(s, getSiblingNodes(s.Nodes, siblingAll, nil, nil), compileMatcher(selector))
|
||||
}
|
||||
|
||||
// SiblingsMatcher gets the siblings of each element in the Selection
|
||||
@@ -291,7 +288,7 @@ func (s *Selection) Next() *Selection {
|
||||
// Selection filtered by a selector. It returns a new Selection object
|
||||
// containing the matched elements.
|
||||
func (s *Selection) NextFiltered(selector string) *Selection {
|
||||
return filterAndPush(s, getSiblingNodes(s.Nodes, siblingNext, nil, nil), cascadia.MustCompile(selector))
|
||||
return filterAndPush(s, getSiblingNodes(s.Nodes, siblingNext, nil, nil), compileMatcher(selector))
|
||||
}
|
||||
|
||||
// NextMatcher gets the immediately following sibling of each element in the
|
||||
@@ -311,7 +308,7 @@ func (s *Selection) NextAll() *Selection {
|
||||
// Selection filtered by a selector. It returns a new Selection object
|
||||
// containing the matched elements.
|
||||
func (s *Selection) NextAllFiltered(selector string) *Selection {
|
||||
return filterAndPush(s, getSiblingNodes(s.Nodes, siblingNextAll, nil, nil), cascadia.MustCompile(selector))
|
||||
return filterAndPush(s, getSiblingNodes(s.Nodes, siblingNextAll, nil, nil), compileMatcher(selector))
|
||||
}
|
||||
|
||||
// NextAllMatcher gets all the following siblings of each element in the
|
||||
@@ -331,7 +328,7 @@ func (s *Selection) Prev() *Selection {
|
||||
// Selection filtered by a selector. It returns a new Selection object
|
||||
// containing the matched elements.
|
||||
func (s *Selection) PrevFiltered(selector string) *Selection {
|
||||
return filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrev, nil, nil), cascadia.MustCompile(selector))
|
||||
return filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrev, nil, nil), compileMatcher(selector))
|
||||
}
|
||||
|
||||
// PrevMatcher gets the immediately preceding sibling of each element in the
|
||||
@@ -351,7 +348,7 @@ func (s *Selection) PrevAll() *Selection {
|
||||
// Selection filtered by a selector. It returns a new Selection object
|
||||
// containing the matched elements.
|
||||
func (s *Selection) PrevAllFiltered(selector string) *Selection {
|
||||
return filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrevAll, nil, nil), cascadia.MustCompile(selector))
|
||||
return filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrevAll, nil, nil), compileMatcher(selector))
|
||||
}
|
||||
|
||||
// PrevAllMatcher gets all the preceding siblings of each element in the
|
||||
@@ -366,7 +363,7 @@ func (s *Selection) PrevAllMatcher(m Matcher) *Selection {
|
||||
// object containing the matched elements.
|
||||
func (s *Selection) NextUntil(selector string) *Selection {
|
||||
return pushStack(s, getSiblingNodes(s.Nodes, siblingNextUntil,
|
||||
cascadia.MustCompile(selector), nil))
|
||||
compileMatcher(selector), nil))
|
||||
}
|
||||
|
||||
// NextUntilMatcher gets all following siblings of each element up to but not
|
||||
@@ -400,7 +397,7 @@ func (s *Selection) NextUntilNodes(nodes ...*html.Node) *Selection {
|
||||
// object containing the matched elements.
|
||||
func (s *Selection) PrevUntil(selector string) *Selection {
|
||||
return pushStack(s, getSiblingNodes(s.Nodes, siblingPrevUntil,
|
||||
cascadia.MustCompile(selector), nil))
|
||||
compileMatcher(selector), nil))
|
||||
}
|
||||
|
||||
// PrevUntilMatcher gets all preceding siblings of each element up to but not
|
||||
@@ -434,7 +431,7 @@ func (s *Selection) PrevUntilNodes(nodes ...*html.Node) *Selection {
|
||||
// It returns a new Selection object containing the matched elements.
|
||||
func (s *Selection) NextFilteredUntil(filterSelector, untilSelector string) *Selection {
|
||||
return filterAndPush(s, getSiblingNodes(s.Nodes, siblingNextUntil,
|
||||
cascadia.MustCompile(untilSelector), nil), cascadia.MustCompile(filterSelector))
|
||||
compileMatcher(untilSelector), nil), compileMatcher(filterSelector))
|
||||
}
|
||||
|
||||
// NextFilteredUntilMatcher is like NextUntilMatcher, with the option to filter
|
||||
@@ -449,7 +446,7 @@ func (s *Selection) NextFilteredUntilMatcher(filter, until Matcher) *Selection {
|
||||
// option to filter the results based on a selector string. It returns a new
|
||||
// Selection object containing the matched elements.
|
||||
func (s *Selection) NextFilteredUntilSelection(filterSelector string, sel *Selection) *Selection {
|
||||
return s.NextMatcherUntilSelection(cascadia.MustCompile(filterSelector), sel)
|
||||
return s.NextMatcherUntilSelection(compileMatcher(filterSelector), sel)
|
||||
}
|
||||
|
||||
// NextMatcherUntilSelection is like NextUntilSelection, with the
|
||||
@@ -467,7 +464,7 @@ func (s *Selection) NextMatcherUntilSelection(filter Matcher, sel *Selection) *S
|
||||
// Selection object containing the matched elements.
|
||||
func (s *Selection) NextFilteredUntilNodes(filterSelector string, nodes ...*html.Node) *Selection {
|
||||
return filterAndPush(s, getSiblingNodes(s.Nodes, siblingNextUntil,
|
||||
nil, nodes), cascadia.MustCompile(filterSelector))
|
||||
nil, nodes), compileMatcher(filterSelector))
|
||||
}
|
||||
|
||||
// NextMatcherUntilNodes is like NextUntilNodes, with the
|
||||
@@ -483,7 +480,7 @@ func (s *Selection) NextMatcherUntilNodes(filter Matcher, nodes ...*html.Node) *
|
||||
// It returns a new Selection object containing the matched elements.
|
||||
func (s *Selection) PrevFilteredUntil(filterSelector, untilSelector string) *Selection {
|
||||
return filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrevUntil,
|
||||
cascadia.MustCompile(untilSelector), nil), cascadia.MustCompile(filterSelector))
|
||||
compileMatcher(untilSelector), nil), compileMatcher(filterSelector))
|
||||
}
|
||||
|
||||
// PrevFilteredUntilMatcher is like PrevUntilMatcher, with the option to filter
|
||||
@@ -498,7 +495,7 @@ func (s *Selection) PrevFilteredUntilMatcher(filter, until Matcher) *Selection {
|
||||
// option to filter the results based on a selector string. It returns a new
|
||||
// Selection object containing the matched elements.
|
||||
func (s *Selection) PrevFilteredUntilSelection(filterSelector string, sel *Selection) *Selection {
|
||||
return s.PrevMatcherUntilSelection(cascadia.MustCompile(filterSelector), sel)
|
||||
return s.PrevMatcherUntilSelection(compileMatcher(filterSelector), sel)
|
||||
}
|
||||
|
||||
// PrevMatcherUntilSelection is like PrevUntilSelection, with the
|
||||
@@ -516,7 +513,7 @@ func (s *Selection) PrevMatcherUntilSelection(filter Matcher, sel *Selection) *S
|
||||
// Selection object containing the matched elements.
|
||||
func (s *Selection) PrevFilteredUntilNodes(filterSelector string, nodes ...*html.Node) *Selection {
|
||||
return filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrevUntil,
|
||||
nil, nodes), cascadia.MustCompile(filterSelector))
|
||||
nil, nodes), compileMatcher(filterSelector))
|
||||
}
|
||||
|
||||
// PrevMatcherUntilNodes is like PrevUntilNodes, with the
|
||||
|
||||
+89
-3
@@ -21,9 +21,9 @@ func TestFindNotSelf(t *testing.T) {
|
||||
assertLength(t, sel.Nodes, 0)
|
||||
}
|
||||
|
||||
func TestFindInvalidSelector(t *testing.T) {
|
||||
defer assertPanic(t)
|
||||
Doc().Find(":+ ^")
|
||||
func TestFindInvalid(t *testing.T) {
|
||||
sel := Doc().Find(":+ ^")
|
||||
assertLength(t, sel.Nodes, 0)
|
||||
}
|
||||
|
||||
func TestChainedFind(t *testing.T) {
|
||||
@@ -31,6 +31,11 @@ func TestChainedFind(t *testing.T) {
|
||||
assertLength(t, sel.Nodes, 4)
|
||||
}
|
||||
|
||||
func TestChainedFindInvalid(t *testing.T) {
|
||||
sel := Doc().Find("div.hero-unit").Find("")
|
||||
assertLength(t, sel.Nodes, 0)
|
||||
}
|
||||
|
||||
func TestChildren(t *testing.T) {
|
||||
sel := Doc().Find(".pvk-content").Children()
|
||||
assertLength(t, sel.Nodes, 5)
|
||||
@@ -58,6 +63,11 @@ func TestChildrenFiltered(t *testing.T) {
|
||||
assertLength(t, sel.Nodes, 1)
|
||||
}
|
||||
|
||||
func TestChildrenFilteredInvalid(t *testing.T) {
|
||||
sel := Doc().Find(".pvk-content").ChildrenFiltered("")
|
||||
assertLength(t, sel.Nodes, 0)
|
||||
}
|
||||
|
||||
func TestChildrenFilteredRollback(t *testing.T) {
|
||||
sel := Doc().Find(".pvk-content")
|
||||
sel2 := sel.ChildrenFiltered(".hero-unit").End()
|
||||
@@ -69,6 +79,11 @@ func TestContentsFiltered(t *testing.T) {
|
||||
assertLength(t, sel.Nodes, 1)
|
||||
}
|
||||
|
||||
func TestContentsFilteredInvalid(t *testing.T) {
|
||||
sel := Doc().Find(".pvk-content").ContentsFiltered("~")
|
||||
assertLength(t, sel.Nodes, 0)
|
||||
}
|
||||
|
||||
func TestContentsFilteredRollback(t *testing.T) {
|
||||
sel := Doc().Find(".pvk-content")
|
||||
sel2 := sel.ContentsFiltered(".hero-unit").End()
|
||||
@@ -102,6 +117,11 @@ func TestParentFiltered(t *testing.T) {
|
||||
assertClass(t, sel, "hero-unit")
|
||||
}
|
||||
|
||||
func TestParentFilteredInvalid(t *testing.T) {
|
||||
sel := Doc().Find(".container-fluid").ParentFiltered("")
|
||||
assertLength(t, sel.Nodes, 0)
|
||||
}
|
||||
|
||||
func TestParentFilteredRollback(t *testing.T) {
|
||||
sel := Doc().Find(".container-fluid")
|
||||
sel2 := sel.ParentFiltered(".hero-unit").End()
|
||||
@@ -130,6 +150,11 @@ func TestParentsFiltered(t *testing.T) {
|
||||
assertLength(t, sel.Nodes, 1)
|
||||
}
|
||||
|
||||
func TestParentsFilteredInvalid(t *testing.T) {
|
||||
sel := Doc().Find(".container-fluid").ParentsFiltered("")
|
||||
assertLength(t, sel.Nodes, 0)
|
||||
}
|
||||
|
||||
func TestParentsFilteredRollback(t *testing.T) {
|
||||
sel := Doc().Find(".container-fluid")
|
||||
sel2 := sel.ParentsFiltered("body").End()
|
||||
@@ -141,6 +166,11 @@ func TestParentsUntil(t *testing.T) {
|
||||
assertLength(t, sel.Nodes, 6)
|
||||
}
|
||||
|
||||
func TestParentsUntilInvalid(t *testing.T) {
|
||||
sel := Doc().Find(".container-fluid").ParentsUntil("")
|
||||
assertLength(t, sel.Nodes, 8)
|
||||
}
|
||||
|
||||
func TestParentsUntilRollback(t *testing.T) {
|
||||
sel := Doc().Find(".container-fluid")
|
||||
sel2 := sel.ParentsUntil("body").End()
|
||||
@@ -180,6 +210,11 @@ func TestParentsFilteredUntil(t *testing.T) {
|
||||
assertLength(t, sel.Nodes, 2)
|
||||
}
|
||||
|
||||
func TestParentsFilteredUntilInvalid(t *testing.T) {
|
||||
sel := Doc().Find(".container-fluid").ParentsFilteredUntil("", "")
|
||||
assertLength(t, sel.Nodes, 0)
|
||||
}
|
||||
|
||||
func TestParentsFilteredUntilRollback(t *testing.T) {
|
||||
sel := Doc().Find(".container-fluid")
|
||||
sel2 := sel.ParentsFilteredUntil(".pvk-content", "body").End()
|
||||
@@ -240,6 +275,11 @@ func TestSiblingsFiltered(t *testing.T) {
|
||||
assertLength(t, sel.Nodes, 3)
|
||||
}
|
||||
|
||||
func TestSiblingsFilteredInvalid(t *testing.T) {
|
||||
sel := Doc().Find(".pvk-gutter").SiblingsFiltered("")
|
||||
assertLength(t, sel.Nodes, 0)
|
||||
}
|
||||
|
||||
func TestSiblingsFilteredRollback(t *testing.T) {
|
||||
sel := Doc().Find(".pvk-gutter")
|
||||
sel2 := sel.SiblingsFiltered(".pvk-content").End()
|
||||
@@ -272,6 +312,11 @@ func TestNextFiltered(t *testing.T) {
|
||||
assertLength(t, sel.Nodes, 2)
|
||||
}
|
||||
|
||||
func TestNextFilteredInvalid(t *testing.T) {
|
||||
sel := Doc().Find(".container-fluid").NextFiltered("")
|
||||
assertLength(t, sel.Nodes, 0)
|
||||
}
|
||||
|
||||
func TestNextFilteredRollback(t *testing.T) {
|
||||
sel := Doc().Find(".container-fluid")
|
||||
sel2 := sel.NextFiltered("div").End()
|
||||
@@ -310,6 +355,11 @@ func TestPrevFiltered(t *testing.T) {
|
||||
assertLength(t, sel.Nodes, 5)
|
||||
}
|
||||
|
||||
func TestPrevFilteredInvalid(t *testing.T) {
|
||||
sel := Doc().Find(".row-fluid").PrevFiltered("")
|
||||
assertLength(t, sel.Nodes, 0)
|
||||
}
|
||||
|
||||
func TestPrevFilteredRollback(t *testing.T) {
|
||||
sel := Doc().Find(".row-fluid")
|
||||
sel2 := sel.PrevFiltered(".row-fluid").End()
|
||||
@@ -342,6 +392,11 @@ func TestNextAllFiltered(t *testing.T) {
|
||||
assertLength(t, sel.Nodes, 2)
|
||||
}
|
||||
|
||||
func TestNextAllFilteredInvalid(t *testing.T) {
|
||||
sel := Doc().Find("#cf2 .row-fluid").NextAllFiltered("")
|
||||
assertLength(t, sel.Nodes, 0)
|
||||
}
|
||||
|
||||
func TestNextAllFilteredRollback(t *testing.T) {
|
||||
sel := Doc().Find("#cf2 .row-fluid")
|
||||
sel2 := sel.NextAllFiltered("[ng-cloak]").End()
|
||||
@@ -380,6 +435,11 @@ func TestPrevAllFiltered(t *testing.T) {
|
||||
assertLength(t, sel.Nodes, 3)
|
||||
}
|
||||
|
||||
func TestPrevAllFilteredInvalid(t *testing.T) {
|
||||
sel := Doc().Find(".pvk-gutter").PrevAllFiltered("")
|
||||
assertLength(t, sel.Nodes, 0)
|
||||
}
|
||||
|
||||
func TestPrevAllFilteredRollback(t *testing.T) {
|
||||
sel := Doc().Find(".pvk-gutter")
|
||||
sel2 := sel.PrevAllFiltered(".pvk-content").End()
|
||||
@@ -392,6 +452,11 @@ func TestNextUntil(t *testing.T) {
|
||||
assertSelectionIs(t, sel, "h4")
|
||||
}
|
||||
|
||||
func TestNextUntilInvalid(t *testing.T) {
|
||||
sel := Doc().Find(".alert a").NextUntil("")
|
||||
assertLength(t, sel.Nodes, 2)
|
||||
}
|
||||
|
||||
func TestNextUntil2(t *testing.T) {
|
||||
sel := Doc().Find("#cf2-1").NextUntil("[ng-cloak]")
|
||||
assertLength(t, sel.Nodes, 1)
|
||||
@@ -446,6 +511,11 @@ func TestPrevUntil(t *testing.T) {
|
||||
assertSelectionIs(t, sel, "h4")
|
||||
}
|
||||
|
||||
func TestPrevUntilInvalid(t *testing.T) {
|
||||
sel := Doc().Find(".alert p").PrevUntil("")
|
||||
assertLength(t, sel.Nodes, 2)
|
||||
}
|
||||
|
||||
func TestPrevUntil2(t *testing.T) {
|
||||
sel := Doc().Find("[ng-cloak]").PrevUntil(":not([ng-cloak])")
|
||||
assertLength(t, sel.Nodes, 1)
|
||||
@@ -500,6 +570,11 @@ func TestNextFilteredUntil(t *testing.T) {
|
||||
assertSelectionIs(t, sel, "#n3", "#n5", "#nf3", "#nf5")
|
||||
}
|
||||
|
||||
func TestNextFilteredUntilInvalid(t *testing.T) {
|
||||
sel := Doc2().Find(".two").NextFilteredUntil("", "")
|
||||
assertLength(t, sel.Nodes, 0)
|
||||
}
|
||||
|
||||
func TestNextFilteredUntilRollback(t *testing.T) {
|
||||
sel := Doc2().Find(".two")
|
||||
sel2 := sel.NextFilteredUntil(".even", ".six").End()
|
||||
@@ -542,6 +617,11 @@ func TestPrevFilteredUntil(t *testing.T) {
|
||||
assertSelectionIs(t, sel, "#n4", "#n2", "#nf4", "#nf2")
|
||||
}
|
||||
|
||||
func TestPrevFilteredUntilInvalid(t *testing.T) {
|
||||
sel := Doc2().Find(".five").PrevFilteredUntil("", "")
|
||||
assertLength(t, sel.Nodes, 0)
|
||||
}
|
||||
|
||||
func TestPrevFilteredUntilRollback(t *testing.T) {
|
||||
sel := Doc2().Find(".four")
|
||||
sel2 := sel.PrevFilteredUntil(".odd", ".one").End()
|
||||
@@ -598,6 +678,12 @@ func TestClosestNone(t *testing.T) {
|
||||
assertLength(t, sel2.Nodes, 0)
|
||||
}
|
||||
|
||||
func TestClosestInvalid(t *testing.T) {
|
||||
sel := Doc().Find("h4")
|
||||
sel2 := sel.Closest("")
|
||||
assertLength(t, sel2.Nodes, 0)
|
||||
}
|
||||
|
||||
func TestClosestMany(t *testing.T) {
|
||||
sel := Doc().Find(".container-fluid")
|
||||
sel2 := sel.Closest(".pvk-content")
|
||||
|
||||
@@ -6,6 +6,8 @@ import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/andybalholm/cascadia"
|
||||
|
||||
"golang.org/x/net/html"
|
||||
)
|
||||
|
||||
@@ -113,3 +115,21 @@ type Matcher interface {
|
||||
MatchAll(*html.Node) []*html.Node
|
||||
Filter([]*html.Node) []*html.Node
|
||||
}
|
||||
|
||||
// compileMatcher compiles the selector string s and returns
|
||||
// the corresponding Matcher. If s is an invalid selector string,
|
||||
// it returns a Matcher that fails all matches.
|
||||
func compileMatcher(s string) Matcher {
|
||||
cs, err := cascadia.Compile(s)
|
||||
if err != nil {
|
||||
return invalidMatcher{}
|
||||
}
|
||||
return cs
|
||||
}
|
||||
|
||||
// invalidMatcher is a Matcher that always fails to match.
|
||||
type invalidMatcher struct{}
|
||||
|
||||
func (invalidMatcher) Match(n *html.Node) bool { return false }
|
||||
func (invalidMatcher) MatchAll(n *html.Node) []*html.Node { return nil }
|
||||
func (invalidMatcher) Filter(ns []*html.Node) []*html.Node { return nil }
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/net/html"
|
||||
@@ -107,6 +108,19 @@ 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
|
||||
@@ -190,3 +204,15 @@ func TestNewDocumentFromResponseNil(t *testing.T) {
|
||||
t.Error("Expected error, got none")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIssue103(t *testing.T) {
|
||||
d, err := NewDocumentFromReader(strings.NewReader("<html><title>Scientists Stored These Images in DNA—Then Flawlessly Retrieved Them</title></html>"))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
text := d.Find("title").Text()
|
||||
for i, r := range text {
|
||||
t.Logf("%d: %d - %q\n", i, r, string(r))
|
||||
}
|
||||
t.Log(text)
|
||||
}
|
||||
|
||||
+6
-6
@@ -20,12 +20,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 {
|
||||
|
||||
+1
-1
@@ -77,7 +77,7 @@ func TestNodeNameMultiSel(t *testing.T) {
|
||||
sort.Strings(in)
|
||||
sort.Strings(out)
|
||||
if !reflect.DeepEqual(in, out) {
|
||||
t.Error("want %v, got %v")
|
||||
t.Errorf("want %v, got %v", in, out)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user