github.com/zhongdalu/gf@v1.0.0/g/encoding/gjson/gjson_api_new_load.go (about) 1 // Copyright 2017 gf Author(https://github.com/zhongdalu/gf). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/zhongdalu/gf. 6 7 // Package gjson provides convenient API for JSON/XML/YAML/TOML data handling. 8 package gjson 9 10 import ( 11 "bytes" 12 "encoding/json" 13 "errors" 14 "fmt" 15 "reflect" 16 17 "github.com/zhongdalu/gf/g/os/gfile" 18 19 "github.com/zhongdalu/gf/g/encoding/gtoml" 20 "github.com/zhongdalu/gf/g/encoding/gxml" 21 "github.com/zhongdalu/gf/g/encoding/gyaml" 22 "github.com/zhongdalu/gf/g/internal/rwmutex" 23 "github.com/zhongdalu/gf/g/os/gfcache" 24 "github.com/zhongdalu/gf/g/text/gregex" 25 "github.com/zhongdalu/gf/g/util/gconv" 26 ) 27 28 // New creates a Json object with any variable type of <data>, 29 // but <data> should be a map or slice for data access reason, 30 // or it will make no sense. 31 // The <unsafe> param specifies whether using this Json object 32 // in un-concurrent-safe context, which is false in default. 33 func New(data interface{}, unsafe ...bool) *Json { 34 j := (*Json)(nil) 35 switch data.(type) { 36 case string, []byte: 37 if r, err := LoadContent(gconv.Bytes(data)); err == nil { 38 j = r 39 } else { 40 j = &Json{ 41 p: &data, 42 c: byte(gDEFAULT_SPLIT_CHAR), 43 vc: false, 44 } 45 } 46 default: 47 rv := reflect.ValueOf(data) 48 kind := rv.Kind() 49 if kind == reflect.Ptr { 50 rv = rv.Elem() 51 kind = rv.Kind() 52 } 53 switch kind { 54 case reflect.Slice: 55 fallthrough 56 case reflect.Array: 57 i := interface{}(nil) 58 i = gconv.Interfaces(data) 59 j = &Json{ 60 p: &i, 61 c: byte(gDEFAULT_SPLIT_CHAR), 62 vc: false, 63 } 64 case reflect.Map: 65 fallthrough 66 case reflect.Struct: 67 i := interface{}(nil) 68 i = gconv.Map(data, "json") 69 j = &Json{ 70 p: &i, 71 c: byte(gDEFAULT_SPLIT_CHAR), 72 vc: false, 73 } 74 default: 75 j = &Json{ 76 p: &data, 77 c: byte(gDEFAULT_SPLIT_CHAR), 78 vc: false, 79 } 80 } 81 } 82 j.mu = rwmutex.New(unsafe...) 83 return j 84 } 85 86 // NewUnsafe creates a un-concurrent-safe Json object. 87 func NewUnsafe(data ...interface{}) *Json { 88 if len(data) > 0 { 89 return New(data[0], true) 90 } 91 return New(nil, true) 92 } 93 94 // Valid checks whether <data> is a valid JSON data type. 95 func Valid(data interface{}) bool { 96 return json.Valid(gconv.Bytes(data)) 97 } 98 99 // Encode encodes <value> to JSON data type of bytes. 100 func Encode(value interface{}) ([]byte, error) { 101 return json.Marshal(value) 102 } 103 104 // Decode decodes <data>(string/[]byte) to golang variable. 105 func Decode(data interface{}) (interface{}, error) { 106 var value interface{} 107 if err := DecodeTo(gconv.Bytes(data), &value); err != nil { 108 return nil, err 109 } else { 110 return value, nil 111 } 112 } 113 114 // Decode decodes <data>(string/[]byte) to specified golang variable <v>. 115 // The <v> should be a pointer type. 116 func DecodeTo(data interface{}, v interface{}) error { 117 decoder := json.NewDecoder(bytes.NewReader(gconv.Bytes(data))) 118 decoder.UseNumber() 119 return decoder.Decode(v) 120 } 121 122 // DecodeToJson codes <data>(string/[]byte) to a Json object. 123 func DecodeToJson(data interface{}, unsafe ...bool) (*Json, error) { 124 if v, err := Decode(gconv.Bytes(data)); err != nil { 125 return nil, err 126 } else { 127 return New(v, unsafe...), nil 128 } 129 } 130 131 // Load loads content from specified file <path>, 132 // and creates a Json object from its content. 133 func Load(path string, unsafe ...bool) (*Json, error) { 134 return doLoadContent(gfile.Ext(path), gfcache.GetBinContents(path), unsafe...) 135 } 136 137 func LoadJson(data interface{}, unsafe ...bool) (*Json, error) { 138 return doLoadContent("json", gconv.Bytes(data), unsafe...) 139 } 140 141 func LoadXml(data interface{}, unsafe ...bool) (*Json, error) { 142 return doLoadContent("xml", gconv.Bytes(data), unsafe...) 143 } 144 145 func LoadYaml(data interface{}, unsafe ...bool) (*Json, error) { 146 return doLoadContent("yaml", gconv.Bytes(data), unsafe...) 147 } 148 149 func LoadToml(data interface{}, unsafe ...bool) (*Json, error) { 150 return doLoadContent("toml", gconv.Bytes(data), unsafe...) 151 } 152 153 func doLoadContent(dataType string, data []byte, unsafe ...bool) (*Json, error) { 154 var err error 155 var result interface{} 156 if len(data) == 0 { 157 return New(nil, unsafe...), nil 158 } 159 if dataType == "" { 160 dataType = checkDataType(data) 161 } 162 switch dataType { 163 case "json", ".json": 164 165 case "xml", ".xml": 166 if data, err = gxml.ToJson(data); err != nil { 167 return nil, err 168 } 169 170 case "yml", "yaml", ".yml", ".yaml": 171 if data, err = gyaml.ToJson(data); err != nil { 172 return nil, err 173 } 174 175 case "toml", ".toml": 176 if data, err = gtoml.ToJson(data); err != nil { 177 return nil, err 178 } 179 180 default: 181 err = errors.New("unsupported type for loading") 182 } 183 if err != nil { 184 return nil, err 185 } 186 if result == nil { 187 decoder := json.NewDecoder(bytes.NewReader(data)) 188 decoder.UseNumber() 189 if err := decoder.Decode(&result); err != nil { 190 return nil, err 191 } 192 switch result.(type) { 193 case string, []byte: 194 return nil, fmt.Errorf(`json decoding failed for content: %s`, string(data)) 195 } 196 } 197 return New(result, unsafe...), nil 198 } 199 200 func LoadContent(data interface{}, unsafe ...bool) (*Json, error) { 201 content := gconv.Bytes(data) 202 if len(content) == 0 { 203 return New(nil, unsafe...), nil 204 } 205 return doLoadContent(checkDataType(content), content, unsafe...) 206 207 } 208 209 // checkDataType automatically checks and returns the data type for <content>. 210 func checkDataType(content []byte) string { 211 if json.Valid(content) { 212 return "json" 213 } else if gregex.IsMatch(`^<.+>[\S\s]+<.+>$`, content) { 214 return "xml" 215 } else if gregex.IsMatch(`^[\s\t]*[\w\-]+\s*:\s*.+`, content) || gregex.IsMatch(`\n[\s\t]*[\w\-]+\s*:\s*.+`, content) { 216 return "yml" 217 } else if gregex.IsMatch(`^[\s\t]*[\w\-]+\s*=\s*.+`, content) || gregex.IsMatch(`\n[\s\t]*[\w\-]+\s*=\s*.+`, content) { 218 return "toml" 219 } else { 220 return "" 221 } 222 }