Я читаю JSON в ответ на конечную точку HTTP и хотел бы извлечь содержимое массива объектов, вложенных внутрь. Ответ может быть большим, поэтому я пытаюсь использовать потоковый подход, а не просто json. Уничтожение всего этого. JSON выглядит так:
{
"useless_thing_1": { /* etc */ },
"useless_thing_2": { /* etc */ },
"the_things_i_want": [
{ /* complex object I want to json.Unmarshal #1 */ },
{ /* complex object I want to json.Unmarshal #2 */ },
{ /* complex object I want to json.Unmarshal #3 */ },
/* could be many thousands of these */
],
"useless_thing_3": { /* etc */ },
}
Библиотека json, поставляемая с Go, имеет json.Unmarshal
, которая хорошо работает для полных JSON объектов. Он также имеет json.Decoder
, который может демаршировать полные объекты или предоставлять отдельные жетоны. Я могу использовать этот токенизатор для тщательного go прохождения и извлечения чего-либо, но логика c для этого несколько сложна, и я не могу тогда легко использовать json.Unmarshal
для объекта после того, как прочитал его как токены.
json .Decoder буферизируется, что затрудняет чтение одного объекта (т.е. { /* complex object I want to json.Unmarshal #1 */ }
), а затем потребляет сам ,
и создает новый json.Decoder
- потому что он будет пытаться использовать запятую сам. Это тот подход, который я пробовал и не смог добиться успеха.
Я ищу лучшее решение этой проблемы. Вот неправильный код, когда я пытался вручную использовать запятые:
// code here that naively looks for `"the_things_i_want": [` and
// puts the next bytes after that in `buffer`
// this is the rest of the stream starting from `{ /* complex object I want to json.Unmarshal #1 */ },`
in := io.MultiReader(buffer, res.Body)
dec := json.NewDecoder(in)
for {
var p MyComplexThing
err := dec.Decode(&p)
if err != nil {
panic(err)
}
// steal the comma from in directly - this does not work because the decoder buffer's its input
var b1 [1]byte
_, err = io.ReadAtLeast(in, b1[:], 1) // returns random data from later in the stream
if err != nil {
panic(err)
}
switch b1[0] {
case ',':
// skip over it
case ']':
break // we're done
default:
panic(fmt.Errorf("Unexpected result from read %#v", b1))
}
}