包含*html.Node的递归函数,用于打印html文档中的所有链接
我试图使用一个接受*HTML.Node作为参数的函数来打印HTML文档中的所有链接。我对Golang和*html.Node数据类型都是新手,以前从未使用过它们包含*html.Node的递归函数,用于打印html文档中的所有链接,html,go,recursion,tree,nodes,Html,Go,Recursion,Tree,Nodes,我试图使用一个接受*HTML.Node作为参数的函数来打印HTML文档中的所有链接。我对Golang和*html.Node数据类型都是新手,以前从未使用过它们 func visit(links []string, n *html.Node) []string { if n == nil { return links } if n.Type == html.ElementNode && n.Data == "a" {
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)
}
检查i==0
的if块的目的是确保回访(links,n.FirstChild)
只运行一次(第一次)和回访(links,n.NextSibling)
在以下迭代中运行。但是,链接
永远不会追加,并且总是返回一个空片段。我不理解代码中的错误
当使用for循环时,代码工作得非常好,但当我尝试使用递归时,代码会中断
for c := n.FirstChild; c != nil; c = c.NextSibling {
links = visit(links, c)
}
您的代码不起作用,因为它取文档的第一个子元素,即
html
元素,然后取其同级元素,即nil
,从而导致函数以空链接片段结束
详细说明:
下面是一个示例代码
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)
}
在这里,循环通过检查每个HTML元素的子元素来帮助递归地查找链接。如果其中一个HTML元素没有同级元素,那么它只需移动到其父元素的下一个同级元素并检查您问题中的变量
i
是否未定义?我已将main/func块外的变量i声明为全局变量
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)
}