Codebase list golang-github-xeipuuv-gojsonpointer / fresh-snapshots/main
[ Alexandre Viau ] [ Debian Janitor ] New upstream snapshot. Debian Janitor 4 years ago
4 changed file(s) with 247 addition(s) and 75 deletion(s). Raw diff Collapse all Expand all
00 # gojsonpointer
11 An implementation of JSON Pointer - Go language
2
3 ## Usage
4 jsonText := `{
5 "name": "Bobby B",
6 "occupation": {
7 "title" : "King",
8 "years" : 15,
9 "heir" : "Joffrey B"
10 }
11 }`
12
13 var jsonDocument map[string]interface{}
14 json.Unmarshal([]byte(jsonText), &jsonDocument)
15
16 //create a JSON pointer
17 pointerString := "/occupation/title"
18 pointer, _ := NewJsonPointer(pointerString)
19
20 //SET a new value for the "title" in the document
21 pointer.Set(jsonDocument, "Supreme Leader of Westeros")
22
23 //GET the new "title" from the document
24 title, _, _ := pointer.Get(jsonDocument)
25 fmt.Println(title) //outputs "Supreme Leader of Westeros"
26
27 //DELETE the "heir" from the document
28 deletePointer := NewJsonPointer("/occupation/heir")
29 deletePointer.Delete(jsonDocument)
30
31 b, _ := json.Marshal(jsonDocument)
32 fmt.Println(string(b))
33 //outputs `{"name":"Bobby B","occupation":{"title":"Supreme Leader of Westeros","years":15}}`
34
235
336 ## References
437 http://tools.ietf.org/html/draft-ietf-appsawg-json-pointer-07
0 golang-github-xeipuuv-gojsonpointer (0.0~git20151027.0.e0fe6f6-3) UNRELEASED; urgency=medium
0 golang-github-xeipuuv-gojsonpointer (0.0~git20190809.0.df4f5c8-1) UNRELEASED; urgency=medium
11
2 [ Alexandre Viau ]
23 * Point Vcs-* urls to salsa.debian.org.
34
4 -- Alexandre Viau <aviau@debian.org> Mon, 02 Apr 2018 21:16:21 -0400
5 [ Debian Janitor ]
6 * New upstream snapshot.
7
8 -- Debian Janitor <janitor@jelmer.uk> Sat, 17 Aug 2019 20:57:45 +0000
59
610 golang-github-xeipuuv-gojsonpointer (0.0~git20151027.0.e0fe6f6-2) unstable; urgency=medium
711
5151 outError error
5252 }
5353
54 func NewJsonPointer(jsonPointerString string) (JsonPointer, error) {
55
56 var p JsonPointer
57 err := p.parse(jsonPointerString)
58 return p, err
59
60 }
61
6254 type JsonPointer struct {
6355 referenceTokens []string
6456 }
6557
66 // "Constructor", parses the given string JSON pointer
67 func (p *JsonPointer) parse(jsonPointerString string) error {
68
69 var err error
70
71 if jsonPointerString != const_empty_pointer {
72 if !strings.HasPrefix(jsonPointerString, const_pointer_separator) {
73 err = errors.New(const_invalid_start)
74 } else {
75 referenceTokens := strings.Split(jsonPointerString, const_pointer_separator)
76 for _, referenceToken := range referenceTokens[1:] {
77 p.referenceTokens = append(p.referenceTokens, referenceToken)
78 }
79 }
80 }
81
82 return err
58 // NewJsonPointer parses the given string JSON pointer and returns an object
59 func NewJsonPointer(jsonPointerString string) (p JsonPointer, err error) {
60
61 // Pointer to the root of the document
62 if len(jsonPointerString) == 0 {
63 // Keep referenceTokens nil
64 return
65 }
66 if jsonPointerString[0] != '/' {
67 return p, errors.New(const_invalid_start)
68 }
69
70 p.referenceTokens = strings.Split(jsonPointerString[1:], const_pointer_separator)
71 return
8372 }
8473
8574 // Uses the pointer to retrieve a value from a JSON document
9887 p.implementation(is)
9988 return document, is.outError
10089
90 }
91
92 // Uses the pointer to delete a value from a JSON document
93 func (p *JsonPointer) Delete(document interface{}) (interface{}, error) {
94 is := &implStruct{mode: "DEL", inDocument: document}
95 p.implementation(is)
96 return document, is.outError
10197 }
10298
10399 // Both Get and Set functions use the same implementation to avoid code duplication
116112
117113 node := i.inDocument
118114
115 previousNodes := make([]interface{}, len(p.referenceTokens))
116 previousTokens := make([]string, len(p.referenceTokens))
117
119118 for ti, token := range p.referenceTokens {
120119
121 decodedToken := decodeReferenceToken(token)
122120 isLastToken := ti == len(p.referenceTokens)-1
123
124 rValue := reflect.ValueOf(node)
125 kind = rValue.Kind()
126
127 switch kind {
128
129 case reflect.Map:
130 m := node.(map[string]interface{})
131 if _, ok := m[decodedToken]; ok {
132 node = m[decodedToken]
121 previousNodes[ti] = node
122 previousTokens[ti] = token
123
124 switch v := node.(type) {
125
126 case map[string]interface{}:
127 decodedToken := decodeReferenceToken(token)
128 if _, ok := v[decodedToken]; ok {
129 node = v[decodedToken]
133130 if isLastToken && i.mode == "SET" {
134 m[decodedToken] = i.setInValue
131 v[decodedToken] = i.setInValue
132 } else if isLastToken && i.mode == "DEL" {
133 delete(v, decodedToken)
135134 }
135 } else if isLastToken && i.mode == "SET" {
136 v[decodedToken] = i.setInValue
136137 } else {
137 i.outError = errors.New(fmt.Sprintf("Object has no key '%s'", token))
138 i.getOutKind = kind
138 i.outError = fmt.Errorf("Object has no key '%s'", decodedToken)
139 i.getOutKind = reflect.Map
139140 i.getOutNode = nil
140141 return
141142 }
142143
143 case reflect.Slice:
144 s := node.([]interface{})
144 case []interface{}:
145145 tokenIndex, err := strconv.Atoi(token)
146146 if err != nil {
147 i.outError = errors.New(fmt.Sprintf("Invalid array index '%s'", token))
148 i.getOutKind = kind
147 i.outError = fmt.Errorf("Invalid array index '%s'", token)
148 i.getOutKind = reflect.Slice
149149 i.getOutNode = nil
150150 return
151151 }
152 sLength := len(s)
153 if tokenIndex < 0 || tokenIndex >= sLength {
154 i.outError = errors.New(fmt.Sprintf("Out of bound array[0,%d] index '%d'", sLength, tokenIndex))
155 i.getOutKind = kind
152 if tokenIndex < 0 || tokenIndex >= len(v) {
153 i.outError = fmt.Errorf("Out of bound array[0,%d] index '%d'", len(v), tokenIndex)
154 i.getOutKind = reflect.Slice
156155 i.getOutNode = nil
157156 return
158157 }
159158
160 node = s[tokenIndex]
159 node = v[tokenIndex]
161160 if isLastToken && i.mode == "SET" {
162 s[tokenIndex] = i.setInValue
161 v[tokenIndex] = i.setInValue
162 } else if isLastToken && i.mode == "DEL" {
163 v[tokenIndex] = v[len(v)-1]
164 v[len(v)-1] = nil
165 v = v[:len(v)-1]
166 previousNodes[ti-1].(map[string]interface{})[previousTokens[ti-1]] = v
163167 }
164168
165169 default:
166 i.outError = errors.New(fmt.Sprintf("Invalid token reference '%s'", token))
167 i.getOutKind = kind
170 i.outError = fmt.Errorf("Invalid token reference '%s'", token)
171 i.getOutKind = reflect.ValueOf(node).Kind()
168172 i.getOutNode = nil
169173 return
170174 }
171175
172176 }
173177
174 rValue := reflect.ValueOf(node)
175 kind = rValue.Kind()
176
177178 i.getOutNode = node
178 i.getOutKind = kind
179 i.getOutKind = reflect.ValueOf(node).Kind()
179180 i.outError = nil
180181 }
181182
196197 // ~1 => /
197198 // ... and vice versa
198199
199 const (
200 const_encoded_reference_token_0 = `~0`
201 const_encoded_reference_token_1 = `~1`
202 const_decoded_reference_token_0 = `~`
203 const_decoded_reference_token_1 = `/`
204 )
205
206200 func decodeReferenceToken(token string) string {
207 step1 := strings.Replace(token, const_encoded_reference_token_1, const_decoded_reference_token_1, -1)
208 step2 := strings.Replace(step1, const_encoded_reference_token_0, const_decoded_reference_token_0, -1)
201 step1 := strings.Replace(token, `~1`, `/`, -1)
202 step2 := strings.Replace(step1, `~0`, `~`, -1)
209203 return step2
210204 }
211205
212206 func encodeReferenceToken(token string) string {
213 step1 := strings.Replace(token, const_decoded_reference_token_1, const_encoded_reference_token_1, -1)
214 step2 := strings.Replace(step1, const_decoded_reference_token_0, const_encoded_reference_token_0, -1)
207 step1 := strings.Replace(token, `~`, `~0`, -1)
208 step2 := strings.Replace(step1, `/`, `~1`, -1)
215209 return step2
216210 }
1414 // author xeipuuv
1515 // author-github https://github.com/xeipuuv
1616 // author-mail xeipuuv@gmail.com
17 //
17 //
1818 // repository-name gojsonpointer
1919 // repository-desc An implementation of JSON Pointer - Go language
20 //
20 //
2121 // description Automated tests on package.
22 //
22 //
2323 // created 03-03-2013
2424
2525 package gojsonpointer
3030 )
3131
3232 const (
33 TEST_DOCUMENT_NB_ELEMENTS = 11
33 TEST_DOCUMENT_NB_ELEMENTS = 13
3434 TEST_NODE_OBJ_NB_ELEMENTS = 4
3535 TEST_DOCUMENT_STRING = `{
3636 "foo": ["bar", "baz"],
4343 "i\\j": 5,
4444 "k\"l": 6,
4545 " ": 7,
46 "m~n": 8
46 "m~n": 8,
47 "o~/p": 9,
48 "q/~r": 10
4749 }`
4850 )
4951
5557
5658 func TestEscaping(t *testing.T) {
5759
58 ins := []string{`/`, `/`, `/a~1b`, `/a~1b`, `/c%d`, `/e^f`, `/g|h`, `/i\j`, `/k"l`, `/ `, `/m~0n`}
59 outs := []float64{0, 0, 1, 1, 2, 3, 4, 5, 6, 7, 8}
60 ins := []string{`/`, `/`, `/a~1b`, `/a~1b`, `/c%d`, `/e^f`, `/g|h`, `/i\j`, `/k"l`, `/ `, `/m~0n`, `/o~0~1p`, `/q~1~0r`}
61 outs := []float64{0, 0, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
6062
6163 for i := range ins {
6264
6365 p, err := NewJsonPointer(ins[i])
6466 if err != nil {
6567 t.Errorf("NewJsonPointer(%v) error %v", ins[i], err.Error())
68 }
69 s := p.String()
70 if s != ins[i] {
71 t.Errorf("\"%v\" -> \"%v\"", ins[i], s)
6672 }
6773
6874 result, _, err := p.Get(testDocumentJson)
7783
7884 }
7985
86 func BenchmarkParse(b *testing.B) {
87 for i := 0; i < b.N; i++ {
88 NewJsonPointer(`/definitions/simple/0/next`)
89 }
90 }
91
92 func BenchmarkParseWithEscape(b *testing.B) {
93 for i := 0; i < b.N; i++ {
94 NewJsonPointer(`/definiti~0ons/simple/0/next`)
95 }
96 }
97
98 func BenchmarkString(b *testing.B) {
99 p, _ := NewJsonPointer(`/definitions/simple/0/next`)
100 b.ResetTimer()
101 for i := 0; i < b.N; i++ {
102 p.String()
103 }
104 }
105
106 func BenchmarkStringWithEscape(b *testing.B) {
107 p, _ := NewJsonPointer(`/definiti~0ons/simple/0/next`)
108 b.ResetTimer()
109 for i := 0; i < b.N; i++ {
110 p.String()
111 }
112 }
113
80114 func TestFullDocument(t *testing.T) {
81115
82116 in := ``
112146
113147 if len(result.(map[string]interface{})) != TEST_NODE_OBJ_NB_ELEMENTS {
114148 t.Errorf("Get(%v) = %v, expect full document", in, result)
149 }
150 }
151
152 func BenchmarkGet(b *testing.B) {
153 p, _ := NewJsonPointer(`/obj/d/1/f`)
154 b.ResetTimer()
155 for i := 0; i < b.N; i++ {
156 p.Get(testDocumentJson)
115157 }
116158 }
117159
202244 }
203245
204246 }
247
248 func TestSetEmptyNode(t *testing.T) {
249
250 jsonText := `{}`
251
252 var jsonDocument interface{}
253 json.Unmarshal([]byte(jsonText), &jsonDocument)
254
255 in := "/a"
256
257 p, err := NewJsonPointer(in)
258 if err != nil {
259 t.Errorf("NewJsonPointer(%v) error %v", in, err.Error())
260 }
261
262 _, err = p.Set(jsonDocument, 999)
263 if err != nil {
264 t.Errorf("Set(%v) error %v", in, err.Error())
265 }
266
267 firstNode := jsonDocument.(map[string]interface{})
268 target := firstNode["a"].(int)
269 if target != 999 {
270 t.Errorf("Set(%s) failed", in)
271 }
272 }
273
274 func TestDelObject(t *testing.T) {
275 jsonText := `{
276 "a":["apple sauce", "ketchup", "soy sauce"],
277 "d": {
278 "z" : {
279 "v" : {
280 "name" : "donald mcbobble",
281 "occupation" : "corporate overlord"
282 }
283 }
284 }
285 }`
286
287 var jsonDocument map[string]interface{}
288 json.Unmarshal([]byte(jsonText), &jsonDocument)
289
290 //Deleting an object key
291 in := "/d/z/v/occupation"
292 p, err := NewJsonPointer(in)
293 if err != nil {
294 t.Errorf("NewJsonPointer(%v) error %v", in, err.Error())
295 }
296
297 _, err = p.Delete(jsonDocument)
298 if err != nil {
299 t.Errorf("Delete(%v) error %v", in, err.Error())
300 }
301
302 var d map[string]interface{} = jsonDocument["d"].(map[string]interface{})
303 var z map[string]interface{} = d["z"].(map[string]interface{})
304 var v map[string]interface{} = z["v"].(map[string]interface{})
305
306 if _, present := v["occupation"]; present {
307 t.Errorf("Delete (%s) failed: key is still present in the map", in)
308 }
309 }
310
311 func TestDelArray(t *testing.T) {
312 jsonText := `{
313 "a":["applesauce", "ketchup", "soysauce", "oliveoil"],
314 "d": {
315 "z" : {
316 "v" : {
317 "name" : "donald mcbobble",
318 "occupation" : "corporate overlord",
319 "responsibilities" : ["managing", "hiring"]
320 }
321 }
322 }
323 }`
324
325 var jsonDocument map[string]interface{}
326 json.Unmarshal([]byte(jsonText), &jsonDocument)
327
328 //Deleting an array member
329 in := "/a/2"
330 p, err := NewJsonPointer(in)
331 if err != nil {
332 t.Errorf("NewJsonPointer(%v) error %v", in, err.Error())
333 }
334
335 _, err = p.Delete(jsonDocument)
336 if err != nil {
337 t.Errorf("Delete(%v) error %v", in, err.Error())
338 }
339
340 a := jsonDocument["a"].([]interface{})
341 if len(a) != 3 || a[2] == "soysauce" {
342 t.Errorf("Delete(%v) error (%s)", in, a)
343 }
344
345 }