norwat norwat - 1 month ago 7
HTTP Question

Parsing explicit arrays

I'm trying to parse this type of response from a server:

[[1,"a","b",2,"000000",[[1,2,3],[1,2,3]],"x","y","z",[[1,2,3],[1,2,3]]]]


Besides writing my own hack'ish parser for this type of messages is there a standard way to interpret this that I'm not aware of?

Answer

Your input is a JSON string. In Go, you can use the encoding/json package to decode it.

Usually, when the structure of the JSON string is known prior, a Go struct type can be constructed which models it, and then you can unmarshal into a value of that struct type.

If the structure is unknown or is varying, you may unmarshal into a value of type interface{} which can be the target of any JSON data:

s := `[[1,"a","b",2,"000000",[[1,2,3],[1,2,3]],"x","y","z",[[1,2,3],[1,2,3]]]]`

var v interface{}
if err := json.Unmarshal([]byte(s), &v); err != nil {
    fmt.Println(err)
    return
}
fmt.Println(v)
fmt.Printf("%#v\n", v)

Output (try it on the Go Playground):

[[1 a b 2 000000 [[1 2 3] [1 2 3]] x y z [[1 2 3] [1 2 3]]]]
[]interface {}{[]interface {}{1, "a", "b", 2, "000000", []interface {}{[]interface {}{1, 2, 3}, []interface {}{1, 2, 3}}, "x", "y", "z", []interface {}{[]interface {}{1, 2, 3}, []interface {}{1, 2, 3}}}}

As you can see, the result is a slice of slices, with elements of varying types (JSON numbers, strings and even more slices).

Here's the same output adding indentation to get a better feeling of it (using Go's composite literal syntax):

[]interface{}{
    []interface{}{
        1, "a", "b", 2, "000000",
        []interface{}{
            []interface{}{1, 2, 3},
            []interface{}{1, 2, 3}},
        "x", "y", "z",
        []interface{}{
            []interface{}{1, 2, 3},
            []interface{}{1, 2, 3},
        },
    },
}

Of course this is not very convenient, as you have to use type assertion to "extract" values from this "generic" value of type interface{}, for example to extract the first 2 non-arrays values (also printing their types for verification):

fmt.Printf("%T %[1]v\n", v.([]interface{})[0].([]interface{})[0])
fmt.Printf("%T %[1]v\n", v.([]interface{})[0].([]interface{})[1])

Output:

float64 1
string a

Worth noting that JSON numbers in Go are unmarshaled to a value of type float64 even though they could be integers (unless another type is explicitly specified).