1 回答

TA貢獻1765條經驗 獲得超5個贊
您的代碼不起作用,因為它采用文檔的第一個子元素,即元素,然后它采用其同級元素,從而導致函數以空的鏈接片結尾。htmlnil
詳細解釋:下面是一個示例代碼,
package main
import (
"fmt"
"log"
"strings"
"golang.org/x/net/html"
)
var i int = 0
func visit(links []string, n *html.Node) []string {
if n == nil {
return links
}
if n.Type == html.ElementNode && n.Data == "a" {
for _, a := range n.Attr {
if a.Key == "href" {
links = append(links, a.Val)
}
}
}
if i == 0 {
i++
return visit(links, n.FirstChild)
}
return visit(links, n.NextSibling)
}
func main() {
s := `<p>Links:</p><ul><li><a href="foo">Foo</a><li><a href="/bar/baz">BarBaz</a></ul>`
doc, err := html.Parse(strings.NewReader(s))
if err != nil {
log.Fatal(err)
}
links := visit([]string{}, doc)
fmt.Println(links)
}
第一次調用訪問,
參數:
鏈接 = []
n = DocumentNode
在第一次調用中,i=0,因此它使用文檔節點的第一個子節點進行遞歸調用。visit
第二次訪問調用,
參數:
鏈接 = []
n = ElementNode (n.Data = “html”)
在第二次調用中,是元素節點。現在,對 元素節點的下一個同級節點進行第三次調用。這就是問題所在。元素節點沒有同級,因此將是 。nhtmlvisithtmlhtmlnnil
第三次調用訪問,
參數:
鏈接 = []
n = nil
因此,現在所有以遞歸方式調用的函數 3 函數調用都將返回,并且執行流將返回到,因此切片將保持為空。mainlinks
希望您理解。
編寫此功能的正確方法是通過您在問題中共享的循環,如下所示,
package main
import (
"fmt"
"log"
"strings"
"golang.org/x/net/html"
)
func visit(links []string, n *html.Node) []string {
if n.Type == html.ElementNode && n.Data == "a" {
for _, a := range n.Attr {
if a.Key == "href" {
links = append(links, a.Val)
}
}
}
for c := n.FirstChild; c != nil; c = c.NextSibling {
links = visit(links, c)
}
return links
}
func main() {
s := `<p>Links:</p><ul><li><a href="foo">Foo</a><li><a href="/bar/baz">BarBaz</a></ul>`
doc, err := html.Parse(strings.NewReader(s))
if err != nil {
log.Fatal(err)
}
links := visit([]string{}, doc)
fmt.Println(links)
}
在這里,循環通過檢查每個HTML元素的子元素來幫助遞歸地查找鏈接。如果其中一個HTML元素沒有同級元素,那么它將簡單地移動到其父級的下一個同級元素并檢查
- 1 回答
- 0 關注
- 92 瀏覽
添加回答
舉報