...

Source file src/github.com/xeipuuv/gojsonschema/utils.go

Documentation: github.com/xeipuuv/gojsonschema

     1  // Copyright 2015 xeipuuv ( https://github.com/xeipuuv )
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //   http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // author           xeipuuv
    16  // author-github    https://github.com/xeipuuv
    17  // author-mail      xeipuuv@gmail.com
    18  //
    19  // repository-name  gojsonschema
    20  // repository-desc  An implementation of JSON Schema, based on IETF's draft v4 - Go language.
    21  //
    22  // description      Various utility functions.
    23  //
    24  // created          26-02-2013
    25  
    26  package gojsonschema
    27  
    28  import (
    29  	"encoding/json"
    30  	"math/big"
    31  	"reflect"
    32  )
    33  
    34  func isKind(what interface{}, kinds ...reflect.Kind) bool {
    35  	target := what
    36  	if isJSONNumber(what) {
    37  		// JSON Numbers are strings!
    38  		target = *mustBeNumber(what)
    39  	}
    40  	targetKind := reflect.ValueOf(target).Kind()
    41  	for _, kind := range kinds {
    42  		if targetKind == kind {
    43  			return true
    44  		}
    45  	}
    46  	return false
    47  }
    48  
    49  func existsMapKey(m map[string]interface{}, k string) bool {
    50  	_, ok := m[k]
    51  	return ok
    52  }
    53  
    54  func isStringInSlice(s []string, what string) bool {
    55  	for i := range s {
    56  		if s[i] == what {
    57  			return true
    58  		}
    59  	}
    60  	return false
    61  }
    62  
    63  // indexStringInSlice returns the index of the first instance of 'what' in s or -1 if it is not found in s.
    64  func indexStringInSlice(s []string, what string) int {
    65  	for i := range s {
    66  		if s[i] == what {
    67  			return i
    68  		}
    69  	}
    70  	return -1
    71  }
    72  
    73  func marshalToJSONString(value interface{}) (*string, error) {
    74  
    75  	mBytes, err := json.Marshal(value)
    76  	if err != nil {
    77  		return nil, err
    78  	}
    79  
    80  	sBytes := string(mBytes)
    81  	return &sBytes, nil
    82  }
    83  
    84  func marshalWithoutNumber(value interface{}) (*string, error) {
    85  
    86  	// The JSON is decoded using https://golang.org/pkg/encoding/json/#Decoder.UseNumber
    87  	// This means the numbers are internally still represented as strings and therefore 1.00 is unequal to 1
    88  	// One way to eliminate these differences is to decode and encode the JSON one more time without Decoder.UseNumber
    89  	// so that these differences in representation are removed
    90  
    91  	jsonString, err := marshalToJSONString(value)
    92  	if err != nil {
    93  		return nil, err
    94  	}
    95  
    96  	var document interface{}
    97  
    98  	err = json.Unmarshal([]byte(*jsonString), &document)
    99  	if err != nil {
   100  		return nil, err
   101  	}
   102  
   103  	return marshalToJSONString(document)
   104  }
   105  
   106  func isJSONNumber(what interface{}) bool {
   107  
   108  	switch what.(type) {
   109  
   110  	case json.Number:
   111  		return true
   112  	}
   113  
   114  	return false
   115  }
   116  
   117  func checkJSONInteger(what interface{}) (isInt bool) {
   118  
   119  	jsonNumber := what.(json.Number)
   120  
   121  	bigFloat, isValidNumber := new(big.Rat).SetString(string(jsonNumber))
   122  
   123  	return isValidNumber && bigFloat.IsInt()
   124  
   125  }
   126  
   127  // same as ECMA Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER
   128  const (
   129  	maxJSONFloat = float64(1<<53 - 1)  // 9007199254740991.0 	 2^53 - 1
   130  	minJSONFloat = -float64(1<<53 - 1) //-9007199254740991.0	-2^53 - 1
   131  )
   132  
   133  func mustBeInteger(what interface{}) *int {
   134  
   135  	if isJSONNumber(what) {
   136  
   137  		number := what.(json.Number)
   138  
   139  		isInt := checkJSONInteger(number)
   140  
   141  		if isInt {
   142  
   143  			int64Value, err := number.Int64()
   144  			if err != nil {
   145  				return nil
   146  			}
   147  
   148  			int32Value := int(int64Value)
   149  			return &int32Value
   150  		}
   151  
   152  	}
   153  
   154  	return nil
   155  }
   156  
   157  func mustBeNumber(what interface{}) *big.Rat {
   158  
   159  	if isJSONNumber(what) {
   160  		number := what.(json.Number)
   161  		float64Value, success := new(big.Rat).SetString(string(number))
   162  		if success {
   163  			return float64Value
   164  		}
   165  	}
   166  
   167  	return nil
   168  
   169  }
   170  
   171  func convertDocumentNode(val interface{}) interface{} {
   172  
   173  	if lval, ok := val.([]interface{}); ok {
   174  
   175  		res := []interface{}{}
   176  		for _, v := range lval {
   177  			res = append(res, convertDocumentNode(v))
   178  		}
   179  
   180  		return res
   181  
   182  	}
   183  
   184  	if mval, ok := val.(map[interface{}]interface{}); ok {
   185  
   186  		res := map[string]interface{}{}
   187  
   188  		for k, v := range mval {
   189  			res[k.(string)] = convertDocumentNode(v)
   190  		}
   191  
   192  		return res
   193  
   194  	}
   195  
   196  	return val
   197  }
   198  

View as plain text