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  }