golang轻松访问和操作嵌套JSON数据的插件库ask的使用

Golang轻松访问和操作嵌套JSON数据的插件库ask的使用

ASK Logo

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

1 回复

更多关于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操作更加直观和易于维护。

回到顶部