1

I'm trying to use tidwall/sjson to modify properties in a json object, but getting the following error:

./prog.go:34:77: syntax error: unexpected {, expecting expression

Here's my code:

package main

import (
    "fmt"
    "github.com/tidwall/sjson"
)

func main() {
    config := `{
                 "root": {
                   "obj1Arr": [
                     {
                       "obj2": {
                         "obj3Arr": [
                           {
                             "key1": "val1",
                             "key2": {
                               "val2": ["a", "b"]
                             }
                           },
                           {
                             "key3": "val3",
                             "key4": "val4"
                           }
                         ]
                       }
                     }
                   ]
                 },
                 "strExample": "bar",
                 "boolExample": true,
                 "floatExample": 12.54
               }`
    value, _ := sjson.Set(config, "root.obj1Arr.0.obj2.obj3Arr", []interface{}[{"hello":"world"}])
    fmt.Println(value)
}

You can reproduce the error with this go playground link. I'm trying to modify the object root.obj1Arr[0].obj2.obj3Arr to simply have a single object inside of it. I'm also trying to work with an unstructured object. How can I fix this error?

4
  • @meagar Can you let me know where in the SO guidelines it mentioned questions cannot depend on link to external code-hosting services. I don't have an issue in posting the code to my question, but it sounds weird link to an external code-hosting service is not allowed as it's super easy for anyone to go there and look/run the code Commented Jul 29, 2021 at 23:29
  • @meagar The post has been updated with the code in the question. Please re-open this question Commented Jul 29, 2021 at 23:32
  • The requirement that code goes into the question is explicitly stated here: stackoverflow.com/help/how-to-ask. This is typically a well known requirement for people who have used this site for any length of time. Links to 3rd party services are not disallowed, but your question cannot depend on them to be meaningful or answerable, whether it's JSFiddle or Github or a live website or Pastebin or any other resource. If the rest of the Internet goes away, your question needs to remain answerable. Commented Jul 30, 2021 at 0:39
  • Thanks @meagar. Commented Jul 30, 2021 at 16:25

3 Answers 3

2

A slice composite literal is created using {} instead of [] e.g.

value, _ := sjson.Set(config, "root.obj1Arr.0.obj2.obj3Arr", []interface{}{map[string]string{"hello":"world"}})

https://play.golang.org/p/1h07L5KNVTR

Note that you cannot create an anonymous object using composite literal syntax. I chose to use a map[string]string in the example. If your types aren't that simple, or simply aren't known, you can use map[string]interface{} e.g. map[string]interface{}{"my": map[string]interface{}{"nested": []string{"values", "are", "here"}}}

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks Gavin. How would this change if the value to override is a JSON object which might be unstructured. For example in the above example, let's say the value to replace is something like {"hello": "world", "key2": {"a": "b"}}. What i'm trying to get to is to build a function which will given an input JSON object, modify the value in the keys for that object. And that value to be replaced could be of any data type viz. string, bool, float, unstructured nested JSON object etc.
@user320550 I extended my answer to cover case you ask for in above comment too.
@user320550 I've updated my answer to include a note about map[string]interface{}.
@Gavin blami, Thank you for the pointers. It did help me understand more. I don't know if this mandates a separate question, but having a hard time trying to come up with the generic logic to update the value of a key of a JSON Object where that value could be of any time viz. string, int, nested complex json object. So for e.g. the value for a key could be overriden with any type. May be i'm new to golang, but in your examples how do compute say the "map[string]interface{}{"my": map[string]interface{}{"nested": []string{"values", "are", "here"}}}" expression dynamically from it's JSON object.
Please ignore my above comment. I was able to resolve that.
1

Based on the suggestions changing replacing []interface{}[{"hello":"world"}] with []interface{}{map[string]string{"hello": "world"}}

package main

import (
    "fmt"
    "github.com/tidwall/sjson"
)

func main() {
    config := `{
                    "root": {
                      "obj1Arr": [
                    {
                  "obj2": {
                      "obj3Arr": [
                        {
                          "key1": "val1",
                          "key2": {
                            "val2": ["a", "b"]
                          }
                            },
                        {
                          "key3": "val3",
                          "key4": "val4"
                        }
                           ]
                  }
                }
                  ]
            },
            "strExample": "bar",
            "boolExample": true,
            "floatExample": 12.54
          }`
    value, _ := sjson.Set(config, "root.obj1Arr.0.obj2.obj3Arr", []interface{}{map[string]string{"hello": "world"}})
    fmt.Println(value)

}

Output:

{
                    "root": {
                      "obj1Arr": [
                        {
                          "obj2": {
                              "obj3Arr": [{"hello":"world"}]
                          }
                        }
                      ]
                    },
                    "strExample": "bar",
                    "boolExample": true,
                    "floatExample": 12.54
                  }

Comments

1

Your []interface{}[{"hello":"world"}] is not valid Go expression as

  1. Slice literal is initialized with []type{...} and not []type[...]
  2. Literal you use to initialize a map inside slice (what you want in object array in JSON) is not valid as it lacks type in front of it, should be: map[string]string{"hello": "world"}

So to modify obj3Arr to be an array of map[string]string the code should be something like:

value, _ := sjson.Set(config, "root.obj1Arr.0.obj2.obj3Arr", []map[string]string{map[string]string{"hello":"world"}})

To work with objects where you don't know structure and types at compile time (as per "I'm also trying to work with an unstructured object" in your question) you will need empty interface{} as type in map instead of string: map[string]interface{}. So that you can store various types in that map values:

value, _ := sjson.Set(config, "root.obj1Arr.0.obj2.obj3Arr", []interface{}{
map[string]interface{}{
    "hello": "world", 
    "key2": true, 
    "listkey": []int{1,2,3,4}, 
    "mapkey": map[int][]bool{1: []bool{true, true, false}}},
})

will produce:

"obj3Arr": [{"hello":"world","key2":true,"listkey":[1,2,3,4],"mapkey":{"1":[true,true,false]}}]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.