前言

现在绝大多数系统已经都使用 json 格式来返回和传输数据。但实际中还是有一些客户需要返回 XML 数据做处理,而在这不服处理过程中最近遇到了两个小问题:

  1. 如何返回 xml 协议头?
  2. 如何返回小写的 <root> 节点?

如果我们像 JSON 格式一样使用 ctx.XML 方法直接返回数据的话就会遇到这样的问题。所以具体使用场景中没有像 JSON 一样那么容易直接使用 ctx.JSON 就可以完成,还需要做一些额外的处理。

如何返回协议头

第一个问题比较简单,就是返回的 xml 通常会有一个 header ,可能像下面这样

1
<?xml version="1.0" encoding="UTF-8"?>

但其实默认直接返回是没有的,于是就需要主动去写一次,解决方式也非常简单

1
2
3
4
5
6
7
8
9
import (
"encoding/xml"
)

func Controller(ctx *gin.Context) {
// ...
ctx.Writer.Write([]byte(xml.Header))
// ...
}

xml 库中默认就呀这个 header,所以直接用就可以了。

如何返回小写的 <root> 节点?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import (
"net/http"


"github.com/gin-gonic/gin"
)

type Resp struct {
Code string `xml:"code"`
Data string `xml:"data"`
}

func main() {
r := gin.New()
r.GET("/hello", func(ctx *gin.Context) {
resp := &Resp{
Data: "aaa",
Code: "bbb",
}
ctx.XML(http.StatusOK, resp)
})

err := r.Run(":8080")
if err != nil {
panic(err)
}
}

如果按照上述代码编写返回的时候数据就是

1
2
curl http://127.0.0.1:8080/hello
<Resp><code>bbb</code><data>aaa</data></Resp>

可以看到最外层返回的节点是 struct 的名称,而通常这不是我们想要的,我们需要指定最外层的 root 节点的名称。

经过踩坑,发现在 golang 中,可以在通过 xml.Name 来实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package main

import (
"net/http"

"encoding/xml"

"github.com/gin-gonic/gin"
)

type Resp struct {
XMLName xml.Name `xml:"root"`
Code string `xml:"code"`
Data string `xml:"data"`
}

func main() {
r := gin.New()
r.GET("/hello", func(ctx *gin.Context) {
resp := &Resp{
Data: "aaa",
Code: "bbb",
}
ctx.XML(http.StatusOK, resp)
})

err := r.Run(":8080")
if err != nil {
panic(err)
}
}

加上之后,返回的内容就会变成

1
2
curl http://127.0.0.1:8080/hello
<root><code>bbb</code><data>aaa</data></root>