前言
网上找不到5.1的解答参考,所以只能手动写了一个。仅供参考。
补充5.2到5.4
题目
练习 5.1:修改findlinks代码中遍历n.FirstChild链表的部分,将循环调用visit,改成递归调用。
练习 5.2: 编写函数,记录在HTML树中出现的同名元素的次数。
练习 5.3: 编写函数输出所有text结点的内容。注意不要访问
代码
package main
import (
"fmt"
"os"
"io"
"golang.org/x/net/html"
"html/template"
"log"
)
type NodeCount map[string]int
const templ = `
--------------------------------------
| HTML NODES COUNT |
--------------------------------------
| |
{{- range $key, $value := . }}
| Type: {{ $key | printf "%-15s" }} Count: {{ $value | printf "%-4d" }} |
{{- end }}
| |
--------------------------------------
`
func (nc NodeCount) Fprint(w io.Writer) {
t := template.Must(template.New("escape").Parse(templ))
if err := t.Execute(w, nc); err != nil {
log.Fatal(err)
}
}
func main() {
doc, err := html.Parse(os.Stdin)
if err != nil {
fmt.Fprintf(os.Stderr, "findlinks1: %v\n", err)
os.Exit(1)
}
for _, link := range visit(nil, doc) {
fmt.Println(link)
}
// 5.2 output
nodeCount := NodeCount{}
count(&nodeCount, doc)
nodeCount.Fprint(os.Stdout)
// 5.3 output
for _, text := range visitText(nil, doc) {
fmt.Println(text)
}
// 5.4 output
for _, link := range visitExtend(nil, doc) {
fmt.Println(link)
}
}
// 5.1 visit appends to links each link found in n and returns the result.
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)
}
}
}
/* for c := n.FirstChild; c != nil; c = c.NextSibling {
links = visit(links, c)
} */
links = visit(links, n.FirstChild)
links = visit(links, n.NextSibling)
return links
}
// 5.2
func count(nc *NodeCount, n *html.Node) {
if n == nil {
return
}
if n.Type == html.ElementNode {
(*nc)[n.Data]++
}
count(nc, n.FirstChild)
count(nc, n.NextSibling)
}
//5.3
func visitText(texts []string, n *html.Node) []string {
if n == nil || n.Data == "script" || n.Data == "style" {
return texts
}
if n.Type == html.TextNode {
texts = append(texts, n.Data)
}
texts = visitText(texts, n.FirstChild)
texts = visitText(texts, n.NextSibling)
return texts
}
// 5.4
var visitData = map[string]int{
"a": 1,
"img": 1,
"link": 1,
"script": 1,
}
func visitExtend(links []string, n *html.Node) []string {
if n == nil {
return links
}
if n.Type == html.ElementNode {
if _, v := visitData[n.Data]; v {
for _, a := range n.Attr {
if a.Key == "href" {
links = append(links, a.Val)
}
}
}
}
links = visitExtend(links, n.FirstChild)
links = visitExtend(links, n.NextSibling)
return links
}
测试
https://golang.org/ 上不去,改用go语言中文网代替
go build gopl.io/ch1/fetch
go build gopl.io/ch5/findlinks1
fetch https://studygolang.com/ | findlinks1
前面几条展示如下。(经过对比,原来的写法结果与修改递归的结果一致)
/
/topics
/articles
/projects
/resources
/books
/go/weekly
https://course.studygolang.com
/dl
#
http://docs.studygolang.com
http://docscn.studygolang.com
参考:
https://github.com/ivanbeldad/the-go-programming-language/blob/master/ch05/ex02/main.go