You are probably looking for json.RawMessage.
For example:
package main
import (
"encoding/json"
"fmt"
"log"
)
func main() {
txt := []byte(`
[
{"key1" : "value1" },
{"key2" : "value2" }
]`)
msg := []json.RawMessage{}
err := json.Unmarshal(txt, &msg)
if err != nil {
log.Fatal(err)
}
for _, c := range msg {
fmt.Printf("%s\n", string(c))
}
}
Note that the redundant white space in the example separating the key/value pairs is intentional: you will see that these are preserved in the output.
Alternatively, even if you don't care about the exact structure, you can still dynamically poke at it by using an interface{} variable. See the JSON and Go document for a running example of this, under the Generic JSON with interface{} section.
If we are trying to do something like a streaming approach, we may attempt to do something custom with the io.Reader. The JSON parser assumes you can represent everything in memory at once. That assumption may not hold in your situation, so we have to break a few things.
Perhaps we might manually consume bytes in the io.Reader till we eat the leading [ character, and then repeatedly call json.Decode on the rest of the io.Reader. Something like this:
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"log"
)
func main() {
var txt io.Reader = bytes.NewBufferString(`
[
{"key1" : "value1" },
{"key2" : "value2" }
]`)
buf := make([]byte, 1)
for {
_, err := txt.Read(buf)
if err != nil {
log.Fatal(err)
}
if buf[0] == '[' {
break
}
}
for {
decoder := json.NewDecoder(txt)
msg := json.RawMessage{}
err := decoder.Decode(&msg)
if err != nil {
break
}
fmt.Printf("I see: %s\n", string(msg))
txt = decoder.Buffered()
for {
_, err := txt.Read(buf)
if err != nil {
log.Fatal(err)
}
if buf[0] == ',' || buf[0] == ']' {
break
}
}
}
}
This code is severely kludgy and non-obvious. I also don't think it's a good idea. If you have to deal with this in a streaming fashion, then JSON is likely not a good serialization format for this scenario. If you have control over the input, then you should consider changing it so it's more amendable to a streaming approach: hacks like what we're doing here are a bad smell that the input is in the wrong shape.