github.com/godaddy-x/freego@v1.0.156/goquery/traversal.go (about) 1 package goquery 2 3 import "golang.org/x/net/html" 4 5 type siblingType int 6 7 // Sibling type, used internally when iterating over children at the same 8 // level (siblings) to specify which nodes are requested. 9 const ( 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. 23 func (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. 30 func (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. 37 func (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. 47 func (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. 59 func (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. 68 func (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. 79 func (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. 85 func (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. 92 func (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. 99 func (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. 105 func (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. 111 func (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. 117 func (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. 123 func (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. 130 func (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. 145 func (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. 165 func (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. 174 func (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. 180 func (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. 186 func (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. 193 func (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. 200 func (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. 207 func (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. 217 func (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. 224 func (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. 230 func (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. 237 func (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. 244 func (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. 254 func (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. 261 func (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. 267 func (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. 274 func (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. 281 func (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. 287 func (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. 294 func (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. 301 func (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. 307 func (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. 314 func (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. 321 func (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. 327 func (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. 334 func (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. 341 func (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. 347 func (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. 354 func (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. 361 func (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. 368 func (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. 376 func (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. 384 func (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. 394 func (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. 402 func (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. 410 func (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. 418 func (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. 428 func (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. 436 func (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. 444 func (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. 452 func (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. 459 func (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. 469 func (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. 477 func (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. 485 func (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. 493 func (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. 501 func (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. 508 func (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. 518 func (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. 526 func (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. 533 func 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. 541 func 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). 556 func 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. 578 func 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. 605 func 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. 613 func 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. 677 func 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. 690 func 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 }