ch5/ch5-05 #144
Replies: 8 comments
-
练习5.7 内容暂时没输出package main
import (
"Study/src/study/day7Function/HtmlTools"
"fmt"
"golang.org/x/net/html"
"log"
"net/http"
"reflect"
)
func main() {
// 同样的,函数可以作为参数传入另一个函数
// forEachNode针对每个结点x,都会调用pre(x)和post(x)。
// pre和post都是可选的。
// 遍历孩子结点之前,pre被调用
// 遍历孩子结点之后,post被调用
var forEachNode func(n *html.Node, pre, post func(n *html.Node))
forEachNode = func(n *html.Node, pre, post func(n *html.Node)) {
if pre != nil {
pre(n)
}
for c := n.FirstChild; c != nil; c = c.NextSibling {
forEachNode(c, pre, post)
}
if post != nil {
post(n)
}
}
var depth int
var ExcludeNodes []string = []string{
"link",
"img",
"meta",
}
// 断言
m, _ := ToMapSetStrictE(ExcludeNodes)
ExcludeNodesMap := m.(map[string]struct{})
startElemen := func(n *html.Node) {
if n.Type == html.ElementNode {
fmt.Printf("%*s<%s", depth*2, "", n.Data)
for _, attr := range n.Attr {
fmt.Printf(" %s=\"%s\"", attr.Key, attr.Val)
}
// 检测单节点
if _, ok := ExcludeNodesMap[n.Data]; ok {
fmt.Println(" />")
} else {
fmt.Println(">")
}
depth++
}
}
endElement := func(n *html.Node) {
if n.Type == html.ElementNode {
depth--
// 检测单节点
if _, ok := ExcludeNodesMap[n.Data]; !ok {
fmt.Printf("%*s</%s>\n", depth*2, "", n.Data)
}
}
}
forEachNode(HtmlTools.GetHtml(), startElemen, endElement)
}
// 借助一个空接口,使切片转为map
func ToMapSetStrictE(i interface{}) (interface{}, error) {
// check param
if i == nil {
return nil, fmt.Errorf("unable to converts %#v of type %T to map[interface{}]struct{}", i, i)
}
t := reflect.TypeOf(i)
kind := t.Kind()
if kind != reflect.Slice && kind != reflect.Array {
return nil, fmt.Errorf("the input %#v of type %T isn't a slice or array", i, i)
}
// execute the convert
v := reflect.ValueOf(i)
mT := reflect.MapOf(t.Elem(), reflect.TypeOf(struct{}{}))
mV := reflect.MakeMapWithSize(mT, v.Len())
for j := 0; j < v.Len(); j++ {
mV.SetMapIndex(v.Index(j), reflect.ValueOf(struct{}{}))
}
return mV.Interface(), nil
}
package HtmlTools
func GetHtml() *html.Node {
resp, err := http.Get("https://golang-china.github.io/gopl-zh/ch5/ch5-02.html")
if err != nil {
log.Fatal(err)
}
if resp.StatusCode != http.StatusOK {
err := resp.Body.Close()
if err != nil {
log.Fatal(err)
return nil
}
}
doc, err := html.Parse(resp.Body)
if err != nil {
log.Fatal(err)
return nil
}
return doc
} |
Beta Was this translation helpful? Give feedback.
-
练习5.8文件 /Practice5.8.gopackage main
import (
"Study/src/study/day7Function/HtmlTools"
"fmt"
"golang.org/x/net/html"
)
func main() {
// 手动清除ResultNode的内容
ResultNode = nil
ElementByID(HtmlTools.GetHtml(), pre, "a")
}
var ResultNode *html.Node = nil
func ElementByID(doc *html.Node, pre func(n *html.Node, id *string) bool, id string) *html.Node {
if doc != nil && ResultNode == nil {
ElementByID(doc.FirstChild, pre, id)
ElementByID(doc.NextSibling, pre, id)
} else {
return nil
}
if pre(doc, &id) {
return nil
}
return nil
}
func pre(n *html.Node, id *string) bool {
if n.Type == html.ElementNode && n.Data == *id {
fmt.Println(n.Data)
ResultNode = n
return true
}
return false
} 文件 /HtmlTools/Tools.gopackage HtmlTools
import (
"golang.org/x/net/html"
"log"
"net/http"
)
func GetHtml() *html.Node {
resp, err := http.Get("https://golang-china.github.io/gopl-zh/ch5/ch5-02.html")
if err != nil {
log.Fatal(err)
}
if resp.StatusCode != http.StatusOK {
err := resp.Body.Close()
if err != nil {
log.Fatal(err)
return nil
}
}
doc, err := html.Parse(resp.Body)
if err != nil {
log.Fatal(err)
return nil
}
return doc
} |
Beta Was this translation helpful? Give feedback.
-
练习5.9
|
Beta Was this translation helpful? Give feedback.
-
exercise 5.7func forEachNode(n *html.Node, pre, post func(n *html.Node, selfClosing bool)) {
selfClosing := n.Type == html.ElementNode && n.FirstChild == nil
if pre != nil {
pre(n, selfClosing)
}
for c := n.FirstChild; c != nil; c = c.NextSibling {
forEachNode(c, pre, post)
}
if post != nil {
post(n, selfClosing)
}
}
var depth int
func startElement(n *html.Node, selfClosing bool) {
if n.Type == html.ElementNode {
// %*s中的*会在字符串之前填充一些空格。
// 在例子中,每次输出会先填充depth*2数量的空格,再输出"",最后再输出HTML标签
getAttr := func(attr []html.Attribute) string {
var res string
for _, attr := range attr {
res += fmt.Sprintf(" %s=\"%s\"", attr.Key, attr.Val)
}
return res
}
if !selfClosing {
fmt.Printf("%*s<%s%s>\n", depth*2, "", n.Data, getAttr(n.Attr))
depth++
} else {
fmt.Printf("%*s<%s%s/>\n", depth*2, "", n.Data, getAttr(n.Attr))
}
}
}
func endElement(n *html.Node, selfClosing bool) {
if n.Type == html.ElementNode && !selfClosing {
depth--
fmt.Printf("%*s</%s>\n", depth*2, "", n.Data)
}
} |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
-
练习 5.9: 编写函数expand,将s中的"foo"替换为f("foo")的返回值。 |
Beta Was this translation helpful? Give feedback.
-
5.9 用标准库 package main
import (
"fmt"
"strings"
)
func main() {
var s string
fmt.Scanf("%s", &s)
s = expand(s, fun)
fmt.Println(s)
}
func expand(s string, f func(string) string) string {
s = strings.ReplaceAll(s, "foo", f("foo"))
return s
}
func fun(s string) string {
return "a"
} |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
ch5/ch5-05
中文版
https://golang-china.github.io/gopl-zh/ch5/ch5-05.html
Beta Was this translation helpful? Give feedback.
All reactions