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() jsonStr, _ := obj.ToJSON()
fmt.Printf("JSON对象: %s\n", jsonStr) 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字符串创建对象 // 从JSON字符串创建对象
newObj := gjson.NewJSONObject() newObj := gjson.NewJSONObject()
newObj.FromJSON(jsonStr) newObj.FromJSON(jsonStr)
@ -79,6 +91,10 @@ func main() {
arrayJson, _ := jsonArray.ToJSON() arrayJson, _ := jsonArray.ToJSON()
fmt.Printf("JSON数组: %s\n", arrayJson) fmt.Printf("JSON数组: %s\n", arrayJson)
// 使用Stringify格式化数组
arrayStringified, _ := gjson.Stringify(jsonArray, " ")
fmt.Printf("格式化数组:\n%s\n", arrayStringified)
// 访问数组元素 // 访问数组元素
firstElement, _ := jsonArray.Get(0) firstElement, _ := jsonArray.Get(0)
fmt.Printf("第一个元素: %v\n", firstElement) fmt.Printf("第一个元素: %v\n", firstElement)
@ -89,12 +105,20 @@ func main() {
fmt.Printf("嵌套对象属性: %s\n", str.Value()) fmt.Printf("嵌套对象属性: %s\n", str.Value())
} }
// 演示各种值类型 // 演示各种值类型的Stringify
nullValue := gjson.NewJSONNull() nullValue := gjson.NewJSONNull()
nullStr, _ := nullValue.ToString() nullStr, _ := gjson.Stringify(nullValue)
fmt.Printf("空值: %s\n", nullStr) fmt.Printf("空值Stringify: %s\n", nullStr)
boolValue := gjson.NewJSONBool(true) boolValue := gjson.NewJSONBool(true)
boolStr, _ := boolValue.ToString() boolStr, _ := gjson.Stringify(boolValue)
fmt.Printf("布尔值: %s\n", boolStr) 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" "strings"
) )
// getProperty 获取属性值 // GetProperty 获取属性值
func GetProperty(obj JSONBaseObject, propertyPath string, defaultValue JSONBaseObject) (JSONBaseObject, error) { func GetProperty(obj JSONBaseObject, propertyPath string, defaultValue JSONBaseObject) (JSONBaseObject, error) {
// 首先尝试将obj转换为其实际类型 // 首先尝试将obj转换为其实际类型
switch v := obj.(type) { 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 { func SetProperty(obj JSONBaseObject, propertyPath string, value JSONBaseObject) error {
switch v := obj.(type) { switch v := obj.(type) {
case *JSONObject: case *JSONObject:
@ -35,35 +35,33 @@ func SetProperty(obj JSONBaseObject, propertyPath string, value JSONBaseObject)
// 从JSONObject中获取属性 // 从JSONObject中获取属性
func getFromJSONObject(obj *JSONObject, propertyPath string, defaultValue JSONBaseObject) (JSONBaseObject, error) { func getFromJSONObject(obj *JSONObject, propertyPath string, defaultValue JSONBaseObject) (JSONBaseObject, error) {
pathParts := strings.Split(propertyPath, ".") 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] key := pathParts[i]
value, exists := currentObj.Get(key) value, exists := currentData[key]
if !exists { if !exists {
return defaultValue, nil return defaultValue, nil
} }
// 如果路径中间部分不是JSONObject则无法继续 // 如果这是最后一个路径部分,返回值
if jsonObj, ok := value.(*JSONObject); ok { if i == len(pathParts)-1 {
currentObj = jsonObj
} 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 convertToJSONBaseObject(value), nil
} }
// 否则继续深入嵌套对象
if nextMap, ok := value.(map[string]interface{}); ok {
currentData = nextMap
} else {
// 如果路径还没结束但无法继续深入,返回默认值
return defaultValue, nil
}
}
return defaultValue, nil
}
// 从JSONArray中获取属性 // 从JSONArray中获取属性
func getFromJSONArray(arr *JSONArray, propertyPath string, defaultValue JSONBaseObject) (JSONBaseObject, error) { func getFromJSONArray(arr *JSONArray, propertyPath string, defaultValue JSONBaseObject) (JSONBaseObject, error) {
// 解析路径,支持数组索引 // 解析路径,支持数组索引
@ -88,10 +86,14 @@ func getFromJSONArray(arr *JSONArray, propertyPath string, defaultValue JSONBase
// 检查元素类型并递归查找 // 检查元素类型并递归查找
switch elem := element.(type) { switch elem := element.(type) {
case *JSONObject: case map[string]interface{}:
return getFromJSONObject(elem, remainingPath, defaultValue) // 创建临时JSONObject用于查找
case *JSONArray: tempObj := &JSONObject{data: elem}
return getFromJSONArray(elem, remainingPath, defaultValue) return getFromJSONObject(tempObj, remainingPath, defaultValue)
case []interface{}:
// 创建临时JSONArray用于查找
tempArr := &JSONArray{data: elem}
return getFromJSONArray(tempArr, remainingPath, defaultValue)
default: default:
// 其他类型无法继续访问属性 // 其他类型无法继续访问属性
return defaultValue, nil return defaultValue, nil
@ -105,26 +107,26 @@ func getFromJSONArray(arr *JSONArray, propertyPath string, defaultValue JSONBase
// 在JSONObject中设置属性 // 在JSONObject中设置属性
func setInJSONObject(obj *JSONObject, propertyPath string, value JSONBaseObject) error { func setInJSONObject(obj *JSONObject, propertyPath string, value JSONBaseObject) error {
pathParts := strings.Split(propertyPath, ".") pathParts := strings.Split(propertyPath, ".")
currentObj := obj currentData := obj.data
// 遍历路径直到倒数第二个部分 // 遍历路径直到倒数第二个部分
for i := 0; i < len(pathParts)-1; i++ { for i := 0; i < len(pathParts)-1; i++ {
key := pathParts[i] key := pathParts[i]
existingValue, exists := currentObj.Get(key) existingValue, exists := currentData[key]
if !exists { if !exists {
// 如果不存在,创建一个新的JSONObject // 如果不存在,创建一个新的map
newObj := NewJSONObject() newMap := make(map[string]interface{})
currentObj.Put(key, newObj) currentData[key] = newMap
currentObj = newObj currentData = newMap
} else if jsonObj, ok := existingValue.(*JSONObject); ok { } else if nextMap, ok := existingValue.(map[string]interface{}); ok {
// 如果已经是JSONObject,继续向下遍历 // 如果已经是map,继续向下遍历
currentObj = jsonObj currentData = nextMap
} else { } else {
// 如果不是JSONObject替换为新的JSONObject // 如果不是map替换为新的map
newObj := NewJSONObject() newMap := make(map[string]interface{})
currentObj.Put(key, newObj) currentData[key] = newMap
currentObj = newObj currentData = newMap
} }
} }
@ -150,7 +152,7 @@ func setInJSONObject(obj *JSONObject, propertyPath string, value JSONBaseObject)
interfaceValue = v interfaceValue = v
} }
currentObj.Put(finalKey, interfaceValue) currentData[finalKey] = interfaceValue
return nil return nil
} }
@ -177,10 +179,12 @@ func setInJSONArray(arr *JSONArray, propertyPath string, value JSONBaseObject) e
// 检查元素类型并递归设置 // 检查元素类型并递归设置
switch elem := element.(type) { switch elem := element.(type) {
case *JSONObject: case map[string]interface{}:
return SetProperty(elem, remainingPath, value) tempObj := &JSONObject{data: elem}
case *JSONArray: return SetProperty(tempObj, remainingPath, value)
return SetProperty(elem, remainingPath, value) case []interface{}:
tempArr := &JSONArray{data: elem}
return SetProperty(tempArr, remainingPath, value)
default: default:
// 其他类型无法设置属性 // 其他类型无法设置属性
return nil 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) // 无缩进的格式
}