Source File
selector.go
Belonging Package
github.com/andybalholm/cascadia
package cascadia
import (
)
type Sel interface {
Matcher
Specificity() Specificity
}
func ( Selector) ( *html.Node) []*html.Node {
return .matchAllInto(, nil)
}
func ( Selector) ( *html.Node, []*html.Node) []*html.Node {
if () {
= append(, )
}
for := .FirstChild; != nil; = .NextSibling {
= .(, )
}
return
}
func ( *html.Node, Matcher, []*html.Node) []*html.Node {
for := .FirstChild; != nil; = .NextSibling {
if .Match() {
= append(, )
}
= (, , )
}
return
}
func ( tagSelector) ( *html.Node) bool {
return .Type == html.ElementNode && .Data == .tag
}
func ( tagSelector) () Specificity {
return Specificity{0, 0, 1}
}
type classSelector struct {
class string
}
func ( classSelector) ( *html.Node) bool {
return matchAttribute(, "class", func( string) bool {
return matchInclude(.class, )
})
}
func ( classSelector) () Specificity {
return Specificity{0, 1, 0}
}
type idSelector struct {
id string
}
func ( idSelector) ( *html.Node) bool {
return matchAttribute(, "id", func( string) bool {
return == .id
})
}
func ( idSelector) () Specificity {
return Specificity{1, 0, 0}
}
type attrSelector struct {
key, val, operation string
regexp *regexp.Regexp
}
func ( attrSelector) ( *html.Node) bool {
switch .operation {
case "":
return matchAttribute(, .key, func(string) bool { return true })
case "=":
return matchAttribute(, .key, func( string) bool { return == .val })
case "!=":
return attributeNotEqualMatch(.key, .val, )
return matchAttribute(, .key, func( string) bool { return matchInclude(.val, ) })
case "|=":
return attributeDashMatch(.key, .val, )
case "^=":
return attributePrefixMatch(.key, .val, )
case "$=":
return attributeSuffixMatch(.key, .val, )
case "*=":
return attributeSubstringMatch(.key, .val, )
case "#=":
return attributeRegexMatch(.key, .regexp, )
default:
panic(fmt.Sprintf("unsuported operation : %s", .operation))
}
}
func ( string, *regexp.Regexp, *html.Node) bool {
return matchAttribute(, ,
func( string) bool {
return .MatchString()
})
}
func ( attrSelector) () Specificity {
return Specificity{0, 1, 0}
}
type relativePseudoClassSelector struct {
name string // one of "not", "has", "haschild"
match SelectorGroup
}
func ( relativePseudoClassSelector) ( *html.Node) bool {
if .Type != html.ElementNode {
return false
}
switch .name {
return hasDescendantMatch(, .match)
func ( *html.Node, Matcher) bool {
for := .FirstChild; != nil; = .NextSibling {
if .Match() {
return true
}
}
return false
}
func ( *html.Node, Matcher) bool {
for := .FirstChild; != nil; = .NextSibling {
if .Match() || (.Type == html.ElementNode && (, )) {
return true
}
}
return false
}
func ( relativePseudoClassSelector) () Specificity {
var Specificity
for , := range .match {
:= .Specificity()
if .Less() {
=
}
}
return
}
type containsPseudoClassSelector struct {
own bool
value string
}
func ( containsPseudoClassSelector) ( *html.Node) bool {
var string
= strings.ToLower(nodeOwnText())
= strings.ToLower(nodeText())
}
return strings.Contains(, .value)
}
func ( containsPseudoClassSelector) () Specificity {
return Specificity{0, 1, 0}
}
type regexpPseudoClassSelector struct {
own bool
regexp *regexp.Regexp
}
func ( regexpPseudoClassSelector) ( *html.Node) bool {
var string
= nodeOwnText()
= nodeText()
}
return .regexp.MatchString()
}
func ( *html.Node, *bytes.Buffer) {
switch .Type {
case html.TextNode:
.WriteString(.Data)
case html.ElementNode:
for := .FirstChild; != nil; = .NextSibling {
(, )
}
}
}
func ( *html.Node) string {
var bytes.Buffer
for := .FirstChild; != nil; = .NextSibling {
if .Type == html.TextNode {
.WriteString(.Data)
}
}
return .String()
}
func ( regexpPseudoClassSelector) () Specificity {
return Specificity{0, 1, 0}
}
type nthPseudoClassSelector struct {
a, b int
last, ofType bool
}
func ( nthPseudoClassSelector) ( *html.Node) bool {
if .a == 0 {
if .last {
return simpleNthLastChildMatch(.b, .ofType, )
} else {
return simpleNthChildMatch(.b, .ofType, )
}
}
return nthChildMatch(.a, .b, .last, .ofType, )
}
func (, int, , bool, *html.Node) bool {
if .Type != html.ElementNode {
return false
}
:= .Parent
if == nil {
return false
}
if .Type == html.DocumentNode {
return false
}
:= -1
:= 0
for := .FirstChild; != nil; = .NextSibling {
if (.Type != html.ElementNode) || ( && .Data != .Data) {
continue
}
++
if == {
=
if ! {
break
}
}
}
return false
}
if {
= - + 1
}
-=
if == 0 {
return == 0
}
return % == 0 && / >= 0
}
func ( int, bool, *html.Node) bool {
if .Type != html.ElementNode {
return false
}
:= .Parent
if == nil {
return false
}
if .Type == html.DocumentNode {
return false
}
:= 0
for := .FirstChild; != nil; = .NextSibling {
if .Type != html.ElementNode || ( && .Data != .Data) {
continue
}
++
if == {
return ==
}
if >= {
return false
}
}
return false
}
func ( int, bool, *html.Node) bool {
if .Type != html.ElementNode {
return false
}
:= .Parent
if == nil {
return false
}
if .Type == html.DocumentNode {
return false
}
:= 0
for := .LastChild; != nil; = .PrevSibling {
if .Type != html.ElementNode || ( && .Data != .Data) {
continue
}
++
if == {
return ==
}
if >= {
return false
}
}
return false
}
func ( nthPseudoClassSelector) () Specificity {
return Specificity{0, 1, 0}
}
type onlyChildPseudoClassSelector struct {
ofType bool
}
func ( onlyChildPseudoClassSelector) ( *html.Node) bool {
if .Type != html.ElementNode {
return false
}
:= .Parent
if == nil {
return false
}
if .Type == html.DocumentNode {
return false
}
:= 0
for := .FirstChild; != nil; = .NextSibling {
if (.Type != html.ElementNode) || (.ofType && .Data != .Data) {
continue
}
++
if > 1 {
return false
}
}
return == 1
}
func ( onlyChildPseudoClassSelector) () Specificity {
return Specificity{0, 1, 0}
}
type inputPseudoClassSelector struct{}
func ( inputPseudoClassSelector) ( *html.Node) bool {
return .Type == html.ElementNode && (.Data == "input" || .Data == "select" || .Data == "textarea" || .Data == "button")
}
func ( inputPseudoClassSelector) () Specificity {
return Specificity{0, 1, 0}
}
type emptyElementPseudoClassSelector struct{}
func ( emptyElementPseudoClassSelector) ( *html.Node) bool {
if .Type != html.ElementNode {
return false
}
for := .FirstChild; != nil; = .NextSibling {
switch .Type {
case html.ElementNode, html.TextNode:
return false
}
}
return true
}
func ( emptyElementPseudoClassSelector) () Specificity {
return Specificity{0, 1, 0}
}
type rootPseudoClassSelector struct{}
func ( rootPseudoClassSelector) ( *html.Node) bool {
if .Type != html.ElementNode {
return false
}
if .Parent == nil {
return false
}
return .Parent.Type == html.DocumentNode
}
func ( rootPseudoClassSelector) () Specificity {
return Specificity{0, 1, 0}
}
type compoundSelector struct {
selectors []Sel
}
func ( compoundSelector) ( *html.Node) bool {
if len(.selectors) == 0 {
return .Type == html.ElementNode
}
for , := range .selectors {
if !.Match() {
return false
}
}
return true
}
func ( compoundSelector) () Specificity {
var Specificity
for , := range .selectors {
= .Add(.Specificity())
}
return
}
type combinedSelector struct {
first Sel
combinator byte
second Sel
}
func ( combinedSelector) ( *html.Node) bool {
if .first == nil {
return false // maybe we should panic
}
switch .combinator {
case 0:
return .first.Match()
case ' ':
return descendantMatch(.first, .second, )
case '>':
return childMatch(.first, .second, )
case '+':
return siblingMatch(.first, .second, true, )
case '~':
return siblingMatch(.first, .second, false, )
default:
panic("unknown combinator")
}
}
for := .PrevSibling; != nil; = .PrevSibling {
if .Match() {
return true
}
}
return false
}
func ( combinedSelector) () Specificity {
:= .first.Specificity()
if .second != nil {
= .Add(.second.Specificity())
}
return
}
type SelectorGroup []Sel
![]() |
The pages are generated with Golds v0.3.2-preview. (GOOS=darwin GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |