golang轻松访问和操作嵌套JSON数据的插件库ask的使用
Golang轻松访问和操作嵌套JSON数据的插件库ask的使用
Ask库提供了一种简单的方法来访问和操作嵌套在map和slice中的属性。它与encoding/json等包配合使用效果很好,这些包可以将任意数据"Unmarshal"到Go数据类型中。该库的灵感来源于lodash JavaScript库中的get函数。
⚠️ 从v0.3.0
版本开始,由于使用了reflect包的新功能,该包需要Go 1.17+版本。
使用方法
package main
import (
"encoding/json"
"fmt"
"github.com/simonnilsson/ask"
)
func main() {
// 使用解析后的JSON作为源数据
var object map[string]interface{}
json.Unmarshal([]byte(`{ "a": [{ "b": { "c": 3 } }] }`), &object)
// 提取数字3
res, ok := ask.For(object, "a[0].b.c").Int(0)
fmt.Println(res, ok)
// 输出: 3 true
// 尝试提取路径.d中不存在的字符串
res2, ok := ask.ForArgs(object, "a", 0, "b", "d").String("nothing")
fmt.Println(res2, ok)
// 输出: nothing false
}
API
ask在内部使用类型断言来遍历提供的路径。每次调用都从For()开始,传入你的数据结构source
和要提取的path
。你也可以使用ForArgs(),如果你想将路径的每个部分作为单独的参数提供,这在你的字段名包含点号时很有用。
For(source interface{}, path string) *Answer
ForArgs(source interface{}, parts ...interface{}) *Answer
可以通过在结果答案上调用Path()/PathArgs()来遍历额外的路径。
(a *Answer) Path(path string) *Answer
(a *Answer) PathArgs(parts ...interface{}) *Answer
类型断言
从For()调用接收到*Answer
后,可以将其断言为某种类型。相关方法如下所示。每个函数都接受一个默认值作为参数,如果无法从答案中断言出值,则将返回该默认值。第二个返回值用于指示断言是否成功。
(a *Answer) String(d string) (string, bool)
(a *Answer) Bool(d bool) (bool, bool)
(a *Answer) Int(d int64) (int64, bool)
(a *Answer) Uint(d uint64) (uint64, bool)
(a *Answer) Float(d float64) (float64, bool)
(a *Answer) Slice(d []interface{}) ([]interface{}, bool)
(a *Answer) Map(d map[string]interface{}) (map[string]interface{}, bool)
如果找到一个数字,但它与请求的类型不同,它将被转换为所需的类型并返回成功。但是,如果该值不适合请求类型的有效范围,操作将失败,并返回默认参数。
还有两个额外的方法可用,一个用于检查答案是否有值(不为nil),另一个用于将原始值作为interface{}返回。
(a *Answer) Exists() bool
(a *Answer) Value() interface{}
完整示例
package main
import (
"encoding/json"
"fmt"
"github.com/simonnilsson/ask"
)
func main() {
// 更复杂的JSON示例
jsonData := `{
"user": {
"name": "John Doe",
"age": 30,
"addresses": [
{
"type": "home",
"street": "123 Main St",
"city": "Anytown"
},
{
"type": "work",
"street": "456 Business Ave",
"city": "Businesstown"
}
],
"active": true
}
}`
var data map[string]interface{}
json.Unmarshal([]byte(jsonData), &data)
// 获取用户名
name, ok := ask.For(data, "user.name").String("")
fmt.Printf("Name: %s (exists: %v)\n", name, ok)
// 获取年龄
age, ok := ask.For(data, "user.age").Int(0)
fmt.Printf("Age: %d (exists: %v)\n", age, ok)
// 获取工作地址城市
workCity, ok := ask.For(data, "user.addresses[1].city").String("")
fmt.Printf("Work City: %s (exists: %v)\n", workCity, ok)
// 检查用户是否活跃
active, ok := ask.For(data, "user.active").Bool(false)
fmt.Printf("Active: %v (exists: %v)\n", active, ok)
// 尝试获取不存在的字段
missing, ok := ask.For(data, "user.missing_field").String("default")
fmt.Printf("Missing Field: %s (exists: %v)\n", missing, ok)
// 使用Path方法链式调用
homeStreet := ask.For(data, "user").Path("addresses[0].street").String("")
fmt.Printf("Home Street: %s\n", homeStreet)
}
这个示例展示了如何使用ask库从复杂的嵌套JSON结构中提取各种类型的数据,包括字符串、整数、布尔值等,以及如何处理不存在的字段。
更多关于golang轻松访问和操作嵌套JSON数据的插件库ask的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang轻松访问和操作嵌套JSON数据的插件库ask的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
使用ask库轻松访问和操作嵌套JSON数据
ask是一个轻量级的Go库,专门用于简化嵌套JSON数据的访问和操作。它提供了一种链式调用的方式来查询和修改JSON数据,避免了繁琐的类型断言和错误检查。
安装ask库
go get github.com/simonnilsson/ask
基本用法
1. 解析JSON数据
package main
import (
"fmt"
"github.com/simonnilsson/ask"
)
func main() {
data := `{
"user": {
"name": "John",
"age": 30,
"address": {
"street": "123 Main St",
"city": "New York"
},
"hobbies": ["reading", "swimming", "coding"]
}
}`
// 解析JSON
root := ask.For([]byte(data))
// 或者从map直接创建
// root := ask.For(map[string]interface{}{...})
}
2. 访问嵌套数据
// 获取用户名
name := root.Get("user.name").String()
fmt.Println("Name:", name) // 输出: Name: John
// 获取年龄(带默认值)
age := root.Get("user.age").Int(0)
fmt.Println("Age:", age) // 输出: Age: 30
// 获取城市
city := root.Get("user.address.city").String()
fmt.Println("City:", city) // 输出: City: New York
// 获取不存在的字段(带默认值)
country := root.Get("user.address.country").String("USA")
fmt.Println("Country:", country) // 输出: Country: USA
3. 处理数组数据
// 获取第一个爱好
firstHobby := root.Get("user.hobbies.0").String()
fmt.Println("First hobby:", firstHobby) // 输出: First hobby: reading
// 获取数组长度
hobbyCount := root.Get("user.hobbies").Len()
fmt.Println("Hobby count:", hobbyCount) // 输出: Hobby count: 3
// 遍历数组
hobbies := root.Get("user.hobbies")
for i := 0; i < hobbies.Len(); i++ {
hobby := hobbies.Index(i).String()
fmt.Printf("Hobby %d: %s\n", i+1, hobby)
}
4. 检查数据是否存在
// 检查字段是否存在
if root.Get("user.email").Exists() {
fmt.Println("Email exists")
} else {
fmt.Println("Email does not exist")
}
// 检查是否为特定类型
if root.Get("user.age").IsNumber() {
fmt.Println("Age is a number")
}
5. 修改JSON数据
// 修改现有值
root.Get("user.name").Set("Alice")
fmt.Println("New name:", root.Get("user.name").String())
// 添加新字段
root.Get("user.email").Set("alice@example.com")
// 删除字段
root.Get("user.hobbies").RemoveIndex(1) // 删除第二个爱好
// 转换为map或JSON
modifiedData := root.Value() // 返回interface{}
jsonData, _ := json.Marshal(modifiedData)
fmt.Println(string(jsonData))
高级用法
1. 链式调用
// 链式调用获取深层嵌套数据
street := ask.For(data).
Get("user").
Get("address").
Get("street").
String()
2. 处理可能不存在的路径
// 安全地获取可能不存在的路径
phone := root.Get("user.contact.phone").String("no phone")
3. 类型转换
// 尝试转换为不同类型
ageStr := root.Get("user.age").String() // "30"
ageFloat := root.Get("user.age").Float64() // 30.0
4. 处理复杂查询
// 检查数组中是否包含特定值
hobbies := root.Get("user.hobbies")
hasCoding := false
for i := 0; i < hobbies.Len(); i++ {
if hobbies.Index(i).String() == "coding" {
hasCoding = true
break
}
}
实际应用示例
func processUserData(jsonData []byte) {
root := ask.For(jsonData)
user := struct {
Name string
Age int
City string
Hobbies []string
}{
Name: root.Get("user.name").String(""),
Age: root.Get("user.age").Int(0),
City: root.Get("user.address.city").String(""),
Hobbies: make([]string, 0),
}
// 收集爱好
hobbies := root.Get("user.hobbies")
for i := 0; i < hobbies.Len(); i++ {
user.Hobbies = append(user.Hobbies, hobbies.Index(i).String())
}
fmt.Printf("Processed user: %+v\n", user)
}
ask库通过提供简洁的API大大简化了嵌套JSON数据的处理,避免了大量的类型断言和错误检查代码,使JSON操作更加直观和易于维护。