1 package goquery
2
3 import (
4 "strings"
5
6 "golang.org/x/net/html"
7 )
8
9
10
11
12
13
14
15
16 func (s *Selection) After(selector string) *Selection {
17 return s.AfterMatcher(compileMatcher(selector))
18 }
19
20
21
22
23
24
25
26
27 func (s *Selection) AfterMatcher(m Matcher) *Selection {
28 return s.AfterNodes(m.MatchAll(s.document.rootNode)...)
29 }
30
31
32
33
34
35 func (s *Selection) AfterSelection(sel *Selection) *Selection {
36 return s.AfterNodes(sel.Nodes...)
37 }
38
39
40
41
42 func (s *Selection) AfterHtml(htmlStr string) *Selection {
43 return s.eachNodeHtml(htmlStr, true, func(node *html.Node, nodes []*html.Node) {
44 nextSibling := node.NextSibling
45 for _, n := range nodes {
46 if node.Parent != nil {
47 node.Parent.InsertBefore(n, nextSibling)
48 }
49 }
50 })
51 }
52
53
54
55
56 func (s *Selection) AfterNodes(ns ...*html.Node) *Selection {
57 return s.manipulateNodes(ns, true, func(sn *html.Node, n *html.Node) {
58 if sn.Parent != nil {
59 sn.Parent.InsertBefore(n, sn.NextSibling)
60 }
61 })
62 }
63
64
65
66
67
68
69
70
71
72
73
74 func (s *Selection) Append(selector string) *Selection {
75 return s.AppendMatcher(compileMatcher(selector))
76 }
77
78
79
80
81
82 func (s *Selection) AppendMatcher(m Matcher) *Selection {
83 return s.AppendNodes(m.MatchAll(s.document.rootNode)...)
84 }
85
86
87
88
89
90 func (s *Selection) AppendSelection(sel *Selection) *Selection {
91 return s.AppendNodes(sel.Nodes...)
92 }
93
94
95 func (s *Selection) AppendHtml(htmlStr string) *Selection {
96 return s.eachNodeHtml(htmlStr, false, func(node *html.Node, nodes []*html.Node) {
97 for _, n := range nodes {
98 node.AppendChild(n)
99 }
100 })
101 }
102
103
104
105
106 func (s *Selection) AppendNodes(ns ...*html.Node) *Selection {
107 return s.manipulateNodes(ns, false, func(sn *html.Node, n *html.Node) {
108 sn.AppendChild(n)
109 })
110 }
111
112
113
114
115 func (s *Selection) Before(selector string) *Selection {
116 return s.BeforeMatcher(compileMatcher(selector))
117 }
118
119
120
121
122 func (s *Selection) BeforeMatcher(m Matcher) *Selection {
123 return s.BeforeNodes(m.MatchAll(s.document.rootNode)...)
124 }
125
126
127
128
129
130 func (s *Selection) BeforeSelection(sel *Selection) *Selection {
131 return s.BeforeNodes(sel.Nodes...)
132 }
133
134
135
136
137 func (s *Selection) BeforeHtml(htmlStr string) *Selection {
138 return s.eachNodeHtml(htmlStr, true, func(node *html.Node, nodes []*html.Node) {
139 for _, n := range nodes {
140 if node.Parent != nil {
141 node.Parent.InsertBefore(n, node)
142 }
143 }
144 })
145 }
146
147
148
149
150 func (s *Selection) BeforeNodes(ns ...*html.Node) *Selection {
151 return s.manipulateNodes(ns, false, func(sn *html.Node, n *html.Node) {
152 if sn.Parent != nil {
153 sn.Parent.InsertBefore(n, sn)
154 }
155 })
156 }
157
158
159
160 func (s *Selection) Clone() *Selection {
161 ns := newEmptySelection(s.document)
162 ns.Nodes = cloneNodes(s.Nodes)
163 return ns
164 }
165
166
167
168 func (s *Selection) Empty() *Selection {
169 var nodes []*html.Node
170
171 for _, n := range s.Nodes {
172 for c := n.FirstChild; c != nil; c = n.FirstChild {
173 n.RemoveChild(c)
174 nodes = append(nodes, c)
175 }
176 }
177
178 return pushStack(s, nodes)
179 }
180
181
182
183 func (s *Selection) Prepend(selector string) *Selection {
184 return s.PrependMatcher(compileMatcher(selector))
185 }
186
187
188
189
190
191 func (s *Selection) PrependMatcher(m Matcher) *Selection {
192 return s.PrependNodes(m.MatchAll(s.document.rootNode)...)
193 }
194
195
196
197
198
199 func (s *Selection) PrependSelection(sel *Selection) *Selection {
200 return s.PrependNodes(sel.Nodes...)
201 }
202
203
204 func (s *Selection) PrependHtml(htmlStr string) *Selection {
205 return s.eachNodeHtml(htmlStr, false, func(node *html.Node, nodes []*html.Node) {
206 firstChild := node.FirstChild
207 for _, n := range nodes {
208 node.InsertBefore(n, firstChild)
209 }
210 })
211 }
212
213
214
215
216
217 func (s *Selection) PrependNodes(ns ...*html.Node) *Selection {
218 return s.manipulateNodes(ns, true, func(sn *html.Node, n *html.Node) {
219
220
221 sn.InsertBefore(n, sn.FirstChild)
222 })
223 }
224
225
226
227 func (s *Selection) Remove() *Selection {
228 for _, n := range s.Nodes {
229 if n.Parent != nil {
230 n.Parent.RemoveChild(n)
231 }
232 }
233
234 return s
235 }
236
237
238
239
240
241
242
243 func (s *Selection) RemoveFiltered(selector string) *Selection {
244 return s.RemoveMatcher(compileMatcher(selector))
245 }
246
247
248
249
250 func (s *Selection) RemoveMatcher(m Matcher) *Selection {
251 return s.FilterMatcher(m).Remove()
252 }
253
254
255
256
257
258
259 func (s *Selection) ReplaceWith(selector string) *Selection {
260 return s.ReplaceWithMatcher(compileMatcher(selector))
261 }
262
263
264
265
266
267
268 func (s *Selection) ReplaceWithMatcher(m Matcher) *Selection {
269 return s.ReplaceWithNodes(m.MatchAll(s.document.rootNode)...)
270 }
271
272
273
274
275
276
277 func (s *Selection) ReplaceWithSelection(sel *Selection) *Selection {
278 return s.ReplaceWithNodes(sel.Nodes...)
279 }
280
281
282
283
284
285
286 func (s *Selection) ReplaceWithHtml(htmlStr string) *Selection {
287 s.eachNodeHtml(htmlStr, true, func(node *html.Node, nodes []*html.Node) {
288 nextSibling := node.NextSibling
289 for _, n := range nodes {
290 if node.Parent != nil {
291 node.Parent.InsertBefore(n, nextSibling)
292 }
293 }
294 })
295 return s.Remove()
296 }
297
298
299
300
301
302
303 func (s *Selection) ReplaceWithNodes(ns ...*html.Node) *Selection {
304 s.AfterNodes(ns...)
305 return s.Remove()
306 }
307
308
309
310 func (s *Selection) SetHtml(htmlStr string) *Selection {
311 for _, context := range s.Nodes {
312 for c := context.FirstChild; c != nil; c = context.FirstChild {
313 context.RemoveChild(c)
314 }
315 }
316 return s.eachNodeHtml(htmlStr, false, func(node *html.Node, nodes []*html.Node) {
317 for _, n := range nodes {
318 node.AppendChild(n)
319 }
320 })
321 }
322
323
324
325 func (s *Selection) SetText(text string) *Selection {
326 return s.SetHtml(html.EscapeString(text))
327 }
328
329
330
331
332 func (s *Selection) Unwrap() *Selection {
333 s.Parent().Each(func(i int, ss *Selection) {
334
335
336
337 if ss.Nodes[0].Data != "body" {
338 ss.ReplaceWithSelection(ss.Contents())
339 }
340 })
341
342 return s
343 }
344
345
346
347
348
349
350 func (s *Selection) Wrap(selector string) *Selection {
351 return s.WrapMatcher(compileMatcher(selector))
352 }
353
354
355
356
357
358
359 func (s *Selection) WrapMatcher(m Matcher) *Selection {
360 return s.wrapNodes(m.MatchAll(s.document.rootNode)...)
361 }
362
363
364
365
366
367
368 func (s *Selection) WrapSelection(sel *Selection) *Selection {
369 return s.wrapNodes(sel.Nodes...)
370 }
371
372
373
374
375
376 func (s *Selection) WrapHtml(htmlStr string) *Selection {
377 nodesMap := make(map[string][]*html.Node)
378 for _, context := range s.Nodes {
379 var parent *html.Node
380 if context.Parent != nil {
381 parent = context.Parent
382 } else {
383 parent = &html.Node{Type: html.ElementNode}
384 }
385 nodes, found := nodesMap[nodeName(parent)]
386 if !found {
387 nodes = parseHtmlWithContext(htmlStr, parent)
388 nodesMap[nodeName(parent)] = nodes
389 }
390 newSingleSelection(context, s.document).wrapAllNodes(cloneNodes(nodes)...)
391 }
392 return s
393 }
394
395
396
397
398
399
400 func (s *Selection) WrapNode(n *html.Node) *Selection {
401 return s.wrapNodes(n)
402 }
403
404 func (s *Selection) wrapNodes(ns ...*html.Node) *Selection {
405 s.Each(func(i int, ss *Selection) {
406 ss.wrapAllNodes(ns...)
407 })
408
409 return s
410 }
411
412
413
414
415
416
417 func (s *Selection) WrapAll(selector string) *Selection {
418 return s.WrapAllMatcher(compileMatcher(selector))
419 }
420
421
422
423
424
425
426 func (s *Selection) WrapAllMatcher(m Matcher) *Selection {
427 return s.wrapAllNodes(m.MatchAll(s.document.rootNode)...)
428 }
429
430
431
432
433
434
435 func (s *Selection) WrapAllSelection(sel *Selection) *Selection {
436 return s.wrapAllNodes(sel.Nodes...)
437 }
438
439
440
441
442
443
444 func (s *Selection) WrapAllHtml(htmlStr string) *Selection {
445 var context *html.Node
446 var nodes []*html.Node
447 if len(s.Nodes) > 0 {
448 context = s.Nodes[0]
449 if context.Parent != nil {
450 nodes = parseHtmlWithContext(htmlStr, context)
451 } else {
452 nodes = parseHtml(htmlStr)
453 }
454 }
455 return s.wrapAllNodes(nodes...)
456 }
457
458 func (s *Selection) wrapAllNodes(ns ...*html.Node) *Selection {
459 if len(ns) > 0 {
460 return s.WrapAllNode(ns[0])
461 }
462 return s
463 }
464
465
466
467
468
469
470 func (s *Selection) WrapAllNode(n *html.Node) *Selection {
471 if s.Size() == 0 {
472 return s
473 }
474
475 wrap := cloneNode(n)
476
477 first := s.Nodes[0]
478 if first.Parent != nil {
479 first.Parent.InsertBefore(wrap, first)
480 first.Parent.RemoveChild(first)
481 }
482
483 for c := getFirstChildEl(wrap); c != nil; c = getFirstChildEl(wrap) {
484 wrap = c
485 }
486
487 newSingleSelection(wrap, s.document).AppendSelection(s)
488
489 return s
490 }
491
492
493
494
495
496
497 func (s *Selection) WrapInner(selector string) *Selection {
498 return s.WrapInnerMatcher(compileMatcher(selector))
499 }
500
501
502
503
504
505
506 func (s *Selection) WrapInnerMatcher(m Matcher) *Selection {
507 return s.wrapInnerNodes(m.MatchAll(s.document.rootNode)...)
508 }
509
510
511
512
513
514
515 func (s *Selection) WrapInnerSelection(sel *Selection) *Selection {
516 return s.wrapInnerNodes(sel.Nodes...)
517 }
518
519
520
521
522
523
524 func (s *Selection) WrapInnerHtml(htmlStr string) *Selection {
525 nodesMap := make(map[string][]*html.Node)
526 for _, context := range s.Nodes {
527 nodes, found := nodesMap[nodeName(context)]
528 if !found {
529 nodes = parseHtmlWithContext(htmlStr, context)
530 nodesMap[nodeName(context)] = nodes
531 }
532 newSingleSelection(context, s.document).wrapInnerNodes(cloneNodes(nodes)...)
533 }
534 return s
535 }
536
537
538
539
540
541
542 func (s *Selection) WrapInnerNode(n *html.Node) *Selection {
543 return s.wrapInnerNodes(n)
544 }
545
546 func (s *Selection) wrapInnerNodes(ns ...*html.Node) *Selection {
547 if len(ns) == 0 {
548 return s
549 }
550
551 s.Each(func(i int, s *Selection) {
552 contents := s.Contents()
553
554 if contents.Size() > 0 {
555 contents.wrapAllNodes(ns...)
556 } else {
557 s.AppendNodes(cloneNode(ns[0]))
558 }
559 })
560
561 return s
562 }
563
564 func parseHtml(h string) []*html.Node {
565
566
567 nodes, err := html.ParseFragment(strings.NewReader(h), &html.Node{Type: html.ElementNode})
568 if err != nil {
569 panic("goquery: failed to parse HTML: " + err.Error())
570 }
571 return nodes
572 }
573
574 func parseHtmlWithContext(h string, context *html.Node) []*html.Node {
575
576
577 nodes, err := html.ParseFragment(strings.NewReader(h), context)
578 if err != nil {
579 panic("goquery: failed to parse HTML: " + err.Error())
580 }
581 return nodes
582 }
583
584
585 func getFirstChildEl(n *html.Node) *html.Node {
586 c := n.FirstChild
587 for c != nil && c.Type != html.ElementNode {
588 c = c.NextSibling
589 }
590 return c
591 }
592
593
594 func cloneNodes(ns []*html.Node) []*html.Node {
595 cns := make([]*html.Node, 0, len(ns))
596
597 for _, n := range ns {
598 cns = append(cns, cloneNode(n))
599 }
600
601 return cns
602 }
603
604
605
606 func cloneNode(n *html.Node) *html.Node {
607 nn := &html.Node{
608 Type: n.Type,
609 DataAtom: n.DataAtom,
610 Data: n.Data,
611 Attr: make([]html.Attribute, len(n.Attr)),
612 }
613
614 copy(nn.Attr, n.Attr)
615 for c := n.FirstChild; c != nil; c = c.NextSibling {
616 nn.AppendChild(cloneNode(c))
617 }
618
619 return nn
620 }
621
622 func (s *Selection) manipulateNodes(ns []*html.Node, reverse bool,
623 f func(sn *html.Node, n *html.Node)) *Selection {
624
625 lasti := s.Size() - 1
626
627
628
629
630 if reverse {
631 for i, j := 0, len(ns)-1; i < j; i, j = i+1, j-1 {
632 ns[i], ns[j] = ns[j], ns[i]
633 }
634 }
635
636 for i, sn := range s.Nodes {
637 for _, n := range ns {
638 if i != lasti {
639 f(sn, cloneNode(n))
640 } else {
641 if n.Parent != nil {
642 n.Parent.RemoveChild(n)
643 }
644 f(sn, n)
645 }
646 }
647 }
648
649 return s
650 }
651
652
653
654
655
656 func (s *Selection) eachNodeHtml(htmlStr string, isParent bool, mergeFn func(n *html.Node, nodes []*html.Node)) *Selection {
657
658 nodeCache := make(map[string][]*html.Node)
659 var context *html.Node
660 for _, n := range s.Nodes {
661 if isParent {
662 context = n.Parent
663 } else {
664 if n.Type != html.ElementNode {
665 continue
666 }
667 context = n
668 }
669 if context != nil {
670 nodes, found := nodeCache[nodeName(context)]
671 if !found {
672 nodes = parseHtmlWithContext(htmlStr, context)
673 nodeCache[nodeName(context)] = nodes
674 }
675 mergeFn(n, cloneNodes(nodes))
676 }
677 }
678 return s
679 }
680
View as plain text