我正在尝试使用The go编程语言书来解决这个问题: 可以在此处找到起始代码:exercise。
我需要做什么:
修改forEachNode,以便pre和post函数返回一个布尔结果,指示是否继续遍历。使用它来编写具有以下签名的函数ElementByID,该签名查找具有指定id属性的第一个HTML元素。一旦找到匹配项,该函数应立即停止遍历。
签名:func ElementByID(doc *html.Node, id string) *html.Node
我做了什么:
func ElementByID(doc *html.Node, id string) *html.Node {
if doc.Data == id {
fmt.Printf(" %s: %s\n", "found", doc.Data)
return doc
}
return nil
}
func startElement(n *html.Node) bool {
if n.Type == html.ElementNode {
if ElementById(n, "a") != nil {
return true
}
fmt.Printf("%*s<%s>\n", depth*2, "", n.Data)
depth++
}
return false
}
func endElement(n *html.Node) bool {
if n.Type == html.ElementNode {
if ElementById(n, "a") != nil {
return true
}
depth--
fmt.Printf("%*s</%s>\n", depth*2, "", n.Data)
}
return false
}
上面是对吗?还是我错过了什么?如何停止遍历元素的遍历?
forEachNode是相同的,只有前后签名被更改为返回一个bool。
答案 0 :(得分:1)
您可以创建closure和“关闭”found
节点。示例如下。
修改forEachNode,使pre和post函数返回一个布尔结果,指示是否继续遍历。:
func forEachNode(n *html.Node, pre, post func(n *html.Node) bool) {
if pre != nil && !pre(n) {
return
}
for c := n.FirstChild; c != nil; c = c.NextSibling {
forEachNode(c, pre, post)
}
if post != nil && !post(n) {
return
}
}
使用它来编写具有以下签名的函数ElementByID,该签名查找具有指定id属性的第一个HTML元素。一旦找到匹配项,该函数应立即停止遍历。
func ElementByID(doc *html.Node, id string) *html.Node {
var found *html.Node
pre := func(n *html.Node) bool {
for _, a := range n.Attr {
if a.Key == "id" && a.Val == id {
found = n // memorize matching node
return false // stop traversing
}
}
return true
}
forEachNode(doc, pre, nil)
return found
}