6

我一直在玩 Go 的 XML 包,看不出下面的代码有什么问题。

package main

import (
    "encoding/xml"
    "fmt"
    "net/http"
) 

type Channel struct {
    Items Item
}

type Item struct {
    Title       string `xml:"title"`
    Link        string `xml:"link"`
    Description string `xml:"description"`
}

func main() {

    var items = new(Channel)
    res, err := http.Get("http://www.reddit.com/r/google.xml")

    if err != nil {
        fmt.Printf("Error: %v\n", err)
    } else {
        decoded := xml.NewDecoder(res.Body)

        err = decoded.Decode(items)

        if err != nil {
            fmt.Printf("Error: %v\n", err)
        }

        fmt.Printf("Title: %s\n", items.Items.Title)
    }
}

上面的代码运行没有任何错误并打印到终端:

Title:

该结构似乎是空的,但我不明白为什么它没有填充 XML 数据。

4

3 回答 3

5

我会像这样完全明确 - 命名所有 XML 部分

有关完整的工作示例,请参见操场

type Rss struct {
    Channel Channel `xml:"channel"`
}

type Channel struct {
    Title       string `xml:"title"`
    Link        string `xml:"link"`
    Description string `xml:"description"`
    Items       []Item `xml:"item"`
}

type Item struct {
    Title       string `xml:"title"`
    Link        string `xml:"link"`
    Description string `xml:"description"`
}
于 2013-09-29T19:23:25.587 回答
4

您的程序接近了,但只需要指定更多的上下文来匹配 XML 文档。

您需要修改您的字段标签以帮助引导 XML 绑定通过您的 Channel结构到您的Item结构:

type Channel struct {
    Items []Item `xml:"channel>item"`
}

type Item struct {
    Title       string `xml:"title"`
    Link        string `xml:"link"`
    Description string `xml:"description"`
}

根据的文档encoding/xml.Unmarshal(),第七个项目符号适用于此:

如果 XML 元素包含一个名称与格式为“a”或“a>b>c”的标记前缀匹配的子元素,则 unmarshal 将进入 XML 结构中查找具有给定名称的元素,并将映射该结构字段的最里面的元素。以“>”开头的标记等效于以字段名称开头后跟“>”的标记。

在您的情况下,您希望通过顶级<rss>元素的<channel>元素向下查找每个<item>元素。但是请注意,我们不需要——事实上也不能——Channel通过将字段的标记<rss>写为Items

`xml:"rss>channel>item"`

该上下文是隐含的;提供给Unmarshall()已经映射到顶级 XML 元素的结构。

还要注意,您的Channel结构Items字段应该是 slice-of- 类型Item,而不仅仅是单个Item.


您提到您在使提案生效时遇到了麻烦。这是一个完整的清单,我发现它可以按预期工作:

package main

import (
    "encoding/xml"
    "fmt"
    "net/http"
    "os"
) 

type Channel struct {
    Items []Item `xml:"channel>item"`
}

type Item struct {
    Title       string `xml:"title"`
    Link        string `xml:"link"`
    Description string `xml:"description"`
}

func main() {
    if res, err := http.Get("http://www.reddit.com/r/google.xml"); err != nil {
        fmt.Println("Error retrieving resource:", err)
        os.Exit(1)
    } else {
        channel := Channel{}
        if err := xml.NewDecoder(res.Body).Decode(&channel); err != nil {
            fmt.Println("Error:", err)
            os.Exit(1)
        } else if len(channel.Items) != 0 {
            item := channel.Items[0]
            fmt.Println("First title:", item.Title)
            fmt.Println("First link:", item.Link)
            fmt.Println("First description:", item.Description)
        }
    }
}
于 2013-09-29T19:01:07.560 回答
0

如今,Reddit RSS 提要似乎已更改为atom类型。这意味着常规解析将不再起作用。go-rss的原子功能可以解析这样的提要:

//Feed struct for RSS
type Feed struct {
  Entry []Entry `xml:"entry"`
}

//Entry struct for each Entry in the Feed
type Entry struct {
  ID      string `xml:"id"`
  Title   string `xml:"title"`
  Updated string `xml:"updated"`
}

//Atom parses atom feeds
func Atom(resp *http.Response) (*Feed, error) {
  defer resp.Body.Close()
  xmlDecoder := xml.NewDecoder(resp.Body)
  xmlDecoder.CharsetReader = charset.NewReader
  feed := Feed{}
  if err := xmlDecoder.Decode(&feed); err != nil {
      return nil, err
  }
  return &feed, nil
}
于 2020-04-04T22:24:49.900 回答