Go中的XML解码 [英] XML Decoding in Go

查看:311
本文介绍了Go中的XML解码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  package main 

import(
encoding / xml
fmt
net / http


类型Channel结构{
Items Item
}

类型结构struct {
标题字符串`xml:标题`
链接字符串`xml:link`
描述字符串`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 {
decode := xml.NewDecoder(res.Body)

err = decoded.Decode(items)

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

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



$ b $ p
$ b

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

 <$ c $标题:

结构看起来是空的,但我看不出它为什么没有被填充与XML数据。

解决方案

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



您需要修改您的字段标记,以帮助指导您通过
Channel 结构将XML绑定引导至 Item 结构:

 类型Channel结构{
Items [] Item `xml:频道>项目`
}

类型项目结构{
标题字符串`xml:标题`
链接字符串`xml:链接`
描述字符串`xml:描述`
}

encoding / xml.Unmarshal() ,第七个项目符号适用于:


如果XML元素包含名称匹配$ b $的子元素b格式为a或a> b> c的标签前缀,解组
将desc最后到XML结构中查找带有
给定名称的元素,并将最内层元素映射到该结构
字段。以>开头的标签相当于一个以字段名称开头的
,后跟>。


在您的情况下,您希望通过顶层< rss> 元素的< channel> 元素进行下载找到每个< item> 元素。但是,请注意,我们不需要 - 实际上不能指定 Channel 结构应该穿越顶层通过将项目字段的标记写入


$ b

  `xml:rss>频道>项目`

;提供给 Unmarshall()的结构已映射到顶层XML元素。



还要注意, code> Channel struct的项目字段应该是slice-of - 项目,不只是一个项目






您无法使提案生效。这是一个完整的列表,我发现它的工作原理是:人们可以期待:

  package main 

import(
encoding / xml
fmt
net / http
os


类型Channel结构{
Items []项目`xml:频道>项目``
}

类型项目结构{
标题字符串`xml:标题`
链接字符串`xml:link`
描述字符串`xml:description`
}

func main(){
if res,err:= http获得( http://www.reddit.com/r/google.xml); err!= nil {
fmt.Println(Error retrieval resources:,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)
}
}
}


I've been playing about with Go's XML package and cannot see what is wrong with the following code.

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)
    }
}

The above code runs without any errors and prints to the terminal:

Title:

The struct seems empty but I can't see why it isn't getting populated with the XML data.

解决方案

Your program comes close, but needs to specify just a little bit more context to match the XML document.

You need to revise your field tags to help guide the XML binding down through your Channel structure to your Item structure:

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

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

Per the documentation for encoding/xml.Unmarshal(), the seventh bullet item applies here:

If the XML element contains a sub-element whose name matches the prefix of a tag formatted as "a" or "a>b>c", unmarshal will descend into the XML structure looking for elements with the given names, and will map the innermost elements to that struct field. A tag starting with ">" is equivalent to one starting with the field name followed by ">".

In your case, you're looking to descend through the top-level <rss> element's <channel> elements to find each <item> element. Note, though, that we don't need to—an in fact can't—specify that the Channel struct should burrow through the top-level <rss> element by writing the Items field's tag as

`xml:"rss>channel>item"`

That context is implicit; the struct supplied to Unmarshall() already maps to the top-level XML element.

Note too that your Channel struct's Items field should be of type slice-of-Item, not just a single Item.


You mentioned that you're having trouble getting the proposal to work. Here's a complete listing that I find works as one would expect:

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)
        }
    }
}

这篇关于Go中的XML解码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆