20

I'm parsing a JSON object which contains an array of strings :

var ii interface{}
json := "{\"aString\": [\"aaa_111\", \"bbb_222\"], \"whatever\":\"ccc\"}"

err := json.Unmarshal([]byte(json), &ii)
if err != nil {
    log.Fatal(err)
}
data := ii.(map[string]interface{})
fmt.Println(data["aString"]) // outputs: ["aaa_111" "bbb_222"]

I tried to convert data["aString"] to []string to be able to loop over it, but it fails :

 test := []string(data["aString"]).([]string)
 fmt.Println(test) // panic -> interface conversion: 
                   //          interface is string, not []string

How can I convert data["aString"] ?


edit:

I didn't express myself properly. If I print data, I have such map :

map[aString:["BBB-222","AAA-111"] whatever:ccc]

I want to loop over aString (to manipule each array entry). But I can't find how, because aString is type interface {} :

for i, v := range aString { // <-- fails
     // ...
     fmt.Println(i, v)
}

That's why I want to convert aString. I don't want to convert a string which looks like an array to an array.

3
  • 1
    Do you know the exact structure of your JSON ? (Are the fields well defined or may they vary) Commented May 19, 2016 at 16:43
  • Your var ii should already be a map[string]interface {}... I see no reason to do the type assertion data := ii.(map[string]interface {}). Fixing that doesn't solve your problem, I just noticed it. Commented May 19, 2016 at 16:55
  • 1
    try this aStringValue := ii.(map[string]interface {})["aString"] Commented May 19, 2016 at 16:59

4 Answers 4

48

I recommend you move away from this implementation in general. Your json may vary but you can easily use objects and avoid all this type unsafe nonsense.

Anyway, that conversion doesn't work because the types inside the slice are not string, they're also interface{}. You have to iterate the collection then do a type assertion on each item like so:

aInterface := data["aString"].([]interface{})
aString := make([]string, len(aInterface))
for i, v := range aInterface {
    aString[i] = v.(string)
}
Sign up to request clarification or add additional context in comments.

7 Comments

@jérôme, I'm with Evan on this, but if you really need to unmarshal your JSON data to maps (there are valid use cases for this), consider using the mxj package.
but that's exactly the problem... I can't loop over data["aString"] since it's type interface {}
@Jérôme ah, ok. So first you have to type assert on the interface{} to []interface{} I can edit my answer to reflect this.
Please update the second data["aString"] to be aInterface. It then works :-)
@evanmcdonnal, pretty good chunk of code but a tiny mistake, you append to aString array, which is already allocated to the good size. Just assign it: aString[i] = v.(string) playground
|
5

Is it what you need?

package main

import (
    "fmt"
    "encoding/json"
)

func main() {
    js := "{\"aString\": [\"aaa_111\", \"bbb_222\"], \"whatever\":\"ccc\"}"
    a := make(map[string]interface{})
    json.Unmarshal([]byte(js), &a)
    for _, v := range a["aString"].([]interface{}) {
        str := v.(string)
        fmt.Println(str)
    }
}

Check on Go Playground

Comments

0

For another approach, you can use a struct instead:

package main

import (
   "encoding/json"
   "fmt"
)

func main() {
   s := []byte(`{"aString": ["aaa_111", "bbb_222"], "whatever":"ccc"}`)
   var t struct {
      Astring []string
      Whatever string
   }
   json.Unmarshal(s, &t)
   fmt.Printf("%+v\n", t) // {Astring:[aaa_111 bbb_222] Whatever:ccc}
}

Comments

0

I'm solving that by just Marshall and Unmarshall:

type Paragraph struct {
    Paragraph_id          string    `json:"paragraph_id"`
    Parent_document_id    string    `json:"parent_document_id"`
    Page_in_document      int       `json:"page_in_document"`
    Text                  string    `json:"text"`
    Previous_paragraph_id string    `json:"previous_paragraph_id"`
    Parent_paragraph_id   string    `json:"parent_paragraph_id"`
    Child_paragraph_ids   []string  `json:"child_paragraph_ids"`
    Next_paragraph_id     string    `json:"next_paragraph_id"`
    Summary               string    `json:"summary"`
    Vector                []float64 `json:"vector"`
    Definitions           []string  `json:"definitions"`
    Keywords              []string  `json:"keywords"`
    IsLeaf                bool      `json:"leaf"`
}

_, err := session.ExecuteRead(db_ctx, func(transaction neo4j.ManagedTransaction) (any, error) {
        result, _:= transaction.Run(db_ctx,
            "MATCH (paragraph:Paragraph) RETURN paragraph",
            map[string]any{},
        )

    paragraphs = []Paragraph{}

    for result.Next(db_ctx) {
            record := result.Record()       
            para, _ := record.Get("paragraph")
            properties := para.(neo4j.Node).GetProperties()
            bytes, _ := json.Marshal(properties)

            var paragraph knowledge_structs.Paragraph
            json.Unmarshal(bytes, &paragraph)

            paragraphs = append(paragraphs, paragraph)
}

Not sure how efficient it is ;)

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.