为什么 len on x/net/html Token().Attr 在这里为空切片返回一个非零值?

我正在使用 Golang 中的内置html库。下面是重现问题的代码:


package main


import (

    "fmt"

    "log"

    "net/http"


    "golang.org/x/net/html"

)


const url = "https://google.com"


func main() {

    resp, err := http.Get(url)

    if err != nil {

        log.Fatal(err)

    }

    defer resp.Body.Close()


    if resp.StatusCode != 200 {

        log.Fatalf("Status code error: %d %s", resp.StatusCode, resp.Status)

    }


    h := html.NewTokenizer(resp.Body)


    for {

        if h.Next() == html.ErrorToken {

            break

        }


        l := len(h.Token().Attr)


        if l != 0 {

            fmt.Println("=======")

            fmt.Println("Length", l) // greater than 0

            fmt.Println("Attr", h.Token().Attr) // empty all the times

        }

    }

}


这是输出的样子


=======

Length 2

Attr []

typeof Attr []html.Attribute

=======

Length 8

Attr []

typeof Attr []html.Attribute

=======

Length 1

Attr []

typeof Attr []html.Attribute

=======

Length 1

Attr []

typeof Attr []html.Attribute


去版本


go version go1.17.7 linux/amd64

为什么 Go 认为的长度h.Token().Attrh.Token().Attr当 the为空时这里的长度不为零?


PS:保存输出h.Token().Attr并将其用于len打印内容使一切正常


慕桂英546537
浏览 98回答 3
3回答

月关宝盒

Tokenizer 有一种有趣的界面,你不能Token()在两次调用之间多次调用Next(). 正如文档所说:在 EBNF 表示法中,每个令牌的有效调用序列是:Next {Raw} [ Token | Text | TagName {TagAttr} ]也就是说:调用后Next()可能调用Raw()零次或多次;那么你可以:调用Token()一次,调用Text()一次,调用TagName()一次,然后调用TagAttr()零次或多次(大概是根本不调用,因为您不关心属性,或者调用的次数足以检索所有属性)。或者什么也不做(也许你正在跳过令牌)。乱序调用的结果是不确定的,因为这些方法修改了内部状态——它们不是纯粹的访问器。在您的第一个片段中,您在Token()两次调用之间调用了多次Next(),因此结果无效。所有属性都由第一次调用使用,而不会由后面的调用返回。

沧海一幻觉

(*Tokenizer).Token()每次都返回一个新的令牌,它再次有一个新的 []Attr,在这里.Token() ,下一次调用中的分词器在第 1145 行的开始和结束是相同的数字,所以它不会进入这个循环,所以下次 attr 将为空。

智慧大石

不是空的,您只需要遍历它并查看值。package mainimport (&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "strings"&nbsp; &nbsp; "golang.org/x/net/html")func main() {&nbsp; &nbsp; body := `<html><body onload="fool()"></body></html>`&nbsp; &nbsp; h := html.NewTokenizer(strings.NewReader(body))&nbsp; &nbsp; for {&nbsp; &nbsp; &nbsp; &nbsp; if h.Next() == html.ErrorToken {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; attr := h.Token().Attr&nbsp; &nbsp; &nbsp; &nbsp; l := len(attr)&nbsp; &nbsp; &nbsp; &nbsp; if l != 0 {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("=======")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("Length", l) // greater than 0&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for i, a := range attr {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf("Attr %d %v\n", i, a)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}游乐场:https ://go.dev/play/p/lzEdppsURl0
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go