mirror of
https://gitee.com/johng/gf.git
synced 2024-12-02 04:07:47 +08:00
improve package gjson/ghttp
This commit is contained in:
parent
587af6dec8
commit
1e141d9f64
@ -22,8 +22,17 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
// Separator char for hierarchical data access.
|
||||
defaultSplitChar = '.'
|
||||
ContentTypeJson = `json`
|
||||
ContentTypeJs = `js`
|
||||
ContentTypeXml = `xml`
|
||||
ContentTypeIni = `ini`
|
||||
ContentTypeYaml = `yaml`
|
||||
ContentTypeYml = `yml`
|
||||
ContentTypeToml = `toml`
|
||||
)
|
||||
|
||||
const (
|
||||
defaultSplitChar = '.' // Separator char for hierarchical data access.
|
||||
)
|
||||
|
||||
// Json is the customized JSON struct.
|
||||
@ -34,10 +43,11 @@ type Json struct {
|
||||
vc bool // Violence Check(false in default), which is used to access data when the hierarchical data key contains separator char.
|
||||
}
|
||||
|
||||
// Options for Json object creating.
|
||||
// Options for Json object creating/loading.
|
||||
type Options struct {
|
||||
Safe bool // Mark this object is for in concurrent-safe usage. This is especially for Json object creating.
|
||||
Tags string // Custom priority tags for decoding. Eg: "json,yaml,MyTag". This is especially for struct parsing into Json object.
|
||||
Tags string // Custom priority tags for decoding, eg: "json,yaml,MyTag". This is especially for struct parsing into Json object.
|
||||
Type string // Type specifies the data content type, eg: json, xml, yaml, toml, ini.
|
||||
StrNumber bool // StrNumber causes the Decoder to unmarshal a number into an interface{} as a string instead of as a float64.
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@ import (
|
||||
"github.com/gogf/gf/v2/internal/rwmutex"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
@ -30,7 +31,7 @@ import (
|
||||
// The parameter `safe` specifies whether using this Json object in concurrent-safe context,
|
||||
// which is false in default.
|
||||
func New(data interface{}, safe ...bool) *Json {
|
||||
return NewWithTag(data, "json", safe...)
|
||||
return NewWithTag(data, ContentTypeJson, safe...)
|
||||
}
|
||||
|
||||
// NewWithTag creates a Json object with any variable type of `data`, but `data` should be a map
|
||||
@ -104,56 +105,73 @@ func Load(path string, safe ...bool) (*Json, error) {
|
||||
} else {
|
||||
path = p
|
||||
}
|
||||
option := Options{}
|
||||
if len(safe) > 0 && safe[0] {
|
||||
option.Safe = true
|
||||
options := Options{
|
||||
Type: gfile.Ext(path),
|
||||
}
|
||||
return doLoadContentWithOptions(gfile.Ext(path), gfile.GetBytesWithCache(path), option)
|
||||
if len(safe) > 0 && safe[0] {
|
||||
options.Safe = true
|
||||
}
|
||||
return doLoadContentWithOptions(gfile.GetBytesWithCache(path), options)
|
||||
}
|
||||
|
||||
// LoadWithOptions creates a Json object from given JSON format content and options.
|
||||
func LoadWithOptions(data interface{}, options Options) (*Json, error) {
|
||||
return doLoadContentWithOptions(gconv.Bytes(data), options)
|
||||
}
|
||||
|
||||
// LoadJson creates a Json object from given JSON format content.
|
||||
func LoadJson(data interface{}, safe ...bool) (*Json, error) {
|
||||
option := Options{}
|
||||
option := Options{
|
||||
Type: ContentTypeJson,
|
||||
}
|
||||
if len(safe) > 0 && safe[0] {
|
||||
option.Safe = true
|
||||
}
|
||||
return doLoadContentWithOptions("json", gconv.Bytes(data), option)
|
||||
return doLoadContentWithOptions(gconv.Bytes(data), option)
|
||||
}
|
||||
|
||||
// LoadXml creates a Json object from given XML format content.
|
||||
func LoadXml(data interface{}, safe ...bool) (*Json, error) {
|
||||
option := Options{}
|
||||
option := Options{
|
||||
Type: ContentTypeXml,
|
||||
}
|
||||
if len(safe) > 0 && safe[0] {
|
||||
option.Safe = true
|
||||
}
|
||||
return doLoadContentWithOptions("xml", gconv.Bytes(data), option)
|
||||
return doLoadContentWithOptions(gconv.Bytes(data), option)
|
||||
}
|
||||
|
||||
// LoadIni creates a Json object from given INI format content.
|
||||
func LoadIni(data interface{}, safe ...bool) (*Json, error) {
|
||||
option := Options{}
|
||||
option := Options{
|
||||
Type: ContentTypeIni,
|
||||
}
|
||||
if len(safe) > 0 && safe[0] {
|
||||
option.Safe = true
|
||||
}
|
||||
return doLoadContentWithOptions("ini", gconv.Bytes(data), option)
|
||||
return doLoadContentWithOptions(gconv.Bytes(data), option)
|
||||
}
|
||||
|
||||
// LoadYaml creates a Json object from given YAML format content.
|
||||
func LoadYaml(data interface{}, safe ...bool) (*Json, error) {
|
||||
option := Options{}
|
||||
option := Options{
|
||||
Type: ContentTypeYaml,
|
||||
}
|
||||
if len(safe) > 0 && safe[0] {
|
||||
option.Safe = true
|
||||
}
|
||||
return doLoadContentWithOptions("yaml", gconv.Bytes(data), option)
|
||||
return doLoadContentWithOptions(gconv.Bytes(data), option)
|
||||
}
|
||||
|
||||
// LoadToml creates a Json object from given TOML format content.
|
||||
func LoadToml(data interface{}, safe ...bool) (*Json, error) {
|
||||
option := Options{}
|
||||
option := Options{
|
||||
Type: ContentTypeToml,
|
||||
}
|
||||
if len(safe) > 0 && safe[0] {
|
||||
option.Safe = true
|
||||
}
|
||||
return doLoadContentWithOptions("toml", gconv.Bytes(data), option)
|
||||
return doLoadContentWithOptions(gconv.Bytes(data), option)
|
||||
}
|
||||
|
||||
// LoadContent creates a Json object from given content, it checks the data type of `content`
|
||||
@ -179,11 +197,13 @@ func LoadContentType(dataType string, data interface{}, safe ...bool) (*Json, er
|
||||
if content[0] == 0xEF && content[1] == 0xBB && content[2] == 0xBF {
|
||||
content = content[3:]
|
||||
}
|
||||
option := Options{}
|
||||
if len(safe) > 0 && safe[0] {
|
||||
option.Safe = true
|
||||
options := Options{
|
||||
Type: dataType,
|
||||
}
|
||||
return doLoadContentWithOptions(dataType, content, option)
|
||||
if len(safe) > 0 && safe[0] {
|
||||
options.Safe = true
|
||||
}
|
||||
return doLoadContentWithOptions(content, options)
|
||||
}
|
||||
|
||||
// IsValidDataType checks and returns whether given `dataType` a valid data type for loading.
|
||||
@ -195,7 +215,14 @@ func IsValidDataType(dataType string) bool {
|
||||
dataType = dataType[1:]
|
||||
}
|
||||
switch dataType {
|
||||
case "json", "js", "xml", "yaml", "yml", "toml", "ini":
|
||||
case
|
||||
ContentTypeJson,
|
||||
ContentTypeJs,
|
||||
ContentTypeXml,
|
||||
ContentTypeYaml,
|
||||
ContentTypeYml,
|
||||
ContentTypeToml,
|
||||
ContentTypeIni:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@ -206,10 +233,13 @@ func loadContentWithOptions(data interface{}, options Options) (*Json, error) {
|
||||
if len(content) == 0 {
|
||||
return NewWithOptions(nil, options), nil
|
||||
}
|
||||
return loadContentTypeWithOptions(checkDataType(content), content, options)
|
||||
if options.Type == "" {
|
||||
options.Type = checkDataType(content)
|
||||
}
|
||||
return loadContentTypeWithOptions(content, options)
|
||||
}
|
||||
|
||||
func loadContentTypeWithOptions(dataType string, data interface{}, options Options) (*Json, error) {
|
||||
func loadContentTypeWithOptions(data interface{}, options Options) (*Json, error) {
|
||||
content := gconv.Bytes(data)
|
||||
if len(content) == 0 {
|
||||
return NewWithOptions(nil, options), nil
|
||||
@ -218,13 +248,13 @@ func loadContentTypeWithOptions(dataType string, data interface{}, options Optio
|
||||
if content[0] == 0xEF && content[1] == 0xBB && content[2] == 0xBF {
|
||||
content = content[3:]
|
||||
}
|
||||
return doLoadContentWithOptions(dataType, content, options)
|
||||
return doLoadContentWithOptions(content, options)
|
||||
}
|
||||
|
||||
// doLoadContent creates a Json object from given content.
|
||||
// It supports data content type as follows:
|
||||
// JSON, XML, INI, YAML and TOML.
|
||||
func doLoadContentWithOptions(dataType string, data []byte, options Options) (*Json, error) {
|
||||
func doLoadContentWithOptions(data []byte, options Options) (*Json, error) {
|
||||
var (
|
||||
err error
|
||||
result interface{}
|
||||
@ -232,34 +262,39 @@ func doLoadContentWithOptions(dataType string, data []byte, options Options) (*J
|
||||
if len(data) == 0 {
|
||||
return NewWithOptions(nil, options), nil
|
||||
}
|
||||
if dataType == "" {
|
||||
dataType = checkDataType(data)
|
||||
if options.Type == "" {
|
||||
options.Type = checkDataType(data)
|
||||
}
|
||||
switch dataType {
|
||||
case "json", ".json", ".js":
|
||||
options.Type = gstr.TrimLeft(options.Type, ".")
|
||||
switch options.Type {
|
||||
case ContentTypeJson, ContentTypeJs:
|
||||
|
||||
case "xml", ".xml":
|
||||
case ContentTypeXml:
|
||||
if data, err = gxml.ToJson(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
case "yml", "yaml", ".yml", ".yaml":
|
||||
case ContentTypeYaml, ContentTypeYml:
|
||||
if data, err = gyaml.ToJson(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
case "toml", ".toml":
|
||||
case ContentTypeToml:
|
||||
if data, err = gtoml.ToJson(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
case "ini", ".ini":
|
||||
case ContentTypeIni:
|
||||
if data, err = gini.ToJson(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
default:
|
||||
err = gerror.NewCodef(gcode.CodeInvalidParameter, `unsupported type "%s" for loading`, dataType)
|
||||
err = gerror.NewCodef(
|
||||
gcode.CodeInvalidParameter,
|
||||
`unsupported type "%s" for loading`,
|
||||
options.Type,
|
||||
)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -268,7 +303,7 @@ func doLoadContentWithOptions(dataType string, data []byte, options Options) (*J
|
||||
if options.StrNumber {
|
||||
decoder.UseNumber()
|
||||
}
|
||||
if err := decoder.Decode(&result); err != nil {
|
||||
if err = decoder.Decode(&result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch result.(type) {
|
||||
@ -283,23 +318,23 @@ func doLoadContentWithOptions(dataType string, data []byte, options Options) (*J
|
||||
// functions to load the content for certain content type.
|
||||
func checkDataType(content []byte) string {
|
||||
if json.Valid(content) {
|
||||
return "json"
|
||||
return ContentTypeJson
|
||||
} else if gregex.IsMatch(`^<.+>[\S\s]+<.+>\s*$`, content) {
|
||||
return "xml"
|
||||
return ContentTypeXml
|
||||
} else if !gregex.IsMatch(`[\n\r]*[\s\t\w\-\."]+\s*=\s*"""[\s\S]+"""`, content) &&
|
||||
!gregex.IsMatch(`[\n\r]*[\s\t\w\-\."]+\s*=\s*'''[\s\S]+'''`, content) &&
|
||||
((gregex.IsMatch(`^[\n\r]*[\w\-\s\t]+\s*:\s*".+"`, content) || gregex.IsMatch(`^[\n\r]*[\w\-\s\t]+\s*:\s*\w+`, content)) ||
|
||||
(gregex.IsMatch(`[\n\r]+[\w\-\s\t]+\s*:\s*".+"`, content) || gregex.IsMatch(`[\n\r]+[\w\-\s\t]+\s*:\s*\w+`, content))) {
|
||||
return "yml"
|
||||
return ContentTypeYaml
|
||||
} else if !gregex.IsMatch(`^[\s\t\n\r]*;.+`, content) &&
|
||||
!gregex.IsMatch(`[\s\t\n\r]+;.+`, content) &&
|
||||
!gregex.IsMatch(`[\n\r]+[\s\t\w\-]+\.[\s\t\w\-]+\s*=\s*.+`, content) &&
|
||||
(gregex.IsMatch(`[\n\r]*[\s\t\w\-\."]+\s*=\s*".+"`, content) || gregex.IsMatch(`[\n\r]*[\s\t\w\-\."]+\s*=\s*\w+`, content)) {
|
||||
return "toml"
|
||||
return ContentTypeToml
|
||||
} else if gregex.IsMatch(`\[[\w\.]+\]`, content) &&
|
||||
(gregex.IsMatch(`[\n\r]*[\s\t\w\-\."]+\s*=\s*".+"`, content) || gregex.IsMatch(`[\n\r]*[\s\t\w\-\."]+\s*=\s*\w+`, content)) {
|
||||
// Must contain "[xxx]" section.
|
||||
return "ini"
|
||||
return ContentTypeIni
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
|
@ -170,7 +170,10 @@ func (r *Request) GetBodyString() string {
|
||||
// GetJson parses current request content as JSON format, and returns the JSON object.
|
||||
// Note that the request content is read from request BODY, not from any field of FORM.
|
||||
func (r *Request) GetJson() (*gjson.Json, error) {
|
||||
return gjson.LoadJson(r.GetBody())
|
||||
return gjson.LoadWithOptions(r.GetBody(), gjson.Options{
|
||||
Type: gjson.ContentTypeJson,
|
||||
StrNumber: true,
|
||||
})
|
||||
}
|
||||
|
||||
// GetMap is an alias and convenient function for GetRequestMap.
|
||||
|
Loading…
Reference in New Issue
Block a user