feat(gjson): 添加Stringify功能并优化GetProperty/SetProperty实现

添加了Stringify、PrettyPrint和Compact函数,用于将JSONBaseObject
转换为格式化的JSON字符串。同时优化了GetProperty和SetProperty函数的
内部实现,改进了嵌套对象的访问逻辑,并更新了example/main.go以演示
新功能的使用方法。
```
This commit is contained in:
程广 2026-02-11 17:32:20 +08:00
parent b9a44c546e
commit 7ee90f3a18
3 changed files with 174 additions and 45 deletions

View File

@ -30,6 +30,18 @@ func main() {
jsonStr, _ := obj.ToJSON()
fmt.Printf("JSON对象: %s\n", jsonStr)
// 使用Stringify函数
stringified, _ := gjson.Stringify(obj)
fmt.Printf("Stringify结果: %s\n", stringified)
// 使用PrettyPrint格式化输出
pretty, _ := gjson.PrettyPrint(obj)
fmt.Printf("格式化输出:\n%s\n", pretty)
// 使用Compact函数
compact, _ := gjson.Compact(obj)
fmt.Printf("紧凑格式: %s\n", compact)
// 从JSON字符串创建对象
newObj := gjson.NewJSONObject()
newObj.FromJSON(jsonStr)
@ -79,6 +91,10 @@ func main() {
arrayJson, _ := jsonArray.ToJSON()
fmt.Printf("JSON数组: %s\n", arrayJson)
// 使用Stringify格式化数组
arrayStringified, _ := gjson.Stringify(jsonArray, " ")
fmt.Printf("格式化数组:\n%s\n", arrayStringified)
// 访问数组元素
firstElement, _ := jsonArray.Get(0)
fmt.Printf("第一个元素: %v\n", firstElement)
@ -89,12 +105,20 @@ func main() {
fmt.Printf("嵌套对象属性: %s\n", str.Value())
}
// 演示各种值类型
// 演示各种值类型的Stringify
nullValue := gjson.NewJSONNull()
nullStr, _ := nullValue.ToString()
fmt.Printf("空值: %s\n", nullStr)
nullStr, _ := gjson.Stringify(nullValue)
fmt.Printf("空值Stringify: %s\n", nullStr)
boolValue := gjson.NewJSONBool(true)
boolStr, _ := boolValue.ToString()
fmt.Printf("布尔值: %s\n", boolStr)
boolStr, _ := gjson.Stringify(boolValue)
fmt.Printf("布尔值Stringify: %s\n", boolStr)
numValue := gjson.NewJSONNumber(42.5)
numStr, _ := gjson.Stringify(numValue)
fmt.Printf("数字Stringify: %s\n", numStr)
strValue := gjson.NewJSONString("hello world")
strStr, _ := gjson.Stringify(strValue)
fmt.Printf("字符串Stringify: %s\n", strStr)
}

View File

@ -5,7 +5,7 @@ import (
"strings"
)
// getProperty 获取属性值
// GetProperty 获取属性值
func GetProperty(obj JSONBaseObject, propertyPath string, defaultValue JSONBaseObject) (JSONBaseObject, error) {
// 首先尝试将obj转换为其实际类型
switch v := obj.(type) {
@ -19,7 +19,7 @@ func GetProperty(obj JSONBaseObject, propertyPath string, defaultValue JSONBaseO
}
}
// setProperty 设置属性值
// SetProperty 设置属性值
func SetProperty(obj JSONBaseObject, propertyPath string, value JSONBaseObject) error {
switch v := obj.(type) {
case *JSONObject:
@ -35,33 +35,31 @@ func SetProperty(obj JSONBaseObject, propertyPath string, value JSONBaseObject)
// 从JSONObject中获取属性
func getFromJSONObject(obj *JSONObject, propertyPath string, defaultValue JSONBaseObject) (JSONBaseObject, error) {
pathParts := strings.Split(propertyPath, ".")
currentObj := obj
currentData := obj.data
// 遍历路径直到倒数第二个部分
for i := 0; i < len(pathParts)-1; i++ {
// 遍历路径直到到达最终部分
for i := 0; i < len(pathParts); i++ {
key := pathParts[i]
value, exists := currentObj.Get(key)
value, exists := currentData[key]
if !exists {
return defaultValue, nil
}
// 如果路径中间部分不是JSONObject则无法继续
if jsonObj, ok := value.(*JSONObject); ok {
currentObj = jsonObj
// 如果这是最后一个路径部分,返回值
if i == len(pathParts)-1 {
return convertToJSONBaseObject(value), nil
}
// 否则继续深入嵌套对象
if nextMap, ok := value.(map[string]interface{}); ok {
currentData = nextMap
} else {
// 如果路径还没结束但无法继续深入,返回默认值
return defaultValue, nil
}
}
// 获取最终值
finalKey := pathParts[len(pathParts)-1]
value, exists := currentObj.Get(finalKey)
if !exists {
return defaultValue, nil
}
// 根据值的类型返回相应的JSONBaseObject
return convertToJSONBaseObject(value), nil
return defaultValue, nil
}
// 从JSONArray中获取属性
@ -88,10 +86,14 @@ func getFromJSONArray(arr *JSONArray, propertyPath string, defaultValue JSONBase
// 检查元素类型并递归查找
switch elem := element.(type) {
case *JSONObject:
return getFromJSONObject(elem, remainingPath, defaultValue)
case *JSONArray:
return getFromJSONArray(elem, remainingPath, defaultValue)
case map[string]interface{}:
// 创建临时JSONObject用于查找
tempObj := &JSONObject{data: elem}
return getFromJSONObject(tempObj, remainingPath, defaultValue)
case []interface{}:
// 创建临时JSONArray用于查找
tempArr := &JSONArray{data: elem}
return getFromJSONArray(tempArr, remainingPath, defaultValue)
default:
// 其他类型无法继续访问属性
return defaultValue, nil
@ -105,26 +107,26 @@ func getFromJSONArray(arr *JSONArray, propertyPath string, defaultValue JSONBase
// 在JSONObject中设置属性
func setInJSONObject(obj *JSONObject, propertyPath string, value JSONBaseObject) error {
pathParts := strings.Split(propertyPath, ".")
currentObj := obj
currentData := obj.data
// 遍历路径直到倒数第二个部分
for i := 0; i < len(pathParts)-1; i++ {
key := pathParts[i]
existingValue, exists := currentObj.Get(key)
existingValue, exists := currentData[key]
if !exists {
// 如果不存在,创建一个新的JSONObject
newObj := NewJSONObject()
currentObj.Put(key, newObj)
currentObj = newObj
} else if jsonObj, ok := existingValue.(*JSONObject); ok {
// 如果已经是JSONObject,继续向下遍历
currentObj = jsonObj
// 如果不存在,创建一个新的map
newMap := make(map[string]interface{})
currentData[key] = newMap
currentData = newMap
} else if nextMap, ok := existingValue.(map[string]interface{}); ok {
// 如果已经是map,继续向下遍历
currentData = nextMap
} else {
// 如果不是JSONObject替换为新的JSONObject
newObj := NewJSONObject()
currentObj.Put(key, newObj)
currentObj = newObj
// 如果不是map替换为新的map
newMap := make(map[string]interface{})
currentData[key] = newMap
currentData = newMap
}
}
@ -150,7 +152,7 @@ func setInJSONObject(obj *JSONObject, propertyPath string, value JSONBaseObject)
interfaceValue = v
}
currentObj.Put(finalKey, interfaceValue)
currentData[finalKey] = interfaceValue
return nil
}
@ -177,10 +179,12 @@ func setInJSONArray(arr *JSONArray, propertyPath string, value JSONBaseObject) e
// 检查元素类型并递归设置
switch elem := element.(type) {
case *JSONObject:
return SetProperty(elem, remainingPath, value)
case *JSONArray:
return SetProperty(elem, remainingPath, value)
case map[string]interface{}:
tempObj := &JSONObject{data: elem}
return SetProperty(tempObj, remainingPath, value)
case []interface{}:
tempArr := &JSONArray{data: elem}
return SetProperty(tempArr, remainingPath, value)
default:
// 其他类型无法设置属性
return nil

101
stringify.go Normal file
View File

@ -0,0 +1,101 @@
package gjson
import (
"encoding/json"
)
// Stringify 将JSONBaseObject转换为格式化的JSON字符串
// 类似于JavaScript中的JSON.stringify函数
func Stringify(obj JSONBaseObject, space ...string) (string, error) {
var indent string
if len(space) > 0 {
indent = space[0]
} else {
indent = "" // 默认无缩进
}
// 根据不同的对象类型进行处理
switch v := obj.(type) {
case *JSONObject:
if indent != "" {
// 格式化带缩进的JSON
bytes, err := json.MarshalIndent(v.data, "", indent)
if err != nil {
return "", err
}
return string(bytes), nil
} else {
// 紧凑型JSON
bytes, err := json.Marshal(v.data)
if err != nil {
return "", err
}
return string(bytes), nil
}
case *JSONArray:
if indent != "" {
// 格式化带缩进的JSON
bytes, err := json.MarshalIndent(v.data, "", indent)
if err != nil {
return "", err
}
return string(bytes), nil
} else {
// 紧凑型JSON
bytes, err := json.Marshal(v.data)
if err != nil {
return "", err
}
return string(bytes), nil
}
case *JSONString:
return v.ToJSON()
case *JSONNumber:
return v.ToJSON()
case *JSONBool:
return v.ToJSON()
case *JSONNull:
return v.ToJSON()
default:
// 如果是其他类型尝试转换为JSON
bytes, err := json.Marshal(v)
if err != nil {
return "", err
}
return string(bytes), nil
}
}
// StringifySimple 简单的字符串化函数将任何值转换为JSON字符串
func StringifySimple(value interface{}, space ...string) (string, error) {
var indent string
if len(space) > 0 {
indent = space[0]
} else {
indent = "" // 默认无缩进
}
if indent != "" {
bytes, err := json.MarshalIndent(value, "", indent)
if err != nil {
return "", err
}
return string(bytes), nil
} else {
bytes, err := json.Marshal(value)
if err != nil {
return "", err
}
return string(bytes), nil
}
}
// PrettyPrint 格式化打印JSON对象
func PrettyPrint(obj JSONBaseObject) (string, error) {
return Stringify(obj, " ") // 使用两个空格作为缩进
}
// Compact 将JSON对象转换为紧凑格式无多余空白字符
func Compact(obj JSONBaseObject) (string, error) {
return Stringify(obj) // 无缩进的格式
}