XML 绑定

虽然 JSON 更流行,但 XML 仍然在很多场景中使用。Gin 同样支持 XML 绑定。

基本用法

type User struct {
    XMLName xml.Name `xml:"user"`
    Name    string   `xml:"name"`
    Email   string   `xml:"email"`
}

r.POST("/users", func(c *gin.Context) {
    var user User
    if err := c.ShouldBindXML(&user); err != nil {
        c.JSON(400, gin.H{"error": err.Error()})
        return
    }

    c.JSON(200, user)
})

请求:

curl -X POST http://localhost:8080/users \
  -H "Content-Type: application/xml" \
  -d '<user><name>Alice</name><email>alice@example.com</email></user>'

XML 标签

type User struct {
    XMLName  xml.Name `xml:"user"`
    ID       int      `xml:"id,attr"`
    Name     string   `xml:"name"`
    Email    string   `xml:"email"`
    Address  string   `xml:"address>city"`
    Comments []string `xml:"comments>comment"`
}

标签选项

选项说明
xml:"name"元素名
xml:",attr"属性
xml:",chardata"字符数据
xml:",innerxml"原始 XML
xml:",comment"注释
xml:"a>b"嵌套路径

属性绑定

type Product struct {
    XMLName xml.Name `xml:"product"`
    ID      string   `xml:"id,attr"`
    Name    string   `xml:"name,attr"`
    Price   float64  `xml:"price,attr"`
}

r.POST("/products", func(c *gin.Context) {
    var product Product
    if err := c.ShouldBindXML(&product); err != nil {
        c.JSON(400, gin.H{"error": err.Error()})
        return
    }

    c.JSON(200, product)
})

请求:

<product id="123" name="iPhone" price="999.99">
</product>

嵌套元素

type Order struct {
    XMLName   xml.Name `xml:"order"`
    ID        string   `xml:"id"`
    Customer  Customer `xml:"customer"`
    Items     []Item   `xml:"items>item"`
}

type Customer struct {
    Name  string `xml:"name"`
    Email string `xml:"email"`
}

type Item struct {
    ProductID string  `xml:"product_id"`
    Quantity  int     `xml:"quantity"`
    Price     float64 `xml:"price"`
}

r.POST("/orders", func(c *gin.Context) {
    var order Order
    if err := c.ShouldBindXML(&order); err != nil {
        c.JSON(400, gin.H{"error": err.Error()})
        return
    }

    c.JSON(200, order)
})

请求:

<order>
    <id>ORD-001</id>
    <customer>
        <name>Alice</name>
        <email>alice@example.com</email>
    </customer>
    <items>
        <item>
            <product_id>P001</product_id>
            <quantity>2</quantity>
            <price>99.99</price>
        </item>
        <item>
            <product_id>P002</product_id>
            <quantity>1</quantity>
            <price>49.99</price>
        </item>
    </items>
</order>

返回 XML 响应

r.GET("/users/:id", func(c *gin.Context) {
    user := User{
        Name:  "Alice",
        Email: "alice@example.com",
    }

    c.XML(200, user)
})

完整示例

package main

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

type User struct {
    XMLName xml.Name `xml:"user"`
    ID      string   `xml:"id,attr"`
    Name    string   `xml:"name"`
    Email   string   `xml:"email"`
}

type CreateUserRequest struct {
    XMLName xml.Name `xml:"user"`
    Name    string   `xml:"name" binding:"required"`
    Email   string   `xml:"email" binding:"required,email"`
}

func main() {
    r := gin.Default()

    r.POST("/users", createUser)
    r.GET("/users/:id", getUser)

    r.Run(":8080")
}

func createUser(c *gin.Context) {
    var req CreateUserRequest
    if err := c.ShouldBindXML(&req); err != nil {
        c.XML(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    user := User{
        ID:    "123",
        Name:  req.Name,
        Email: req.Email,
    }

    c.XML(http.StatusCreated, user)
}

func getUser(c *gin.Context) {
    id := c.Param("id")

    user := User{
        ID:    id,
        Name:  "User " + id,
        Email: "user@example.com",
    }

    c.XML(http.StatusOK, user)
}

小结

这一章学习了:

  • XML 绑定的基本用法
  • XML 标签选项
  • 属性和嵌套元素
  • 返回 XML 响应