mirror of
https://gitee.com/johng/gf
synced 2026-06-06 16:21:40 +08:00
This pull request improves YAML support for i18n translation files and refactors content type detection and loading logic in the `gjson` package. The main changes include more robust detection of YAML, TOML, INI, and Properties formats, refactoring of content type handling, and the addition of new tests to ensure correct parsing of YAML-based i18n resources. ### Improved content type detection and loading * Refactored content type detection logic in `gjson` to use dedicated functions for XML, YAML, TOML, INI, and Properties formats, making the detection more reliable and maintainable. * Changed the content loading mechanism in `gjson` to use specific decode functions (`gxml.Decode`, `gyaml.Decode`, etc.) for each format instead of converting everything to JSON first, improving accuracy and extensibility. * Updated type definitions and struct field comments in `gjson.go` for clarity and consistency, including changing `ContentType` to a type alias and improving documentation. [[1]](diffhunk://#diff-0e4432d7e4cf171c0339e01b1842530432b986948d7f839a155543623236a03fL24-R24) [[2]](diffhunk://#diff-0e4432d7e4cf171c0339e01b1842530432b986948d7f839a155543623236a03fL38-R71) ### i18n YAML support * Modified i18n manager to use the new `gjson.LoadPath` method for loading translation files, ensuring correct parsing of YAML files for i18n. * Added new test cases and test data for loading and verifying YAML i18n files, including edge cases and real-world translation strings. [[1]](diffhunk://#diff-e6eacc5abab33c149f9b39d8ebe300cf4d0abe907434605991984a5969e8707dR262-R283) [[2]](diffhunk://#diff-1bfd438797c1f9ef18ab3cb00d23ae95202e85e2362c39c3df4f1a29c55733feR421-R430) [[3]](diffhunk://#diff-a3ee37ff2a67c9e1ba2e1617e0f5fd63eb261ad7760a07423f703538138c2decR1-R16) ### Minor improvements * Simplified file loading logic in `gjson.LoadPath` by removing caching and directly reading file bytes, which streamlines the code and avoids potential cache issues. --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
431 lines
11 KiB
Go
431 lines
11 KiB
Go
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
|
//
|
|
// This Source Code Form is subject to the terms of the MIT License.
|
|
// If a copy of the MIT was not distributed with this file,
|
|
// You can obtain one at https://github.com/gogf/gf.
|
|
|
|
package gjson_test
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/gogf/gf/v2/encoding/gjson"
|
|
"github.com/gogf/gf/v2/frame/g"
|
|
"github.com/gogf/gf/v2/os/gfile"
|
|
"github.com/gogf/gf/v2/test/gtest"
|
|
)
|
|
|
|
func Test_Load_JSON1(t *testing.T) {
|
|
data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`)
|
|
// JSON
|
|
gtest.C(t, func(t *gtest.T) {
|
|
j, err := gjson.LoadContent(data)
|
|
t.AssertNil(err)
|
|
t.Assert(j.Get("n").String(), "123456789")
|
|
t.Assert(j.Get("m").Map(), g.Map{"k": "v"})
|
|
t.Assert(j.Get("m.k").String(), "v")
|
|
t.Assert(j.Get("a").Slice(), g.Slice{1, 2, 3})
|
|
t.Assert(j.Get("a.1").Int(), 2)
|
|
})
|
|
// JSON
|
|
gtest.C(t, func(t *gtest.T) {
|
|
errData := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]`)
|
|
_, err := gjson.LoadContentType("json", errData, true)
|
|
t.AssertNE(err, nil)
|
|
})
|
|
// JSON
|
|
gtest.C(t, func(t *gtest.T) {
|
|
path := "test.json"
|
|
gfile.PutBytes(path, data)
|
|
defer gfile.Remove(path)
|
|
j, err := gjson.Load(path, true)
|
|
t.AssertNil(err)
|
|
t.Assert(j.Get("n").String(), "123456789")
|
|
t.Assert(j.Get("m").Map(), g.Map{"k": "v"})
|
|
t.Assert(j.Get("m.k").String(), "v")
|
|
t.Assert(j.Get("a").Slice(), g.Slice{1, 2, 3})
|
|
t.Assert(j.Get("a.1").Int(), 2)
|
|
})
|
|
}
|
|
|
|
func Test_Load_JSON2(t *testing.T) {
|
|
data := []byte(`{"n":123456789000000000000, "m":{"k":"v"}, "a":[1,2,3]}`)
|
|
gtest.C(t, func(t *gtest.T) {
|
|
j, err := gjson.LoadContent(data)
|
|
t.AssertNil(err)
|
|
t.Assert(j.Get("n").String(), "123456789000000000000")
|
|
t.Assert(j.Get("m").Map(), g.Map{"k": "v"})
|
|
t.Assert(j.Get("m.k").String(), "v")
|
|
t.Assert(j.Get("a").Slice(), g.Slice{1, 2, 3})
|
|
t.Assert(j.Get("a.1").Int(), 2)
|
|
})
|
|
}
|
|
|
|
func Test_Load_XML(t *testing.T) {
|
|
data := []byte(`<doc><a>1</a><a>2</a><a>3</a><m><k>v</k></m><n>123456789</n></doc>`)
|
|
// XML
|
|
gtest.C(t, func(t *gtest.T) {
|
|
j, err := gjson.LoadContent(data)
|
|
t.AssertNil(err)
|
|
t.Assert(j.Get("doc.n").String(), "123456789")
|
|
t.Assert(j.Get("doc.m").Map(), g.Map{"k": "v"})
|
|
t.Assert(j.Get("doc.m.k").String(), "v")
|
|
t.Assert(j.Get("doc.a").Slice(), g.Slice{"1", "2", "3"})
|
|
t.Assert(j.Get("doc.a.1").Int(), 2)
|
|
})
|
|
// XML
|
|
gtest.C(t, func(t *gtest.T) {
|
|
j, err := gjson.LoadXml(data, true)
|
|
t.AssertNil(err)
|
|
t.Assert(j.Get("doc.n").String(), "123456789")
|
|
t.Assert(j.Get("doc.m").Map(), g.Map{"k": "v"})
|
|
t.Assert(j.Get("doc.m.k").String(), "v")
|
|
t.Assert(j.Get("doc.a").Slice(), g.Slice{"1", "2", "3"})
|
|
t.Assert(j.Get("doc.a.1").Int(), 2)
|
|
})
|
|
// XML
|
|
gtest.C(t, func(t *gtest.T) {
|
|
errData := []byte(`<doc><a>1</a><a>2</a><a>3</a><m><k>v</k></m><n>123456789</n><doc>`)
|
|
_, err := gjson.LoadContentType("xml", errData, true)
|
|
t.AssertNE(err, nil)
|
|
})
|
|
// XML
|
|
gtest.C(t, func(t *gtest.T) {
|
|
path := "test.xml"
|
|
gfile.PutBytes(path, data)
|
|
defer gfile.Remove(path)
|
|
j, err := gjson.Load(path)
|
|
t.AssertNil(err)
|
|
t.Assert(j.Get("doc.n").String(), "123456789")
|
|
t.Assert(j.Get("doc.m").Map(), g.Map{"k": "v"})
|
|
t.Assert(j.Get("doc.m.k").String(), "v")
|
|
t.Assert(j.Get("doc.a").Array(), g.Slice{"1", "2", "3"})
|
|
t.Assert(j.Get("doc.a.1").Int(), 2)
|
|
})
|
|
|
|
// XML
|
|
gtest.C(t, func(t *gtest.T) {
|
|
xml := []byte(`
|
|
<?xml version="1.0"?>
|
|
|
|
<Output type="o">
|
|
<itotalSize>0</itotalSize>
|
|
<ipageSize>1</ipageSize>
|
|
<ipageIndex>2</ipageIndex>
|
|
<itotalRecords>GF框架</itotalRecords>
|
|
<nworkOrderDtos/>
|
|
<nworkOrderFrontXML/>
|
|
</Output>
|
|
`)
|
|
j, err := gjson.LoadContent(xml)
|
|
t.AssertNil(err)
|
|
t.Assert(j.Get("Output.ipageIndex"), "2")
|
|
t.Assert(j.Get("Output.itotalRecords"), "GF框架")
|
|
})
|
|
}
|
|
|
|
func Test_Load_YAML1(t *testing.T) {
|
|
data := []byte(`
|
|
a:
|
|
- 1
|
|
- 2
|
|
- 3
|
|
m:
|
|
k: v
|
|
"n": 123456789
|
|
`)
|
|
// YAML
|
|
gtest.C(t, func(t *gtest.T) {
|
|
j, err := gjson.LoadContent(data)
|
|
t.AssertNil(err)
|
|
t.Assert(j.Get("n").String(), "123456789")
|
|
t.Assert(j.Get("m").Map(), g.Map{"k": "v"})
|
|
t.Assert(j.Get("m.k").String(), "v")
|
|
t.Assert(j.Get("a").Slice(), g.Slice{1, 2, 3})
|
|
t.Assert(j.Get("a.1").Int(), 2)
|
|
})
|
|
// YAML
|
|
gtest.C(t, func(t *gtest.T) {
|
|
j, err := gjson.LoadYaml(data, true)
|
|
t.AssertNil(err)
|
|
t.Assert(j.Get("n").String(), "123456789")
|
|
t.Assert(j.Get("m").Map(), g.Map{"k": "v"})
|
|
t.Assert(j.Get("m.k").String(), "v")
|
|
t.Assert(j.Get("a").Slice(), g.Slice{1, 2, 3})
|
|
t.Assert(j.Get("a.1").Int(), 2)
|
|
})
|
|
// YAML
|
|
gtest.C(t, func(t *gtest.T) {
|
|
path := "test.yaml"
|
|
gfile.PutBytes(path, data)
|
|
defer gfile.Remove(path)
|
|
j, err := gjson.Load(path)
|
|
t.AssertNil(err)
|
|
t.Assert(j.Get("n").String(), "123456789")
|
|
t.Assert(j.Get("m").Map(), g.Map{"k": "v"})
|
|
t.Assert(j.Get("m.k").String(), "v")
|
|
t.Assert(j.Get("a").Slice(), g.Slice{1, 2, 3})
|
|
t.Assert(j.Get("a.1").Int(), 2)
|
|
})
|
|
}
|
|
|
|
func Test_Load_YAML2(t *testing.T) {
|
|
data := []byte("i : 123456789")
|
|
gtest.C(t, func(t *gtest.T) {
|
|
j, err := gjson.LoadContent(data)
|
|
t.AssertNil(err)
|
|
t.Assert(j.Get("i"), "123456789")
|
|
})
|
|
gtest.C(t, func(t *gtest.T) {
|
|
errData := []byte("i # 123456789")
|
|
_, err := gjson.LoadContentType("yaml", errData, true)
|
|
t.AssertNE(err, nil)
|
|
})
|
|
}
|
|
|
|
func Test_Load_TOML1(t *testing.T) {
|
|
data := []byte(`
|
|
a = ["1", "2", "3"]
|
|
n = 123456789
|
|
|
|
[m]
|
|
k = "v"
|
|
`)
|
|
// TOML
|
|
gtest.C(t, func(t *gtest.T) {
|
|
j, err := gjson.LoadContent(data)
|
|
t.AssertNil(err)
|
|
t.Assert(j.Get("n").String(), "123456789")
|
|
t.Assert(j.Get("m").Map(), g.Map{"k": "v"})
|
|
t.Assert(j.Get("m.k").String(), "v")
|
|
t.Assert(j.Get("a").Slice(), g.Slice{"1", "2", "3"})
|
|
t.Assert(j.Get("a.1").Int(), 2)
|
|
})
|
|
// TOML
|
|
gtest.C(t, func(t *gtest.T) {
|
|
j, err := gjson.LoadToml(data, true)
|
|
t.AssertNil(err)
|
|
t.Assert(j.Get("n").String(), "123456789")
|
|
t.Assert(j.Get("m").Map(), g.Map{"k": "v"})
|
|
t.Assert(j.Get("m.k").String(), "v")
|
|
t.Assert(j.Get("a").Slice(), g.Slice{"1", "2", "3"})
|
|
t.Assert(j.Get("a.1").Int(), 2)
|
|
})
|
|
// TOML
|
|
gtest.C(t, func(t *gtest.T) {
|
|
path := "test.toml"
|
|
gfile.PutBytes(path, data)
|
|
defer gfile.Remove(path)
|
|
j, err := gjson.Load(path)
|
|
t.AssertNil(err)
|
|
t.Assert(j.Get("n").String(), "123456789")
|
|
t.Assert(j.Get("m").Map(), g.Map{"k": "v"})
|
|
t.Assert(j.Get("m.k").String(), "v")
|
|
t.Assert(j.Get("a").Slice(), g.Slice{"1", "2", "3"})
|
|
t.Assert(j.Get("a.1").Int(), 2)
|
|
})
|
|
}
|
|
|
|
func Test_Load_TOML2(t *testing.T) {
|
|
data := []byte("i=123456789")
|
|
gtest.C(t, func(t *gtest.T) {
|
|
j, err := gjson.LoadContent(data)
|
|
t.AssertNil(err)
|
|
t.Assert(j.Get("i"), "123456789")
|
|
})
|
|
gtest.C(t, func(t *gtest.T) {
|
|
errData := []byte("i : 123456789")
|
|
_, err := gjson.LoadContentType("toml", errData, true)
|
|
t.AssertNE(err, nil)
|
|
})
|
|
}
|
|
|
|
func Test_Load_Basic(t *testing.T) {
|
|
gtest.C(t, func(t *gtest.T) {
|
|
j := gjson.New(nil)
|
|
t.Assert(j.Interface(), nil)
|
|
_, err := gjson.Decode(nil)
|
|
t.AssertNE(err, nil)
|
|
_, err = gjson.DecodeToJson(nil)
|
|
t.AssertNE(err, nil)
|
|
j, err = gjson.LoadContent(nil)
|
|
t.AssertNil(err)
|
|
t.Assert(j.Interface(), nil)
|
|
|
|
j, err = gjson.LoadContent([]byte(`{"name": "gf"}`))
|
|
t.AssertNil(err)
|
|
|
|
j, err = gjson.LoadContent([]byte(`{"name": "gf"""}`))
|
|
t.AssertNE(err, nil)
|
|
|
|
j = gjson.New(&g.Map{"name": "gf"})
|
|
t.Assert(j.Get("name").String(), "gf")
|
|
|
|
})
|
|
}
|
|
|
|
func Test_Load_Ini(t *testing.T) {
|
|
var data = []byte(`
|
|
|
|
;注释
|
|
|
|
[addr]
|
|
ip = 127.0.0.1
|
|
port=9001
|
|
enable=true
|
|
|
|
[DBINFO]
|
|
type=mysql
|
|
user=root
|
|
password=password
|
|
|
|
`)
|
|
|
|
gtest.C(t, func(t *gtest.T) {
|
|
j, err := gjson.LoadContent(data)
|
|
if err != nil {
|
|
gtest.Fatal(err)
|
|
}
|
|
|
|
t.Assert(j.Get("addr.ip").String(), "127.0.0.1")
|
|
t.Assert(j.Get("addr.port").String(), "9001")
|
|
t.Assert(j.Get("addr.enable").String(), "true")
|
|
t.Assert(j.Get("DBINFO.type").String(), "mysql")
|
|
t.Assert(j.Get("DBINFO.user").String(), "root")
|
|
t.Assert(j.Get("DBINFO.password").String(), "password")
|
|
|
|
_, err = j.ToIni()
|
|
if err != nil {
|
|
gtest.Fatal(err)
|
|
}
|
|
})
|
|
|
|
gtest.C(t, func(t *gtest.T) {
|
|
j, err := gjson.LoadIni(data, true)
|
|
if err != nil {
|
|
gtest.Fatal(err)
|
|
}
|
|
|
|
t.Assert(j.Get("addr.ip").String(), "127.0.0.1")
|
|
t.Assert(j.Get("addr.port").String(), "9001")
|
|
t.Assert(j.Get("addr.enable").String(), "true")
|
|
t.Assert(j.Get("DBINFO.type").String(), "mysql")
|
|
t.Assert(j.Get("DBINFO.user").String(), "root")
|
|
t.Assert(j.Get("DBINFO.password").String(), "password")
|
|
})
|
|
|
|
gtest.C(t, func(t *gtest.T) {
|
|
errData := []byte("i : 123456789")
|
|
_, err := gjson.LoadContentType("ini", errData, true)
|
|
t.AssertNE(err, nil)
|
|
})
|
|
}
|
|
|
|
func Test_Load_YamlWithV3(t *testing.T) {
|
|
content := []byte(`
|
|
# CLI tool, only in development environment.
|
|
# https://goframe.org/pages/viewpage.action?pageId=3673173
|
|
gfcli:
|
|
gen:
|
|
dao:
|
|
- path : "../../pkg/oss/oss/internal"
|
|
group : "oss"
|
|
stdTime : true
|
|
descriptionTag : true
|
|
noJsonTag : true
|
|
noModelComment : true
|
|
overwriteDao : true
|
|
modelFileForDao : "model_dao.go"
|
|
tablesEx : |
|
|
bpmn_info,
|
|
dlocker,
|
|
dlocker_detail,
|
|
message_table,
|
|
monitor_data,
|
|
resource_param_info,
|
|
version_info,
|
|
version_topology_info,
|
|
work_flow,
|
|
work_flow_step_info,
|
|
work_flow_undo_step_info
|
|
|
|
- path : "../../pkg/oss/workflow/internal"
|
|
group : "workflow"
|
|
stdTime : true
|
|
descriptionTag : true
|
|
noJsonTag : true
|
|
noModelComment : true
|
|
overwriteDao : true
|
|
modelFileForDao : "model_dao.go"
|
|
`)
|
|
gtest.C(t, func(t *gtest.T) {
|
|
_, err := gjson.LoadContent(content)
|
|
t.AssertNil(err)
|
|
})
|
|
}
|
|
|
|
func Test_Load_Properties(t *testing.T) {
|
|
var data = []byte(`
|
|
|
|
#注释
|
|
|
|
|
|
addr.ip = 127.0.0.1
|
|
addr.port=9001
|
|
addr.enable=true
|
|
DBINFO.type=mysql
|
|
DBINFO.user=root
|
|
DBINFO.password=password
|
|
|
|
`)
|
|
|
|
gtest.C(t, func(t *gtest.T) {
|
|
j, err := gjson.LoadContent(data)
|
|
if err != nil {
|
|
gtest.Fatal(err)
|
|
}
|
|
|
|
t.Assert(j.Get("addr.ip").String(), "127.0.0.1")
|
|
t.Assert(j.Get("addr.port").String(), "9001")
|
|
t.Assert(j.Get("addr.enable").String(), "true")
|
|
t.Assert(j.Get("DBINFO.type").String(), "mysql")
|
|
t.Assert(j.Get("DBINFO.user").String(), "root")
|
|
t.Assert(j.Get("DBINFO.password").String(), "password")
|
|
|
|
_, err = j.ToProperties()
|
|
if err != nil {
|
|
gtest.Fatal(err)
|
|
}
|
|
})
|
|
|
|
gtest.C(t, func(t *gtest.T) {
|
|
j, err := gjson.LoadProperties(data, true)
|
|
if err != nil {
|
|
gtest.Fatal(err)
|
|
}
|
|
|
|
t.Assert(j.Get("addr.ip").String(), "127.0.0.1")
|
|
t.Assert(j.Get("addr.port").String(), "9001")
|
|
t.Assert(j.Get("addr.enable").String(), "true")
|
|
t.Assert(j.Get("DBINFO.type").String(), "mysql")
|
|
t.Assert(j.Get("DBINFO.user").String(), "root")
|
|
t.Assert(j.Get("DBINFO.password").String(), "password")
|
|
})
|
|
|
|
gtest.C(t, func(t *gtest.T) {
|
|
errData := []byte("i\\u1 : 123456789")
|
|
_, err := gjson.LoadContentType("properties", errData, true)
|
|
t.AssertNE(err, nil)
|
|
})
|
|
}
|
|
|
|
func Test_Load_YAML_For_I18n(t *testing.T) {
|
|
var data = []byte(gtest.DataContent("yaml", "i18n-issue.yaml"))
|
|
gtest.C(t, func(t *gtest.T) {
|
|
j, err := gjson.LoadContent(data)
|
|
t.AssertNil(err)
|
|
j.SetViolenceCheck(true)
|
|
t.Assert(j.Get("resourceUsage.workflow").String(), "workflow")
|
|
})
|
|
}
|