为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
慕桂英546537 2023-01-03 15:59:27
我正在使用 Golang 中的内置html库。下面是重现问题的代码:package mainimport (    "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 2Attr []typeof Attr []html.Attribute=======Length 8Attr []typeof Attr []html.Attribute=======Length 1Attr []typeof Attr []html.Attribute=======Length 1Attr []typeof Attr []html.Attribute去版本go version go1.17.7 linux/amd64为什么 Go 认为的长度h.Token().Attrh.Token().Attr当 the为空时这里的长度不为零?PS:保存输出h.Token().Attr并将其用于len打印内容使一切正常
查看完整描述

3 回答

?
月关宝盒

TA贡献1772条经验 获得超5个赞

Tokenizer 有一种有趣的界面,你不能Token()在两次调用之间多次调用Next(). 正如文档所说:

在 EBNF 表示法中,每个令牌的有效调用序列是:
Next {Raw} [ Token | Text | TagName {TagAttr} ]

也就是说:调用后Next()可能调用Raw()零次或多次;那么你可以

  • 调用Token()一次,

  • 调用Text()一次,

  • 调用TagName()一次,然后调用TagAttr()零次或多次(大概是根本不调用,因为您不关心属性,或者调用的次数足以检索所有属性)。

  • 或者什么也不做(也许你正在跳过令牌)。

乱序调用的结果是不确定的,因为这些方法修改了内部状态——它们不是纯粹的访问器。在您的第一个片段中,您在Token()两次调用之间调用了多次Next(),因此结果无效。所有属性都由第一次调用使用,而不会由后面的调用返回。


查看完整回答
反对 回复 2023-01-03
?
沧海一幻觉

TA贡献1824条经验 获得超5个赞

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



查看完整回答
反对 回复 2023-01-03
?
智慧大石

TA贡献1946条经验 获得超3个赞

不是空的,您只需要遍历它并查看值。


package main


import (

    "fmt"

    "strings"


    "golang.org/x/net/html"

)


func main() {

    body := `

<html>

<body onload="fool()">

</body>

</html>

`

    h := html.NewTokenizer(strings.NewReader(body))


    for {

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

            break

        }


        attr := h.Token().Attr

        l := len(attr)


        if l != 0 {

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

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

            for i, a := range attr {

                fmt.Printf("Attr %d %v\n", i, a)

            }

        }

    }

}


游乐场:https ://go.dev/play/p/lzEdppsURl0


查看完整回答
反对 回复 2023-01-03
  • 3 回答
  • 0 关注
  • 95 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信