1package goquery 2 3import "golang.org/x/net/html" 4 5type siblingType int 6 7// Sibling type, used internally when iterating over children at the same 8// level (siblings) to specify which nodes are requested. 9const ( 10 siblingPrevUntil siblingType = iota - 3 11 siblingPrevAll 12 siblingPrev 13 siblingAll 14 siblingNext 15 siblingNextAll 16 siblingNextUntil 17 siblingAllIncludingNonElements 18) 19 20// Find gets the descendants of each element in the current set of matched 21// elements, filtered by a selector. It returns a new Selection object 22// containing these matched elements. 23func (s *Selection) Find(selector string) *Selection { 24 return pushStack(s, findWithMatcher(s.Nodes, compileMatcher(selector))) 25} 26 27// FindMatcher gets the descendants of each element in the current set of matched 28// elements, filtered by the matcher. It returns a new Selection object 29// containing these matched elements. 30func (s *Selection) FindMatcher(m Matcher) *Selection { 31 return pushStack(s, findWithMatcher(s.Nodes, m)) 32} 33 34// FindSelection gets the descendants of each element in the current 35// Selection, filtered by a Selection. It returns a new Selection object 36// containing these matched elements. 37func (s *Selection) FindSelection(sel *Selection) *Selection { 38 if sel == nil { 39 return pushStack(s, nil) 40 } 41 return s.FindNodes(sel.Nodes...) 42} 43 44// FindNodes gets the descendants of each element in the current 45// Selection, filtered by some nodes. It returns a new Selection object 46// containing these matched elements. 47func (s *Selection) FindNodes(nodes ...*html.Node) *Selection { 48 return pushStack(s, mapNodes(nodes, func(i int, n *html.Node) []*html.Node { 49 if sliceContains(s.Nodes, n) { 50 return []*html.Node{n} 51 } 52 return nil 53 })) 54} 55 56// Contents gets the children of each element in the Selection, 57// including text and comment nodes. It returns a new Selection object 58// containing these elements. 59func (s *Selection) Contents() *Selection { 60 return pushStack(s, getChildrenNodes(s.Nodes, siblingAllIncludingNonElements)) 61} 62 63// ContentsFiltered gets the children of each element in the Selection, 64// filtered by the specified selector. It returns a new Selection 65// object containing these elements. Since selectors only act on Element nodes, 66// this function is an alias to ChildrenFiltered unless the selector is empty, 67// in which case it is an alias to Contents. 68func (s *Selection) ContentsFiltered(selector string) *Selection { 69 if selector != "" { 70 return s.ChildrenFiltered(selector) 71 } 72 return s.Contents() 73} 74 75// ContentsMatcher gets the children of each element in the Selection, 76// filtered by the specified matcher. It returns a new Selection 77// object containing these elements. Since matchers only act on Element nodes, 78// this function is an alias to ChildrenMatcher. 79func (s *Selection) ContentsMatcher(m Matcher) *Selection { 80 return s.ChildrenMatcher(m) 81} 82 83// Children gets the child elements of each element in the Selection. 84// It returns a new Selection object containing these elements. 85func (s *Selection) Children() *Selection { 86 return pushStack(s, getChildrenNodes(s.Nodes, siblingAll)) 87} 88 89// ChildrenFiltered gets the child elements of each element in the Selection, 90// filtered by the specified selector. It returns a new 91// Selection object containing these elements. 92func (s *Selection) ChildrenFiltered(selector string) *Selection { 93 return filterAndPush(s, getChildrenNodes(s.Nodes, siblingAll), compileMatcher(selector)) 94} 95 96// ChildrenMatcher gets the child elements of each element in the Selection, 97// filtered by the specified matcher. It returns a new 98// Selection object containing these elements. 99func (s *Selection) ChildrenMatcher(m Matcher) *Selection { 100 return filterAndPush(s, getChildrenNodes(s.Nodes, siblingAll), m) 101} 102 103// Parent gets the parent of each element in the Selection. It returns a 104// new Selection object containing the matched elements. 105func (s *Selection) Parent() *Selection { 106 return pushStack(s, getParentNodes(s.Nodes)) 107} 108 109// ParentFiltered gets the parent of each element in the Selection filtered by a 110// selector. It returns a new Selection object containing the matched elements. 111func (s *Selection) ParentFiltered(selector string) *Selection { 112 return filterAndPush(s, getParentNodes(s.Nodes), compileMatcher(selector)) 113} 114 115// ParentMatcher gets the parent of each element in the Selection filtered by a 116// matcher. It returns a new Selection object containing the matched elements. 117func (s *Selection) ParentMatcher(m Matcher) *Selection { 118 return filterAndPush(s, getParentNodes(s.Nodes), m) 119} 120 121// Closest gets the first element that matches the selector by testing the 122// element itself and traversing up through its ancestors in the DOM tree. 123func (s *Selection) Closest(selector string) *Selection { 124 cs := compileMatcher(selector) 125 return s.ClosestMatcher(cs) 126} 127 128// ClosestMatcher gets the first element that matches the matcher by testing the 129// element itself and traversing up through its ancestors in the DOM tree. 130func (s *Selection) ClosestMatcher(m Matcher) *Selection { 131 return pushStack(s, mapNodes(s.Nodes, func(i int, n *html.Node) []*html.Node { 132 // For each node in the selection, test the node itself, then each parent 133 // until a match is found. 134 for ; n != nil; n = n.Parent { 135 if m.Match(n) { 136 return []*html.Node{n} 137 } 138 } 139 return nil 140 })) 141} 142 143// ClosestNodes gets the first element that matches one of the nodes by testing the 144// element itself and traversing up through its ancestors in the DOM tree. 145func (s *Selection) ClosestNodes(nodes ...*html.Node) *Selection { 146 set := make(map[*html.Node]bool) 147 for _, n := range nodes { 148 set[n] = true 149 } 150 return pushStack(s, mapNodes(s.Nodes, func(i int, n *html.Node) []*html.Node { 151 // For each node in the selection, test the node itself, then each parent 152 // until a match is found. 153 for ; n != nil; n = n.Parent { 154 if set[n] { 155 return []*html.Node{n} 156 } 157 } 158 return nil 159 })) 160} 161 162// ClosestSelection gets the first element that matches one of the nodes in the 163// Selection by testing the element itself and traversing up through its ancestors 164// in the DOM tree. 165func (s *Selection) ClosestSelection(sel *Selection) *Selection { 166 if sel == nil { 167 return pushStack(s, nil) 168 } 169 return s.ClosestNodes(sel.Nodes...) 170} 171 172// Parents gets the ancestors of each element in the current Selection. It 173// returns a new Selection object with the matched elements. 174func (s *Selection) Parents() *Selection { 175 return pushStack(s, getParentsNodes(s.Nodes, nil, nil)) 176} 177 178// ParentsFiltered gets the ancestors of each element in the current 179// Selection. It returns a new Selection object with the matched elements. 180func (s *Selection) ParentsFiltered(selector string) *Selection { 181 return filterAndPush(s, getParentsNodes(s.Nodes, nil, nil), compileMatcher(selector)) 182} 183 184// ParentsMatcher gets the ancestors of each element in the current 185// Selection. It returns a new Selection object with the matched elements. 186func (s *Selection) ParentsMatcher(m Matcher) *Selection { 187 return filterAndPush(s, getParentsNodes(s.Nodes, nil, nil), m) 188} 189 190// ParentsUntil gets the ancestors of each element in the Selection, up to but 191// not including the element matched by the selector. It returns a new Selection 192// object containing the matched elements. 193func (s *Selection) ParentsUntil(selector string) *Selection { 194 return pushStack(s, getParentsNodes(s.Nodes, compileMatcher(selector), nil)) 195} 196 197// ParentsUntilMatcher gets the ancestors of each element in the Selection, up to but 198// not including the element matched by the matcher. It returns a new Selection 199// object containing the matched elements. 200func (s *Selection) ParentsUntilMatcher(m Matcher) *Selection { 201 return pushStack(s, getParentsNodes(s.Nodes, m, nil)) 202} 203 204// ParentsUntilSelection gets the ancestors of each element in the Selection, 205// up to but not including the elements in the specified Selection. It returns a 206// new Selection object containing the matched elements. 207func (s *Selection) ParentsUntilSelection(sel *Selection) *Selection { 208 if sel == nil { 209 return s.Parents() 210 } 211 return s.ParentsUntilNodes(sel.Nodes...) 212} 213 214// ParentsUntilNodes gets the ancestors of each element in the Selection, 215// up to but not including the specified nodes. It returns a 216// new Selection object containing the matched elements. 217func (s *Selection) ParentsUntilNodes(nodes ...*html.Node) *Selection { 218 return pushStack(s, getParentsNodes(s.Nodes, nil, nodes)) 219} 220 221// ParentsFilteredUntil is like ParentsUntil, with the option to filter the 222// results based on a selector string. It returns a new Selection 223// object containing the matched elements. 224func (s *Selection) ParentsFilteredUntil(filterSelector, untilSelector string) *Selection { 225 return filterAndPush(s, getParentsNodes(s.Nodes, compileMatcher(untilSelector), nil), compileMatcher(filterSelector)) 226} 227 228// ParentsFilteredUntilMatcher is like ParentsUntilMatcher, with the option to filter the 229// results based on a matcher. It returns a new Selection object containing the matched elements. 230func (s *Selection) ParentsFilteredUntilMatcher(filter, until Matcher) *Selection { 231 return filterAndPush(s, getParentsNodes(s.Nodes, until, nil), filter) 232} 233 234// ParentsFilteredUntilSelection is like ParentsUntilSelection, with the 235// option to filter the results based on a selector string. It returns a new 236// Selection object containing the matched elements. 237func (s *Selection) ParentsFilteredUntilSelection(filterSelector string, sel *Selection) *Selection { 238 return s.ParentsMatcherUntilSelection(compileMatcher(filterSelector), sel) 239} 240 241// ParentsMatcherUntilSelection is like ParentsUntilSelection, with the 242// option to filter the results based on a matcher. It returns a new 243// Selection object containing the matched elements. 244func (s *Selection) ParentsMatcherUntilSelection(filter Matcher, sel *Selection) *Selection { 245 if sel == nil { 246 return s.ParentsMatcher(filter) 247 } 248 return s.ParentsMatcherUntilNodes(filter, sel.Nodes...) 249} 250 251// ParentsFilteredUntilNodes is like ParentsUntilNodes, with the 252// option to filter the results based on a selector string. It returns a new 253// Selection object containing the matched elements. 254func (s *Selection) ParentsFilteredUntilNodes(filterSelector string, nodes ...*html.Node) *Selection { 255 return filterAndPush(s, getParentsNodes(s.Nodes, nil, nodes), compileMatcher(filterSelector)) 256} 257 258// ParentsMatcherUntilNodes is like ParentsUntilNodes, with the 259// option to filter the results based on a matcher. It returns a new 260// Selection object containing the matched elements. 261func (s *Selection) ParentsMatcherUntilNodes(filter Matcher, nodes ...*html.Node) *Selection { 262 return filterAndPush(s, getParentsNodes(s.Nodes, nil, nodes), filter) 263} 264 265// Siblings gets the siblings of each element in the Selection. It returns 266// a new Selection object containing the matched elements. 267func (s *Selection) Siblings() *Selection { 268 return pushStack(s, getSiblingNodes(s.Nodes, siblingAll, nil, nil)) 269} 270 271// SiblingsFiltered gets the siblings of each element in the Selection 272// filtered by a selector. It returns a new Selection object containing the 273// matched elements. 274func (s *Selection) SiblingsFiltered(selector string) *Selection { 275 return filterAndPush(s, getSiblingNodes(s.Nodes, siblingAll, nil, nil), compileMatcher(selector)) 276} 277 278// SiblingsMatcher gets the siblings of each element in the Selection 279// filtered by a matcher. It returns a new Selection object containing the 280// matched elements. 281func (s *Selection) SiblingsMatcher(m Matcher) *Selection { 282 return filterAndPush(s, getSiblingNodes(s.Nodes, siblingAll, nil, nil), m) 283} 284 285// Next gets the immediately following sibling of each element in the 286// Selection. It returns a new Selection object containing the matched elements. 287func (s *Selection) Next() *Selection { 288 return pushStack(s, getSiblingNodes(s.Nodes, siblingNext, nil, nil)) 289} 290 291// NextFiltered gets the immediately following sibling of each element in the 292// Selection filtered by a selector. It returns a new Selection object 293// containing the matched elements. 294func (s *Selection) NextFiltered(selector string) *Selection { 295 return filterAndPush(s, getSiblingNodes(s.Nodes, siblingNext, nil, nil), compileMatcher(selector)) 296} 297 298// NextMatcher gets the immediately following sibling of each element in the 299// Selection filtered by a matcher. It returns a new Selection object 300// containing the matched elements. 301func (s *Selection) NextMatcher(m Matcher) *Selection { 302 return filterAndPush(s, getSiblingNodes(s.Nodes, siblingNext, nil, nil), m) 303} 304 305// NextAll gets all the following siblings of each element in the 306// Selection. It returns a new Selection object containing the matched elements. 307func (s *Selection) NextAll() *Selection { 308 return pushStack(s, getSiblingNodes(s.Nodes, siblingNextAll, nil, nil)) 309} 310 311// NextAllFiltered gets all the following siblings of each element in the 312// Selection filtered by a selector. It returns a new Selection object 313// containing the matched elements. 314func (s *Selection) NextAllFiltered(selector string) *Selection { 315 return filterAndPush(s, getSiblingNodes(s.Nodes, siblingNextAll, nil, nil), compileMatcher(selector)) 316} 317 318// NextAllMatcher gets all the following siblings of each element in the 319// Selection filtered by a matcher. It returns a new Selection object 320// containing the matched elements. 321func (s *Selection) NextAllMatcher(m Matcher) *Selection { 322 return filterAndPush(s, getSiblingNodes(s.Nodes, siblingNextAll, nil, nil), m) 323} 324 325// Prev gets the immediately preceding sibling of each element in the 326// Selection. It returns a new Selection object containing the matched elements. 327func (s *Selection) Prev() *Selection { 328 return pushStack(s, getSiblingNodes(s.Nodes, siblingPrev, nil, nil)) 329} 330 331// PrevFiltered gets the immediately preceding sibling of each element in the 332// Selection filtered by a selector. It returns a new Selection object 333// containing the matched elements. 334func (s *Selection) PrevFiltered(selector string) *Selection { 335 return filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrev, nil, nil), compileMatcher(selector)) 336} 337 338// PrevMatcher gets the immediately preceding sibling of each element in the 339// Selection filtered by a matcher. It returns a new Selection object 340// containing the matched elements. 341func (s *Selection) PrevMatcher(m Matcher) *Selection { 342 return filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrev, nil, nil), m) 343} 344 345// PrevAll gets all the preceding siblings of each element in the 346// Selection. It returns a new Selection object containing the matched elements. 347func (s *Selection) PrevAll() *Selection { 348 return pushStack(s, getSiblingNodes(s.Nodes, siblingPrevAll, nil, nil)) 349} 350 351// PrevAllFiltered gets all the preceding siblings of each element in the 352// Selection filtered by a selector. It returns a new Selection object 353// containing the matched elements. 354func (s *Selection) PrevAllFiltered(selector string) *Selection { 355 return filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrevAll, nil, nil), compileMatcher(selector)) 356} 357 358// PrevAllMatcher gets all the preceding siblings of each element in the 359// Selection filtered by a matcher. It returns a new Selection object 360// containing the matched elements. 361func (s *Selection) PrevAllMatcher(m Matcher) *Selection { 362 return filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrevAll, nil, nil), m) 363} 364 365// NextUntil gets all following siblings of each element up to but not 366// including the element matched by the selector. It returns a new Selection 367// object containing the matched elements. 368func (s *Selection) NextUntil(selector string) *Selection { 369 return pushStack(s, getSiblingNodes(s.Nodes, siblingNextUntil, 370 compileMatcher(selector), nil)) 371} 372 373// NextUntilMatcher gets all following siblings of each element up to but not 374// including the element matched by the matcher. It returns a new Selection 375// object containing the matched elements. 376func (s *Selection) NextUntilMatcher(m Matcher) *Selection { 377 return pushStack(s, getSiblingNodes(s.Nodes, siblingNextUntil, 378 m, nil)) 379} 380 381// NextUntilSelection gets all following siblings of each element up to but not 382// including the element matched by the Selection. It returns a new Selection 383// object containing the matched elements. 384func (s *Selection) NextUntilSelection(sel *Selection) *Selection { 385 if sel == nil { 386 return s.NextAll() 387 } 388 return s.NextUntilNodes(sel.Nodes...) 389} 390 391// NextUntilNodes gets all following siblings of each element up to but not 392// including the element matched by the nodes. It returns a new Selection 393// object containing the matched elements. 394func (s *Selection) NextUntilNodes(nodes ...*html.Node) *Selection { 395 return pushStack(s, getSiblingNodes(s.Nodes, siblingNextUntil, 396 nil, nodes)) 397} 398 399// PrevUntil gets all preceding siblings of each element up to but not 400// including the element matched by the selector. It returns a new Selection 401// object containing the matched elements. 402func (s *Selection) PrevUntil(selector string) *Selection { 403 return pushStack(s, getSiblingNodes(s.Nodes, siblingPrevUntil, 404 compileMatcher(selector), nil)) 405} 406 407// PrevUntilMatcher gets all preceding siblings of each element up to but not 408// including the element matched by the matcher. It returns a new Selection 409// object containing the matched elements. 410func (s *Selection) PrevUntilMatcher(m Matcher) *Selection { 411 return pushStack(s, getSiblingNodes(s.Nodes, siblingPrevUntil, 412 m, nil)) 413} 414 415// PrevUntilSelection gets all preceding siblings of each element up to but not 416// including the element matched by the Selection. It returns a new Selection 417// object containing the matched elements. 418func (s *Selection) PrevUntilSelection(sel *Selection) *Selection { 419 if sel == nil { 420 return s.PrevAll() 421 } 422 return s.PrevUntilNodes(sel.Nodes...) 423} 424 425// PrevUntilNodes gets all preceding siblings of each element up to but not 426// including the element matched by the nodes. It returns a new Selection 427// object containing the matched elements. 428func (s *Selection) PrevUntilNodes(nodes ...*html.Node) *Selection { 429 return pushStack(s, getSiblingNodes(s.Nodes, siblingPrevUntil, 430 nil, nodes)) 431} 432 433// NextFilteredUntil is like NextUntil, with the option to filter 434// the results based on a selector string. 435// It returns a new Selection object containing the matched elements. 436func (s *Selection) NextFilteredUntil(filterSelector, untilSelector string) *Selection { 437 return filterAndPush(s, getSiblingNodes(s.Nodes, siblingNextUntil, 438 compileMatcher(untilSelector), nil), compileMatcher(filterSelector)) 439} 440 441// NextFilteredUntilMatcher is like NextUntilMatcher, with the option to filter 442// the results based on a matcher. 443// It returns a new Selection object containing the matched elements. 444func (s *Selection) NextFilteredUntilMatcher(filter, until Matcher) *Selection { 445 return filterAndPush(s, getSiblingNodes(s.Nodes, siblingNextUntil, 446 until, nil), filter) 447} 448 449// NextFilteredUntilSelection is like NextUntilSelection, with the 450// option to filter the results based on a selector string. It returns a new 451// Selection object containing the matched elements. 452func (s *Selection) NextFilteredUntilSelection(filterSelector string, sel *Selection) *Selection { 453 return s.NextMatcherUntilSelection(compileMatcher(filterSelector), sel) 454} 455 456// NextMatcherUntilSelection is like NextUntilSelection, with the 457// option to filter the results based on a matcher. It returns a new 458// Selection object containing the matched elements. 459func (s *Selection) NextMatcherUntilSelection(filter Matcher, sel *Selection) *Selection { 460 if sel == nil { 461 return s.NextMatcher(filter) 462 } 463 return s.NextMatcherUntilNodes(filter, sel.Nodes...) 464} 465 466// NextFilteredUntilNodes is like NextUntilNodes, with the 467// option to filter the results based on a selector string. It returns a new 468// Selection object containing the matched elements. 469func (s *Selection) NextFilteredUntilNodes(filterSelector string, nodes ...*html.Node) *Selection { 470 return filterAndPush(s, getSiblingNodes(s.Nodes, siblingNextUntil, 471 nil, nodes), compileMatcher(filterSelector)) 472} 473 474// NextMatcherUntilNodes is like NextUntilNodes, with the 475// option to filter the results based on a matcher. It returns a new 476// Selection object containing the matched elements. 477func (s *Selection) NextMatcherUntilNodes(filter Matcher, nodes ...*html.Node) *Selection { 478 return filterAndPush(s, getSiblingNodes(s.Nodes, siblingNextUntil, 479 nil, nodes), filter) 480} 481 482// PrevFilteredUntil is like PrevUntil, with the option to filter 483// the results based on a selector string. 484// It returns a new Selection object containing the matched elements. 485func (s *Selection) PrevFilteredUntil(filterSelector, untilSelector string) *Selection { 486 return filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrevUntil, 487 compileMatcher(untilSelector), nil), compileMatcher(filterSelector)) 488} 489 490// PrevFilteredUntilMatcher is like PrevUntilMatcher, with the option to filter 491// the results based on a matcher. 492// It returns a new Selection object containing the matched elements. 493func (s *Selection) PrevFilteredUntilMatcher(filter, until Matcher) *Selection { 494 return filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrevUntil, 495 until, nil), filter) 496} 497 498// PrevFilteredUntilSelection is like PrevUntilSelection, with the 499// option to filter the results based on a selector string. It returns a new 500// Selection object containing the matched elements. 501func (s *Selection) PrevFilteredUntilSelection(filterSelector string, sel *Selection) *Selection { 502 return s.PrevMatcherUntilSelection(compileMatcher(filterSelector), sel) 503} 504 505// PrevMatcherUntilSelection is like PrevUntilSelection, with the 506// option to filter the results based on a matcher. It returns a new 507// Selection object containing the matched elements. 508func (s *Selection) PrevMatcherUntilSelection(filter Matcher, sel *Selection) *Selection { 509 if sel == nil { 510 return s.PrevMatcher(filter) 511 } 512 return s.PrevMatcherUntilNodes(filter, sel.Nodes...) 513} 514 515// PrevFilteredUntilNodes is like PrevUntilNodes, with the 516// option to filter the results based on a selector string. It returns a new 517// Selection object containing the matched elements. 518func (s *Selection) PrevFilteredUntilNodes(filterSelector string, nodes ...*html.Node) *Selection { 519 return filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrevUntil, 520 nil, nodes), compileMatcher(filterSelector)) 521} 522 523// PrevMatcherUntilNodes is like PrevUntilNodes, with the 524// option to filter the results based on a matcher. It returns a new 525// Selection object containing the matched elements. 526func (s *Selection) PrevMatcherUntilNodes(filter Matcher, nodes ...*html.Node) *Selection { 527 return filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrevUntil, 528 nil, nodes), filter) 529} 530 531// Filter and push filters the nodes based on a matcher, and pushes the results 532// on the stack, with the srcSel as previous selection. 533func filterAndPush(srcSel *Selection, nodes []*html.Node, m Matcher) *Selection { 534 // Create a temporary Selection with the specified nodes to filter using winnow 535 sel := &Selection{nodes, srcSel.document, nil} 536 // Filter based on matcher and push on stack 537 return pushStack(srcSel, winnow(sel, m, true)) 538} 539 540// Internal implementation of Find that return raw nodes. 541func findWithMatcher(nodes []*html.Node, m Matcher) []*html.Node { 542 // Map nodes to find the matches within the children of each node 543 return mapNodes(nodes, func(i int, n *html.Node) (result []*html.Node) { 544 // Go down one level, becausejQuery's Find selects only within descendants 545 for c := n.FirstChild; c != nil; c = c.NextSibling { 546 if c.Type == html.ElementNode { 547 result = append(result, m.MatchAll(c)...) 548 } 549 } 550 return 551 }) 552} 553 554// Internal implementation to get all parent nodes, stopping at the specified 555// node (or nil if no stop). 556func getParentsNodes(nodes []*html.Node, stopm Matcher, stopNodes []*html.Node) []*html.Node { 557 return mapNodes(nodes, func(i int, n *html.Node) (result []*html.Node) { 558 for p := n.Parent; p != nil; p = p.Parent { 559 sel := newSingleSelection(p, nil) 560 if stopm != nil { 561 if sel.IsMatcher(stopm) { 562 break 563 } 564 } else if len(stopNodes) > 0 { 565 if sel.IsNodes(stopNodes...) { 566 break 567 } 568 } 569 if p.Type == html.ElementNode { 570 result = append(result, p) 571 } 572 } 573 return 574 }) 575} 576 577// Internal implementation of sibling nodes that return a raw slice of matches. 578func getSiblingNodes(nodes []*html.Node, st siblingType, untilm Matcher, untilNodes []*html.Node) []*html.Node { 579 var f func(*html.Node) bool 580 581 // If the requested siblings are ...Until, create the test function to 582 // determine if the until condition is reached (returns true if it is) 583 if st == siblingNextUntil || st == siblingPrevUntil { 584 f = func(n *html.Node) bool { 585 if untilm != nil { 586 // Matcher-based condition 587 sel := newSingleSelection(n, nil) 588 return sel.IsMatcher(untilm) 589 } else if len(untilNodes) > 0 { 590 // Nodes-based condition 591 sel := newSingleSelection(n, nil) 592 return sel.IsNodes(untilNodes...) 593 } 594 return false 595 } 596 } 597 598 return mapNodes(nodes, func(i int, n *html.Node) []*html.Node { 599 return getChildrenWithSiblingType(n.Parent, st, n, f) 600 }) 601} 602 603// Gets the children nodes of each node in the specified slice of nodes, 604// based on the sibling type request. 605func getChildrenNodes(nodes []*html.Node, st siblingType) []*html.Node { 606 return mapNodes(nodes, func(i int, n *html.Node) []*html.Node { 607 return getChildrenWithSiblingType(n, st, nil, nil) 608 }) 609} 610 611// Gets the children of the specified parent, based on the requested sibling 612// type, skipping a specified node if required. 613func getChildrenWithSiblingType(parent *html.Node, st siblingType, skipNode *html.Node, 614 untilFunc func(*html.Node) bool) (result []*html.Node) { 615 616 // Create the iterator function 617 var iter = func(cur *html.Node) (ret *html.Node) { 618 // Based on the sibling type requested, iterate the right way 619 for { 620 switch st { 621 case siblingAll, siblingAllIncludingNonElements: 622 if cur == nil { 623 // First iteration, start with first child of parent 624 // Skip node if required 625 if ret = parent.FirstChild; ret == skipNode && skipNode != nil { 626 ret = skipNode.NextSibling 627 } 628 } else { 629 // Skip node if required 630 if ret = cur.NextSibling; ret == skipNode && skipNode != nil { 631 ret = skipNode.NextSibling 632 } 633 } 634 case siblingPrev, siblingPrevAll, siblingPrevUntil: 635 if cur == nil { 636 // Start with previous sibling of the skip node 637 ret = skipNode.PrevSibling 638 } else { 639 ret = cur.PrevSibling 640 } 641 case siblingNext, siblingNextAll, siblingNextUntil: 642 if cur == nil { 643 // Start with next sibling of the skip node 644 ret = skipNode.NextSibling 645 } else { 646 ret = cur.NextSibling 647 } 648 default: 649 panic("Invalid sibling type.") 650 } 651 if ret == nil || ret.Type == html.ElementNode || st == siblingAllIncludingNonElements { 652 return 653 } 654 // Not a valid node, try again from this one 655 cur = ret 656 } 657 } 658 659 for c := iter(nil); c != nil; c = iter(c) { 660 // If this is an ...Until case, test before append (returns true 661 // if the until condition is reached) 662 if st == siblingNextUntil || st == siblingPrevUntil { 663 if untilFunc(c) { 664 return 665 } 666 } 667 result = append(result, c) 668 if st == siblingNext || st == siblingPrev { 669 // Only one node was requested (immediate next or previous), so exit 670 return 671 } 672 } 673 return 674} 675 676// Internal implementation of parent nodes that return a raw slice of Nodes. 677func getParentNodes(nodes []*html.Node) []*html.Node { 678 return mapNodes(nodes, func(i int, n *html.Node) []*html.Node { 679 if n.Parent != nil && n.Parent.Type == html.ElementNode { 680 return []*html.Node{n.Parent} 681 } 682 return nil 683 }) 684} 685 686// Internal map function used by many traversing methods. Takes the source nodes 687// to iterate on and the mapping function that returns an array of nodes. 688// Returns an array of nodes mapped by calling the callback function once for 689// each node in the source nodes. 690func mapNodes(nodes []*html.Node, f func(int, *html.Node) []*html.Node) (result []*html.Node) { 691 set := make(map[*html.Node]bool) 692 for i, n := range nodes { 693 if vals := f(i, n); len(vals) > 0 { 694 result = appendWithoutDuplicates(result, vals, set) 695 } 696 } 697 return result 698} 699