123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138 |
- // 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 gproperties provides accessing and converting for .properties content.
- package gproperties
- import (
- "bytes"
- "sort"
- "strings"
- "github.com/magiconair/properties"
- "github.com/gogf/gf/v2/errors/gerror"
- "github.com/gogf/gf/v2/internal/json"
- "github.com/gogf/gf/v2/util/gconv"
- )
- // Decode converts properties format to map.
- func Decode(data []byte) (res map[string]interface{}, err error) {
- res = make(map[string]interface{})
- pr, err := properties.Load(data, properties.UTF8)
- if err != nil || pr == nil {
- err = gerror.Wrapf(err, `Lib magiconair load Properties data failed.`)
- return nil, err
- }
- for _, key := range pr.Keys() {
- // ignore existence check: we know it's there
- value, _ := pr.Get(key)
- // recursively build nested maps
- path := strings.Split(key, ".")
- lastKey := strings.ToLower(path[len(path)-1])
- deepestMap := deepSearch(res, path[0:len(path)-1])
- // set innermost value
- deepestMap[lastKey] = value
- }
- return res, nil
- }
- // Encode converts map to properties format.
- func Encode(data map[string]interface{}) (res []byte, err error) {
- pr := properties.NewProperties()
- flattened := map[string]interface{}{}
- flattened = flattenAndMergeMap(flattened, data, "", ".")
- keys := make([]string, 0, len(flattened))
- for key := range flattened {
- keys = append(keys, key)
- }
- sort.Strings(keys)
- for _, key := range keys {
- _, _, err := pr.Set(key, gconv.String(flattened[key]))
- if err != nil {
- err = gerror.Wrapf(err, `Sets the property key to the corresponding value failed.`)
- return nil, err
- }
- }
- var buf bytes.Buffer
- _, err = pr.Write(&buf, properties.UTF8)
- if err != nil {
- err = gerror.Wrapf(err, `Properties Write buf failed.`)
- return nil, err
- }
- return buf.Bytes(), nil
- }
- // ToJson convert .properties format to JSON.
- func ToJson(data []byte) (res []byte, err error) {
- prMap, err := Decode(data)
- if err != nil {
- return nil, err
- }
- return json.Marshal(prMap)
- }
- // deepSearch scans deep maps, following the key indexes listed in the sequence "path".
- // The last value is expected to be another map, and is returned.
- func deepSearch(m map[string]interface{}, path []string) map[string]interface{} {
- for _, k := range path {
- m2, ok := m[k]
- if !ok {
- // intermediate key does not exist
- // => create it and continue from there
- m3 := make(map[string]interface{})
- m[k] = m3
- m = m3
- continue
- }
- m3, ok := m2.(map[string]interface{})
- if !ok {
- m3 = make(map[string]interface{})
- m[k] = m3
- }
- // continue search from here
- m = m3
- }
- return m
- }
- // flattenAndMergeMap recursively flattens the given map into a new map
- func flattenAndMergeMap(shadow map[string]interface{}, m map[string]interface{}, prefix string, delimiter string) map[string]interface{} {
- if shadow != nil && prefix != "" && shadow[prefix] != nil {
- return shadow
- }
- var m2 map[string]interface{}
- if prefix != "" {
- prefix += delimiter
- }
- for k, val := range m {
- fullKey := prefix + k
- switch val.(type) {
- case map[string]interface{}:
- m2 = val.(map[string]interface{})
- case map[interface{}]interface{}:
- m2 = gconv.Map(val)
- default:
- // immediate value
- shadow[strings.ToLower(fullKey)] = val
- continue
- }
- // recursively merge to shadow map
- shadow = flattenAndMergeMap(shadow, m2, fullKey, delimiter)
- }
- return shadow
- }
|