You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

selector.go 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833
  1. package cascadia
  2. import (
  3. "bytes"
  4. "fmt"
  5. "regexp"
  6. "strings"
  7. "golang.org/x/net/html"
  8. )
  9. // Matcher is the interface for basic selector functionality.
  10. // Match returns whether a selector matches n.
  11. type Matcher interface {
  12. Match(n *html.Node) bool
  13. }
  14. // Sel is the interface for all the functionality provided by selectors.
  15. // It is currently the same as Matcher, but other methods may be added in the
  16. // future.
  17. type Sel interface {
  18. Matcher
  19. Specificity() Specificity
  20. }
  21. // Parse parses a selector.
  22. func Parse(sel string) (Sel, error) {
  23. p := &parser{s: sel}
  24. compiled, err := p.parseSelector()
  25. if err != nil {
  26. return nil, err
  27. }
  28. if p.i < len(sel) {
  29. return nil, fmt.Errorf("parsing %q: %d bytes left over", sel, len(sel)-p.i)
  30. }
  31. return compiled, nil
  32. }
  33. // ParseGroup parses a selector, or a group of selectors separated by commas.
  34. func ParseGroup(sel string) (SelectorGroup, error) {
  35. p := &parser{s: sel}
  36. compiled, err := p.parseSelectorGroup()
  37. if err != nil {
  38. return nil, err
  39. }
  40. if p.i < len(sel) {
  41. return nil, fmt.Errorf("parsing %q: %d bytes left over", sel, len(sel)-p.i)
  42. }
  43. return compiled, nil
  44. }
  45. // A Selector is a function which tells whether a node matches or not.
  46. //
  47. // This type is maintained for compatibility; I recommend using the newer and
  48. // more idiomatic interfaces Sel and Matcher.
  49. type Selector func(*html.Node) bool
  50. // Compile parses a selector and returns, if successful, a Selector object
  51. // that can be used to match against html.Node objects.
  52. func Compile(sel string) (Selector, error) {
  53. compiled, err := ParseGroup(sel)
  54. if err != nil {
  55. return nil, err
  56. }
  57. return Selector(compiled.Match), nil
  58. }
  59. // MustCompile is like Compile, but panics instead of returning an error.
  60. func MustCompile(sel string) Selector {
  61. compiled, err := Compile(sel)
  62. if err != nil {
  63. panic(err)
  64. }
  65. return compiled
  66. }
  67. // MatchAll returns a slice of the nodes that match the selector,
  68. // from n and its children.
  69. func (s Selector) MatchAll(n *html.Node) []*html.Node {
  70. return s.matchAllInto(n, nil)
  71. }
  72. func (s Selector) matchAllInto(n *html.Node, storage []*html.Node) []*html.Node {
  73. if s(n) {
  74. storage = append(storage, n)
  75. }
  76. for child := n.FirstChild; child != nil; child = child.NextSibling {
  77. storage = s.matchAllInto(child, storage)
  78. }
  79. return storage
  80. }
  81. func queryInto(n *html.Node, m Matcher, storage []*html.Node) []*html.Node {
  82. for child := n.FirstChild; child != nil; child = child.NextSibling {
  83. if m.Match(child) {
  84. storage = append(storage, child)
  85. }
  86. storage = queryInto(child, m, storage)
  87. }
  88. return storage
  89. }
  90. // QueryAll returns a slice of all the nodes that match m, from the descendants
  91. // of n.
  92. func QueryAll(n *html.Node, m Matcher) []*html.Node {
  93. return queryInto(n, m, nil)
  94. }
  95. // Match returns true if the node matches the selector.
  96. func (s Selector) Match(n *html.Node) bool {
  97. return s(n)
  98. }
  99. // MatchFirst returns the first node that matches s, from n and its children.
  100. func (s Selector) MatchFirst(n *html.Node) *html.Node {
  101. if s.Match(n) {
  102. return n
  103. }
  104. for c := n.FirstChild; c != nil; c = c.NextSibling {
  105. m := s.MatchFirst(c)
  106. if m != nil {
  107. return m
  108. }
  109. }
  110. return nil
  111. }
  112. // Query returns the first node that matches m, from the descendants of n.
  113. // If none matches, it returns nil.
  114. func Query(n *html.Node, m Matcher) *html.Node {
  115. for c := n.FirstChild; c != nil; c = c.NextSibling {
  116. if m.Match(c) {
  117. return c
  118. }
  119. if matched := Query(c, m); matched != nil {
  120. return matched
  121. }
  122. }
  123. return nil
  124. }
  125. // Filter returns the nodes in nodes that match the selector.
  126. func (s Selector) Filter(nodes []*html.Node) (result []*html.Node) {
  127. for _, n := range nodes {
  128. if s(n) {
  129. result = append(result, n)
  130. }
  131. }
  132. return result
  133. }
  134. // Filter returns the nodes that match m.
  135. func Filter(nodes []*html.Node, m Matcher) (result []*html.Node) {
  136. for _, n := range nodes {
  137. if m.Match(n) {
  138. result = append(result, n)
  139. }
  140. }
  141. return result
  142. }
  143. type tagSelector struct {
  144. tag string
  145. }
  146. // Matches elements with a given tag name.
  147. func (t tagSelector) Match(n *html.Node) bool {
  148. return n.Type == html.ElementNode && n.Data == t.tag
  149. }
  150. func (c tagSelector) Specificity() Specificity {
  151. return Specificity{0, 0, 1}
  152. }
  153. type classSelector struct {
  154. class string
  155. }
  156. // Matches elements by class attribute.
  157. func (t classSelector) Match(n *html.Node) bool {
  158. return matchAttribute(n, "class", func(s string) bool {
  159. return matchInclude(t.class, s)
  160. })
  161. }
  162. func (c classSelector) Specificity() Specificity {
  163. return Specificity{0, 1, 0}
  164. }
  165. type idSelector struct {
  166. id string
  167. }
  168. // Matches elements by id attribute.
  169. func (t idSelector) Match(n *html.Node) bool {
  170. return matchAttribute(n, "id", func(s string) bool {
  171. return s == t.id
  172. })
  173. }
  174. func (c idSelector) Specificity() Specificity {
  175. return Specificity{1, 0, 0}
  176. }
  177. type attrSelector struct {
  178. key, val, operation string
  179. regexp *regexp.Regexp
  180. }
  181. // Matches elements by attribute value.
  182. func (t attrSelector) Match(n *html.Node) bool {
  183. switch t.operation {
  184. case "":
  185. return matchAttribute(n, t.key, func(string) bool { return true })
  186. case "=":
  187. return matchAttribute(n, t.key, func(s string) bool { return s == t.val })
  188. case "!=":
  189. return attributeNotEqualMatch(t.key, t.val, n)
  190. case "~=":
  191. // matches elements where the attribute named key is a whitespace-separated list that includes val.
  192. return matchAttribute(n, t.key, func(s string) bool { return matchInclude(t.val, s) })
  193. case "|=":
  194. return attributeDashMatch(t.key, t.val, n)
  195. case "^=":
  196. return attributePrefixMatch(t.key, t.val, n)
  197. case "$=":
  198. return attributeSuffixMatch(t.key, t.val, n)
  199. case "*=":
  200. return attributeSubstringMatch(t.key, t.val, n)
  201. case "#=":
  202. return attributeRegexMatch(t.key, t.regexp, n)
  203. default:
  204. panic(fmt.Sprintf("unsuported operation : %s", t.operation))
  205. }
  206. }
  207. // matches elements where the attribute named key satisifes the function f.
  208. func matchAttribute(n *html.Node, key string, f func(string) bool) bool {
  209. if n.Type != html.ElementNode {
  210. return false
  211. }
  212. for _, a := range n.Attr {
  213. if a.Key == key && f(a.Val) {
  214. return true
  215. }
  216. }
  217. return false
  218. }
  219. // attributeNotEqualMatch matches elements where
  220. // the attribute named key does not have the value val.
  221. func attributeNotEqualMatch(key, val string, n *html.Node) bool {
  222. if n.Type != html.ElementNode {
  223. return false
  224. }
  225. for _, a := range n.Attr {
  226. if a.Key == key && a.Val == val {
  227. return false
  228. }
  229. }
  230. return true
  231. }
  232. // returns true if s is a whitespace-separated list that includes val.
  233. func matchInclude(val, s string) bool {
  234. for s != "" {
  235. i := strings.IndexAny(s, " \t\r\n\f")
  236. if i == -1 {
  237. return s == val
  238. }
  239. if s[:i] == val {
  240. return true
  241. }
  242. s = s[i+1:]
  243. }
  244. return false
  245. }
  246. // matches elements where the attribute named key equals val or starts with val plus a hyphen.
  247. func attributeDashMatch(key, val string, n *html.Node) bool {
  248. return matchAttribute(n, key,
  249. func(s string) bool {
  250. if s == val {
  251. return true
  252. }
  253. if len(s) <= len(val) {
  254. return false
  255. }
  256. if s[:len(val)] == val && s[len(val)] == '-' {
  257. return true
  258. }
  259. return false
  260. })
  261. }
  262. // attributePrefixMatch returns a Selector that matches elements where
  263. // the attribute named key starts with val.
  264. func attributePrefixMatch(key, val string, n *html.Node) bool {
  265. return matchAttribute(n, key,
  266. func(s string) bool {
  267. if strings.TrimSpace(s) == "" {
  268. return false
  269. }
  270. return strings.HasPrefix(s, val)
  271. })
  272. }
  273. // attributeSuffixMatch matches elements where
  274. // the attribute named key ends with val.
  275. func attributeSuffixMatch(key, val string, n *html.Node) bool {
  276. return matchAttribute(n, key,
  277. func(s string) bool {
  278. if strings.TrimSpace(s) == "" {
  279. return false
  280. }
  281. return strings.HasSuffix(s, val)
  282. })
  283. }
  284. // attributeSubstringMatch matches nodes where
  285. // the attribute named key contains val.
  286. func attributeSubstringMatch(key, val string, n *html.Node) bool {
  287. return matchAttribute(n, key,
  288. func(s string) bool {
  289. if strings.TrimSpace(s) == "" {
  290. return false
  291. }
  292. return strings.Contains(s, val)
  293. })
  294. }
  295. // attributeRegexMatch matches nodes where
  296. // the attribute named key matches the regular expression rx
  297. func attributeRegexMatch(key string, rx *regexp.Regexp, n *html.Node) bool {
  298. return matchAttribute(n, key,
  299. func(s string) bool {
  300. return rx.MatchString(s)
  301. })
  302. }
  303. func (c attrSelector) Specificity() Specificity {
  304. return Specificity{0, 1, 0}
  305. }
  306. // ---------------- Pseudo class selectors ----------------
  307. // we use severals concrete types of pseudo-class selectors
  308. type relativePseudoClassSelector struct {
  309. name string // one of "not", "has", "haschild"
  310. match SelectorGroup
  311. }
  312. func (s relativePseudoClassSelector) Match(n *html.Node) bool {
  313. if n.Type != html.ElementNode {
  314. return false
  315. }
  316. switch s.name {
  317. case "not":
  318. // matches elements that do not match a.
  319. return !s.match.Match(n)
  320. case "has":
  321. // matches elements with any descendant that matches a.
  322. return hasDescendantMatch(n, s.match)
  323. case "haschild":
  324. // matches elements with a child that matches a.
  325. return hasChildMatch(n, s.match)
  326. default:
  327. panic(fmt.Sprintf("unsupported relative pseudo class selector : %s", s.name))
  328. }
  329. }
  330. // hasChildMatch returns whether n has any child that matches a.
  331. func hasChildMatch(n *html.Node, a Matcher) bool {
  332. for c := n.FirstChild; c != nil; c = c.NextSibling {
  333. if a.Match(c) {
  334. return true
  335. }
  336. }
  337. return false
  338. }
  339. // hasDescendantMatch performs a depth-first search of n's descendants,
  340. // testing whether any of them match a. It returns true as soon as a match is
  341. // found, or false if no match is found.
  342. func hasDescendantMatch(n *html.Node, a Matcher) bool {
  343. for c := n.FirstChild; c != nil; c = c.NextSibling {
  344. if a.Match(c) || (c.Type == html.ElementNode && hasDescendantMatch(c, a)) {
  345. return true
  346. }
  347. }
  348. return false
  349. }
  350. // Specificity returns the specificity of the most specific selectors
  351. // in the pseudo-class arguments.
  352. // See https://www.w3.org/TR/selectors/#specificity-rules
  353. func (s relativePseudoClassSelector) Specificity() Specificity {
  354. var max Specificity
  355. for _, sel := range s.match {
  356. newSpe := sel.Specificity()
  357. if max.Less(newSpe) {
  358. max = newSpe
  359. }
  360. }
  361. return max
  362. }
  363. type containsPseudoClassSelector struct {
  364. own bool
  365. value string
  366. }
  367. func (s containsPseudoClassSelector) Match(n *html.Node) bool {
  368. var text string
  369. if s.own {
  370. // matches nodes that directly contain the given text
  371. text = strings.ToLower(nodeOwnText(n))
  372. } else {
  373. // matches nodes that contain the given text.
  374. text = strings.ToLower(nodeText(n))
  375. }
  376. return strings.Contains(text, s.value)
  377. }
  378. func (s containsPseudoClassSelector) Specificity() Specificity {
  379. return Specificity{0, 1, 0}
  380. }
  381. type regexpPseudoClassSelector struct {
  382. own bool
  383. regexp *regexp.Regexp
  384. }
  385. func (s regexpPseudoClassSelector) Match(n *html.Node) bool {
  386. var text string
  387. if s.own {
  388. // matches nodes whose text directly matches the specified regular expression
  389. text = nodeOwnText(n)
  390. } else {
  391. // matches nodes whose text matches the specified regular expression
  392. text = nodeText(n)
  393. }
  394. return s.regexp.MatchString(text)
  395. }
  396. // writeNodeText writes the text contained in n and its descendants to b.
  397. func writeNodeText(n *html.Node, b *bytes.Buffer) {
  398. switch n.Type {
  399. case html.TextNode:
  400. b.WriteString(n.Data)
  401. case html.ElementNode:
  402. for c := n.FirstChild; c != nil; c = c.NextSibling {
  403. writeNodeText(c, b)
  404. }
  405. }
  406. }
  407. // nodeText returns the text contained in n and its descendants.
  408. func nodeText(n *html.Node) string {
  409. var b bytes.Buffer
  410. writeNodeText(n, &b)
  411. return b.String()
  412. }
  413. // nodeOwnText returns the contents of the text nodes that are direct
  414. // children of n.
  415. func nodeOwnText(n *html.Node) string {
  416. var b bytes.Buffer
  417. for c := n.FirstChild; c != nil; c = c.NextSibling {
  418. if c.Type == html.TextNode {
  419. b.WriteString(c.Data)
  420. }
  421. }
  422. return b.String()
  423. }
  424. func (s regexpPseudoClassSelector) Specificity() Specificity {
  425. return Specificity{0, 1, 0}
  426. }
  427. type nthPseudoClassSelector struct {
  428. a, b int
  429. last, ofType bool
  430. }
  431. func (s nthPseudoClassSelector) Match(n *html.Node) bool {
  432. if s.a == 0 {
  433. if s.last {
  434. return simpleNthLastChildMatch(s.b, s.ofType, n)
  435. } else {
  436. return simpleNthChildMatch(s.b, s.ofType, n)
  437. }
  438. }
  439. return nthChildMatch(s.a, s.b, s.last, s.ofType, n)
  440. }
  441. // nthChildMatch implements :nth-child(an+b).
  442. // If last is true, implements :nth-last-child instead.
  443. // If ofType is true, implements :nth-of-type instead.
  444. func nthChildMatch(a, b int, last, ofType bool, n *html.Node) bool {
  445. if n.Type != html.ElementNode {
  446. return false
  447. }
  448. parent := n.Parent
  449. if parent == nil {
  450. return false
  451. }
  452. if parent.Type == html.DocumentNode {
  453. return false
  454. }
  455. i := -1
  456. count := 0
  457. for c := parent.FirstChild; c != nil; c = c.NextSibling {
  458. if (c.Type != html.ElementNode) || (ofType && c.Data != n.Data) {
  459. continue
  460. }
  461. count++
  462. if c == n {
  463. i = count
  464. if !last {
  465. break
  466. }
  467. }
  468. }
  469. if i == -1 {
  470. // This shouldn't happen, since n should always be one of its parent's children.
  471. return false
  472. }
  473. if last {
  474. i = count - i + 1
  475. }
  476. i -= b
  477. if a == 0 {
  478. return i == 0
  479. }
  480. return i%a == 0 && i/a >= 0
  481. }
  482. // simpleNthChildMatch implements :nth-child(b).
  483. // If ofType is true, implements :nth-of-type instead.
  484. func simpleNthChildMatch(b int, ofType bool, n *html.Node) bool {
  485. if n.Type != html.ElementNode {
  486. return false
  487. }
  488. parent := n.Parent
  489. if parent == nil {
  490. return false
  491. }
  492. if parent.Type == html.DocumentNode {
  493. return false
  494. }
  495. count := 0
  496. for c := parent.FirstChild; c != nil; c = c.NextSibling {
  497. if c.Type != html.ElementNode || (ofType && c.Data != n.Data) {
  498. continue
  499. }
  500. count++
  501. if c == n {
  502. return count == b
  503. }
  504. if count >= b {
  505. return false
  506. }
  507. }
  508. return false
  509. }
  510. // simpleNthLastChildMatch implements :nth-last-child(b).
  511. // If ofType is true, implements :nth-last-of-type instead.
  512. func simpleNthLastChildMatch(b int, ofType bool, n *html.Node) bool {
  513. if n.Type != html.ElementNode {
  514. return false
  515. }
  516. parent := n.Parent
  517. if parent == nil {
  518. return false
  519. }
  520. if parent.Type == html.DocumentNode {
  521. return false
  522. }
  523. count := 0
  524. for c := parent.LastChild; c != nil; c = c.PrevSibling {
  525. if c.Type != html.ElementNode || (ofType && c.Data != n.Data) {
  526. continue
  527. }
  528. count++
  529. if c == n {
  530. return count == b
  531. }
  532. if count >= b {
  533. return false
  534. }
  535. }
  536. return false
  537. }
  538. // Specificity for nth-child pseudo-class.
  539. // Does not support a list of selectors
  540. func (s nthPseudoClassSelector) Specificity() Specificity {
  541. return Specificity{0, 1, 0}
  542. }
  543. type onlyChildPseudoClassSelector struct {
  544. ofType bool
  545. }
  546. // Match implements :only-child.
  547. // If `ofType` is true, it implements :only-of-type instead.
  548. func (s onlyChildPseudoClassSelector) Match(n *html.Node) bool {
  549. if n.Type != html.ElementNode {
  550. return false
  551. }
  552. parent := n.Parent
  553. if parent == nil {
  554. return false
  555. }
  556. if parent.Type == html.DocumentNode {
  557. return false
  558. }
  559. count := 0
  560. for c := parent.FirstChild; c != nil; c = c.NextSibling {
  561. if (c.Type != html.ElementNode) || (s.ofType && c.Data != n.Data) {
  562. continue
  563. }
  564. count++
  565. if count > 1 {
  566. return false
  567. }
  568. }
  569. return count == 1
  570. }
  571. func (s onlyChildPseudoClassSelector) Specificity() Specificity {
  572. return Specificity{0, 1, 0}
  573. }
  574. type inputPseudoClassSelector struct{}
  575. // Matches input, select, textarea and button elements.
  576. func (s inputPseudoClassSelector) Match(n *html.Node) bool {
  577. return n.Type == html.ElementNode && (n.Data == "input" || n.Data == "select" || n.Data == "textarea" || n.Data == "button")
  578. }
  579. func (s inputPseudoClassSelector) Specificity() Specificity {
  580. return Specificity{0, 1, 0}
  581. }
  582. type emptyElementPseudoClassSelector struct{}
  583. // Matches empty elements.
  584. func (s emptyElementPseudoClassSelector) Match(n *html.Node) bool {
  585. if n.Type != html.ElementNode {
  586. return false
  587. }
  588. for c := n.FirstChild; c != nil; c = c.NextSibling {
  589. switch c.Type {
  590. case html.ElementNode, html.TextNode:
  591. return false
  592. }
  593. }
  594. return true
  595. }
  596. func (s emptyElementPseudoClassSelector) Specificity() Specificity {
  597. return Specificity{0, 1, 0}
  598. }
  599. type rootPseudoClassSelector struct{}
  600. // Match implements :root
  601. func (s rootPseudoClassSelector) Match(n *html.Node) bool {
  602. if n.Type != html.ElementNode {
  603. return false
  604. }
  605. if n.Parent == nil {
  606. return false
  607. }
  608. return n.Parent.Type == html.DocumentNode
  609. }
  610. func (s rootPseudoClassSelector) Specificity() Specificity {
  611. return Specificity{0, 1, 0}
  612. }
  613. type compoundSelector struct {
  614. selectors []Sel
  615. }
  616. // Matches elements if each sub-selectors matches.
  617. func (t compoundSelector) Match(n *html.Node) bool {
  618. if len(t.selectors) == 0 {
  619. return n.Type == html.ElementNode
  620. }
  621. for _, sel := range t.selectors {
  622. if !sel.Match(n) {
  623. return false
  624. }
  625. }
  626. return true
  627. }
  628. func (s compoundSelector) Specificity() Specificity {
  629. var out Specificity
  630. for _, sel := range s.selectors {
  631. out = out.Add(sel.Specificity())
  632. }
  633. return out
  634. }
  635. type combinedSelector struct {
  636. first Sel
  637. combinator byte
  638. second Sel
  639. }
  640. func (t combinedSelector) Match(n *html.Node) bool {
  641. if t.first == nil {
  642. return false // maybe we should panic
  643. }
  644. switch t.combinator {
  645. case 0:
  646. return t.first.Match(n)
  647. case ' ':
  648. return descendantMatch(t.first, t.second, n)
  649. case '>':
  650. return childMatch(t.first, t.second, n)
  651. case '+':
  652. return siblingMatch(t.first, t.second, true, n)
  653. case '~':
  654. return siblingMatch(t.first, t.second, false, n)
  655. default:
  656. panic("unknown combinator")
  657. }
  658. }
  659. // matches an element if it matches d and has an ancestor that matches a.
  660. func descendantMatch(a, d Matcher, n *html.Node) bool {
  661. if !d.Match(n) {
  662. return false
  663. }
  664. for p := n.Parent; p != nil; p = p.Parent {
  665. if a.Match(p) {
  666. return true
  667. }
  668. }
  669. return false
  670. }
  671. // matches an element if it matches d and its parent matches a.
  672. func childMatch(a, d Matcher, n *html.Node) bool {
  673. return d.Match(n) && n.Parent != nil && a.Match(n.Parent)
  674. }
  675. // matches an element if it matches s2 and is preceded by an element that matches s1.
  676. // If adjacent is true, the sibling must be immediately before the element.
  677. func siblingMatch(s1, s2 Matcher, adjacent bool, n *html.Node) bool {
  678. if !s2.Match(n) {
  679. return false
  680. }
  681. if adjacent {
  682. for n = n.PrevSibling; n != nil; n = n.PrevSibling {
  683. if n.Type == html.TextNode || n.Type == html.CommentNode {
  684. continue
  685. }
  686. return s1.Match(n)
  687. }
  688. return false
  689. }
  690. // Walk backwards looking for element that matches s1
  691. for c := n.PrevSibling; c != nil; c = c.PrevSibling {
  692. if s1.Match(c) {
  693. return true
  694. }
  695. }
  696. return false
  697. }
  698. func (s combinedSelector) Specificity() Specificity {
  699. spec := s.first.Specificity()
  700. if s.second != nil {
  701. spec = spec.Add(s.second.Specificity())
  702. }
  703. return spec
  704. }
  705. // A SelectorGroup is a list of selectors, which matches if any of the
  706. // individual selectors matches.
  707. type SelectorGroup []Sel
  708. // Match returns true if the node matches one of the single selectors.
  709. func (s SelectorGroup) Match(n *html.Node) bool {
  710. for _, sel := range s {
  711. if sel.Match(n) {
  712. return true
  713. }
  714. }
  715. return false
  716. }