-
Notifications
You must be signed in to change notification settings - Fork 0
FxJSON 使用指南(中文)
CloudZA edited this page Sep 4, 2025
·
4 revisions
FxJSON 是一个专为 Go 语言设计的高性能 JSON 解析库,它让 JSON 处理变得快速、安全、简单。可以把它想象成标准 JSON 库的超级版本!
传统方式(标准库):
// 需要大量错误处理和内存分配
var data map[string]interface{}
if err := json.Unmarshal(jsonBytes, &data); err != nil {
// 处理错误
}
name, ok := data["name"].(string)
if !ok {
name = "未知"
}FxJSON 方式:
// 简单、快速、安全
node := fxjson.FromBytes(jsonBytes)
name := node.Get("name").StringOr("未知") // 一行代码,不会出错!- 67 倍更快的数组处理
- 20 倍更快的对象遍历
- 零内存分配的基础操作
- 内置安全性和默认值
go get github.com/icloudza/fxjsonpackage main
import (
"fmt"
"github.com/icloudza/fxjson"
)
func main() {
// 第1步:解析 JSON 字节数据
jsonData := []byte(`{
"name": "小明",
"age": 25,
"active": true
}`)
// 第2步:从 JSON 创建节点
node := fxjson.FromBytes(jsonData)
// 第3步:安全地提取值(带默认值)
name := node.Get("name").StringOr("未知")
age := node.Get("age").IntOr(0)
active := node.Get("active").BoolOr(false)
fmt.Printf("%s 今年 %d 岁(活跃:%v)\n", name, age, active)
// 输出:小明 今年 25 岁(活跃:true)
}-
无需错误处理 -
StringOr(),IntOr(),BoolOr()提供安全的默认值 - 类型安全 - 自动类型转换和回退
- 代码简洁 - 简单易读的 API
- 高性能 - 比标准库更快
Node 是 FxJSON 的核心类型 - 把它想象成任何 JSON 值的智能包装器。无论你处理的是对象、数组、字符串、数字、布尔值还是 null,它们都用 Node 来表示。
jsonData := []byte(`{
"name": "小李",
"age": 30,
"hobbies": ["阅读", "编程"],
"address": {"city": "北京"}
}`)
root := fxjson.FromBytes(jsonData)
// 每次字段访问都返回一个 Node
nameNode := root.Get("name") // 包含 "小李" 的 Node
ageNode := root.Get("age") // 包含 30 的 Node
hobbiesNode := root.Get("hobbies") // 包含 ["阅读", "编程"] 的 Node传统 JSON 的问题:
// 传统方式 - 大量的错误检查
var data map[string]interface{}
json.Unmarshal(jsonBytes, &data)
name, ok := data["name"].(string)
if !ok {
name = "默认值"
}FxJSON 的解决方案:
// FxJSON 方式 - 简单且安全
node := fxjson.FromBytes(jsonBytes)
name := node.Get("name").StringOr("默认值") // 一行代码,不会出错!对于嵌套的 JSON,使用点符号路径:
// 不用链式调用多个 Get()
city := root.Get("address").Get("city").StringOr("")
// 使用路径让代码更清晰
city := root.GetPath("address.city").StringOr("")
// 数组路径也支持
jsonData := []byte(`{"users": [{"name": "张三"}, {"name": "李四"}]}`)
node := fxjson.FromBytes(jsonData)
secondUser := node.GetPath("users[1].name").StringOr("") // "李四"JSON 对象就像 Go 的 map - 键值对的集合:
// 用户数据示例
userJSON := []byte(`{
"id": 12345,
"name": "王小明",
"email": "wangxm@example.com",
"active": true,
"profile": {
"city": "上海",
"age": 28
}
}`)
user := fxjson.FromBytes(userJSON)
// 访问基本字段
id := user.Get("id").IntOr(0)
name := user.Get("name").StringOr("未知")
email := user.Get("email").StringOr("")
active := user.Get("active").BoolOr(false)
// 访问嵌套字段(两种方法)
city1 := user.Get("profile").Get("city").StringOr("") // 方法1
city2 := user.GetPath("profile.city").StringOr("") // 方法2(更简洁)
// 检查字段是否存在
if user.HasKey("email") {
fmt.Println("用户有邮箱地址")
}
// 获取对象的所有键
keys := user.GetAllKeys()
fmt.Println("用户字段:", keys) // [id, name, email, active, profile]JSON 数组是有序的值列表:
// 购物车示例
cartJSON := []byte(`{
"items": [
{"name": "笔记本电脑", "price": 5999},
{"name": "鼠标", "price": 99},
{"name": "键盘", "price": 299}
],
"tags": ["数码产品", "电脑配件"]
}`)
cart := fxjson.FromBytes(cartJSON)
items := cart.Get("items")
// 获取数组长度
count := items.Len()
fmt.Printf("购物车有 %d 件商品\n", count) // 购物车有 3 件商品
// 通过索引访问数组元素
firstItem := items.Index(0) // 获取第一个商品
firstItemName := firstItem.Get("name").StringOr("")
firstItemPrice := firstItem.Get("price").IntOr(0)
// 遍历数组(高性能方法)
var total int
items.ArrayForEach(func(index int, item fxjson.Node) bool {
name := item.Get("name").StringOr("")
price := item.Get("price").IntOr(0)
total += price
fmt.Printf("%d. %s: ¥%d\n", index+1, name, price)
return true // 继续下一个元素
})
fmt.Printf("总计: ¥%d\n", total)tags := cart.Get("tags")
// 获取第一个和最后一个元素
first := tags.First().StringOr("") // "数码产品"
last := tags.Last().StringOr("") // "电脑配件"
// 转换为 Go 切片进行高级操作
if tagList, err := tags.ToStringSlice(); err == nil {
for i, tag := range tagList {
fmt.Printf("标签 %d: %s\n", i+1, tag)
}
}FxJSON 自动处理类型检查和转换:
// JSON 中的混合类型
mixedJSON := []byte(`{
"name": "小张",
"age": 30,
"height": 1.75,
"active": true,
"skills": ["Go", "JavaScript"],
"address": {"city": "深圳"}
}`)
data := fxjson.FromBytes(mixedJSON)
// 带默认值的安全转换(推荐)
name := data.Get("name").StringOr("未知") // 字符串
age := data.Get("age").IntOr(0) // 整数
height := data.Get("height").FloatOr(0.0) // 浮点数
active := data.Get("active").BoolOr(false) // 布尔值
skills := data.Get("skills") // 数组
address := data.Get("address") // 对象
// 处理前检查类型(可选)
if skills.IsArray() {
fmt.Printf("用户有 %d 项技能\n", skills.Len())
}
if address.IsObject() {
city := address.Get("city").StringOr("未知")
fmt.Printf("用户住在 %s\n", city)
}FxJSON 最大的优势之一是带默认值的安全提取:
// 这些操作永远不会 panic 或出错
unknownField := data.Get("不存在的字段")
safeString := unknownField.StringOr("默认值") // "默认值"
safeNumber := unknownField.IntOr(-1) // -1
safeBool := unknownField.BoolOr(false) // false
fmt.Printf("安全值: %s, %d, %v\n", safeString, safeNumber, safeBool)FxJSON 包含常用验证器,让数据验证变得简单:
// 用户注册表单数据
formData := []byte(`{
"email": "user@example.com",
"website": "https://mysite.com",
"phone": "+86-138-0013-8000",
"id": "123e4567-e89b-12d3-a456-426614174000"
}`)
form := fxjson.FromBytes(formData)
// 验证邮箱
if form.Get("email").IsValidEmail() {
fmt.Println("✅ 邮箱格式正确")
}
// 验证网址
if form.Get("website").IsValidURL() {
fmt.Println("✅ 网址格式正确")
}
// 验证手机号
if form.Get("phone").IsValidPhone() {
fmt.Println("✅ 手机号格式正确")
}
// 验证 UUID
if form.Get("id").IsValidUUID() {
fmt.Println("✅ ID 是有效的 UUID")
}userData := []byte(`{
"name": " 张大伟 ",
"bio": "软件开发工程师",
"website": "https://zhangdawei.dev"
}`)
user := fxjson.FromBytes(userData)
name := user.Get("name")
// 内置字符串操作
trimmed, _ := name.Trim() // "张大伟"(去除空格)
upper, _ := name.ToUpper() // " 张大伟 "(转大写)
lower, _ := name.ToLower() // " 张大伟 "(转小写)
website := user.Get("website")
// 字符串检查
if website.StartsWith("https://") {
fmt.Println("✅ 使用安全网址")
}
if website.Contains("zhangdawei") {
fmt.Println("✅ 个人网站")
}高效获取多个值:
orderJSON := []byte(`{
"id": "ORDER-123",
"customer": {"name": "李小花", "email": "li@example.com"},
"total": 199.99
}`)
order := fxjson.FromBytes(orderJSON)
// 一次获取多个值
values := order.GetMultiple(
"id",
"customer.name",
"customer.email",
"total",
)
orderId := values[0].StringOr("")
customerName := values[1].StringOr("未知")
email := values[2].StringOr("")
total := values[3].FloatOr(0.0)
fmt.Printf("订单 %s: %s (¥%.2f)\n", orderId, customerName, total)
// 检查所有必需字段是否存在
required := []string{"id", "customer.name", "total"}
if order.HasAllPaths(required...) {
fmt.Println("✅ 所有必需字段都存在")
}查找和过滤数组元素:
productsJSON := []byte(`{
"products": [
{"id": 1, "name": "笔记本电脑", "price": 5999, "inStock": true},
{"id": 2, "name": "鼠标", "price": 99, "inStock": false},
{"id": 3, "name": "键盘", "price": 299, "inStock": true}
]
}`)
catalog := fxjson.FromBytes(productsJSON)
products := catalog.Get("products")
// 查找第一个有库存的产品
_, firstInStock, found := products.FindInArray(func(idx int, product fxjson.Node) bool {
return product.Get("inStock").BoolOr(false)
})
if found {
name := firstInStock.Get("name").StringOr("")
fmt.Printf("第一个有库存的商品: %s\n", name)
}
// 过滤出价格低于 1000 的产品
affordable := products.FilterArray(func(idx int, product fxjson.Node) bool {
return product.Get("price").IntOr(0) < 1000
})
fmt.Printf("找到 %d 个实惠商品\n", len(affordable))将 Go 结构体高性能地转换为 JSON:
package main
import (
"fmt"
"github.com/icloudza/fxjson"
)
// 定义用户结构体
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email,omitempty"`
Active bool `json:"active"`
Tags []string `json:"tags,omitempty"`
}
func main() {
user := User{
ID: 123,
Name: "小王",
Email: "xiaowang@example.com",
Active: true,
Tags: []string{"开发者", "Go语言"},
}
// 基本序列化(压缩)
jsonBytes, err := fxjson.Marshal(user)
if err != nil {
panic(err)
}
fmt.Println("压缩格式:", string(jsonBytes))
// 美化序列化
prettyJSON, err := fxjson.MarshalIndent(user, "", " ")
if err != nil {
panic(err)
}
fmt.Println("美化格式:\n", string(prettyJSON))
}// 自定义序列化选项
opts := fxjson.SerializeOptions{
Indent: " ", // 2空格缩进
EscapeHTML: true, // 转义HTML字符
SortKeys: true, // 按键排序
OmitEmpty: true, // 跳过空字段
FloatPrecision: 2, // 浮点数保留2位小数
}
customJSON, err := fxjson.MarshalWithOptions(user, opts)
if err != nil {
panic(err)
}
// 或使用预设
prettyJSON, _ := fxjson.MarshalWithOptions(user, fxjson.PrettySerializeOptions)
compactJSON, _ := fxjson.MarshalWithOptions(user, fxjson.DefaultSerializeOptions)// 超快序列化(无错误检查)
fastJSON := fxjson.FastMarshal(user)
fmt.Println("快速:", string(fastJSON))
// 批量序列化多个对象
users := []User{user1, user2, user3}
batchJSON, err := fxjson.BatchMarshalStructs([]interface{}{user1, user2, user3})// ❌ 对大数组慢(创建很多中间对象)
for i := 0; i < array.Len(); i++ {
item := array.Index(i)
// 处理元素
}
// ✅ 快速,零分配遍历
array.ArrayForEach(func(index int, item fxjson.Node) bool {
// 处理元素
return true // 继续遍历
})// ❌ 传统方式需要错误处理
value, err := node.Get("key").String()
if err != nil {
value = "默认值"
}
// ✅ FxJSON 方式使用默认值
value := node.Get("key").StringOr("默认值")// ❌ 冗长且容易出错
city := node.Get("user").Get("address").Get("city").StringOr("")
// ✅ 简洁易读
city := node.GetPath("user.address.city").StringOr("")// 对于频繁解析的 JSON,使用缓存
cache := fxjson.NewMemoryCache(100)
fxjson.EnableCaching(cache)
// 带缓存解析(后续解析会更快)
node := fxjson.FromBytesWithCache(jsonData, 5*time.Minute)func handleAPIResponse(responseBody []byte) {
response := fxjson.FromBytes(responseBody)
// 检查请求是否成功
if !response.Get("success").BoolOr(false) {
errorMsg := response.Get("error").StringOr("未知错误")
log.Printf("API 错误: %s", errorMsg)
return
}
// 根据类型处理数据
data := response.Get("data")
if data.IsArray() {
fmt.Printf("收到 %d 条记录\n", data.Len())
data.ArrayForEach(func(i int, item fxjson.Node) bool {
id := item.Get("id").IntOr(0)
name := item.Get("name").StringOr("未知")
fmt.Printf("项目 %d: %s\n", id, name)
return true
})
}
// 处理分页
currentPage := response.GetPath("meta.page").IntOr(1)
totalPages := response.GetPath("meta.totalPages").IntOr(1)
fmt.Printf("第 %d 页,共 %d 页\n", currentPage, totalPages)
}type Config struct {
Server struct {
Host string `json:"host"`
Port int `json:"port"`
} `json:"server"`
Database struct {
URL string `json:"url"`
PoolSize int `json:"poolSize"`
} `json:"database"`
}
func loadConfig(env string) (*Config, error) {
// 加载基础配置
baseConfig, _ := os.ReadFile("config/base.json")
// 加载环境特定配置
envConfig, _ := os.ReadFile(fmt.Sprintf("config/%s.json", env))
if envConfig == nil {
envConfig = []byte("{}")
}
// 解析并合并
base := fxjson.FromBytes(baseConfig)
envSpecific := fxjson.FromBytes(envConfig)
final := base.Merge(envSpecific)
// 验证必需字段
required := []string{"server.host", "server.port", "database.url"}
if !final.HasAllPaths(required...) {
return nil, errors.New("缺少必需的配置项")
}
// 解码为结构体
var config Config
if err := final.Decode(&config); err != nil {
return nil, err
}
// 应用默认值
if config.Database.PoolSize == 0 {
config.Database.PoolSize = 10
}
return &config, nil
}func analyzeJSONLogs(logData []byte) {
lines := strings.Split(string(logData), "\n")
var errorCount, warnCount, infoCount int
errorMessages := make(map[string]int)
for _, line := range lines {
if line == "" {
continue
}
logEntry := fxjson.FromBytes([]byte(line))
level := logEntry.Get("level").StringOr("")
switch level {
case "ERROR":
errorCount++
msg := logEntry.Get("message").StringOr("")
errorMessages[msg]++
case "WARN":
warnCount++
case "INFO":
infoCount++
}
// 检查服务器错误
if logEntry.Get("status").IntOr(0) >= 500 {
timestamp := logEntry.Get("timestamp").StringOr("")
message := logEntry.Get("message").StringOr("")
fmt.Printf("服务器错误 %s: %s\n", timestamp, message)
}
}
fmt.Printf("日志摘要: %d 错误, %d 警告, %d 信息\n",
errorCount, warnCount, infoCount)
// 显示高频错误
for msg, count := range errorMessages {
if count > 1 {
fmt.Printf("高频错误: %s (%d 次)\n", msg, count)
}
}
}// ❌ 不要这样做
value, err := node.Get("key").String()
if err != nil {
// 处理错误
}
// ✅ 这样做
value := node.Get("key").StringOr("默认值")// ❌ 冗长且容易出错
city := node.Get("user").Get("address").Get("city").StringOr("")
// ✅ 简洁易读
city := node.GetPath("user.address.city").StringOr("")// ✅ 处理未知数据的安全方法
field := node.Get("unknown_field")
if field.IsNumber() {
value := field.IntOr(0)
} else if field.IsString() {
value := field.StringOr("")
}// ✅ 始终先验证结构
requiredFields := []string{"id", "name", "email"}
if !node.HasAllPaths(requiredFields...) {
return errors.New("缺少必需字段")
}
// 然后安全处理
id := node.Get("id").IntOr(0)
name := node.Get("name").StringOr("")
email := node.Get("email").StringOr("")// ❌ 对大对象/数组慢
for i := 0; i < array.Len(); i++ {
item := array.Index(i)
// 处理
}
// ✅ 快速,零分配
array.ArrayForEach(func(i int, item fxjson.Node) bool {
// 处理
return true
})// 普通场景 - 使用 Marshal
data, err := fxjson.Marshal(obj)
// 性能关键场景 - 使用 FastMarshal
data := fxjson.FastMarshal(obj)
// 大量数据 - 使用批量序列化
results, err := fxjson.BatchMarshalStructs(objects)// 问题:空字符串可能导致问题
jsonData := []byte(`{"name": "", "description": null}`)
node := fxjson.FromBytes(jsonData)
// 解决方案:始终使用默认值
name := node.Get("name").StringOr("匿名")
description := node.Get("description").StringOr("无描述")
// 检查是否真的为空
if node.Get("name").IsEmpty() {
fmt.Println("名称为空")
}// 问题:浮点数精度
jsonData := []byte(`{"price": 19.99, "tax": 1.995}`)
node := fxjson.FromBytes(jsonData)
// 解决方案:计算时使用适当的舍入
price := node.Get("price").FloatOr(0)
tax := node.Get("tax").FloatOr(0)
total := math.Round((price+tax)*100) / 100 // 适当的舍入// 问题:高效处理大数组
largeArray := []byte(`{"items": [/* 数千个项目 */]}`)
// 解决方案:使用 ArrayForEach 进行流式处理
node := fxjson.FromBytes(largeArray)
items := node.Get("items")
items.ArrayForEach(func(i int, item fxjson.Node) bool {
// 高效处理元素
return true
})-
转换前检查节点类型:
node.IsString(),node.IsArray()等 - 使用 HasKey():验证字段存在后再访问
- 启用缓存:对频繁解析的 JSON 启用缓存以提高性能
-
使用路径:对深层嵌套结构使用
GetPath()
FxJSON 让 JSON 处理变得快速、安全、有趣! 🚀
更多示例和高级用法,请查看项目仓库。