前言
網上找不到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