XML 响应

虽然 JSON 已经是主流,但 XML 在一些老系统或者特定行业里还是占有一席之地的。Gin 返回 XML 响应同样简单。

基本 XML 响应

使用 c.XML() 方法返回 XML 格式数据:

package main

import (
    "net/http"
    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()
    
    r.GET("/xml", func(c *gin.Context) {
        c.XML(http.StatusOK, gin.H{
            "name": "张三",
            "age":  25,
            "city": "北京",
        })
    })
    
    r.Run(":8080")
}

返回的结果类似:

<map>
    <name>张三</name>
    <age>25</age>
    <city>北京</city>
</map>

使用结构体

和 JSON 一样,用结构体可以获得更好的类型控制和字段命名:

type UserXML struct {
    XMLName xml.Name `xml:"user"`
    ID      int      `xml:"id,attr"`
    Name    string   `xml:"name"`
    Email   string   `xml:"email"`
    Active  bool     `xml:"active"`
}

r.GET("/user/xml", func(c *gin.Context) {
    user := UserXML{
        ID:     1,
        Name:   "张三",
        Email:  "zhangsan@example.com",
        Active: true,
    }
    c.XML(http.StatusOK, user)
})

返回结果:

<user id="1">
    <name>张三</name>
    <email>zhangsan@example.com</email>
    <active>true</active>
</user>

通过 xml tag 可以灵活控制 XML 的结构,比如 xml:"id,attr" 把字段作为属性,xml:",chardata" 把字段作为元素的文本内容。

嵌套结构

XML 经常需要嵌套结构,这在 Go 里也很好处理:

type Address struct {
    City    string `xml:"city"`
    Street  string `xml:"street"`
    ZipCode string `xml:"zip_code"`
}

type Person struct {
    XMLName xml.Name `xml:"person"`
    Name    string   `xml:"name"`
    Address Address  `xml:"address"`
}

r.GET("/person", func(c *gin.Context) {
    person := Person{
        Name: "张三",
        Address: Address{
            City:    "北京",
            Street:  "长安街1号",
            ZipCode: "100000",
        },
    }
    c.XML(http.StatusOK, person)
})

XML 列表

返回列表数据时,需要定义一个包装结构:

type User struct {
    ID   int    `xml:"id"`
    Name string `xml:"name"`
}

type UserList struct {
    XMLName xml.Name `xml:"users"`
    Users   []User   `xml:"user"`
}

r.GET("/users/xml", func(c *gin.Context) {
    users := UserList{
        Users: []User{
            {ID: 1, Name: "张三"},
            {ID: 2, Name: "李四"},
            {ID: 3, Name: "王五"},
        },
    }
    c.XML(http.StatusOK, users)
})

设置响应头

有时候需要明确指定响应的 Content-Type:

r.GET("/custom/xml", func(c *gin.Context) {
    c.Header("Content-Type", "application/xml; charset=utf-8")
    c.XML(http.StatusOK, gin.H{
        "message": "自定义 Content-Type",
    })
})

小结

Gin 的 XML 响应使用起来和 JSON 几乎一样,主要区别在于结构体 tag 使用 xml 而不是 json。如果你的 API 需要对接老系统或者特定行业标准,XML 响应就能派上用场了。