Skip to content

Instantly share code, notes, and snippets.

@mosajjal
Created January 6, 2024 23:00
Show Gist options
  • Save mosajjal/be9fb970940c18f91f8edd97c39702d6 to your computer and use it in GitHub Desktop.
Save mosajjal/be9fb970940c18f91f8edd97c39702d6 to your computer and use it in GitHub Desktop.
flatten nested json strings
// use:
// cat nested.json | go run . > flattenned.json
package main
import (
"bytes"
"compress/gzip"
"encoding/base64"
"fmt"
"io"
"log"
"os"
"testing"
"time"
"github.com/jeremywohl/flatten/v2"
)
const (
maxBufferSize = 102400
)
func main() {
b := make([]byte, 1)
c := make(chan byte, 2)
fd := os.Stdout
go start(c, fd)
for {
n, err := os.Stdin.Read(b)
if err != nil && err != io.EOF {
log.Fatal(err)
}
if n == 0 {
// sleep for a bit
time.Sleep(100 * time.Millisecond)
break
}
c <- b[0]
}
}
func start(c chan byte, fd io.Writer) {
buf := make([]byte, maxBufferSize)
openBracket := 0
count := 0
inObject := false
// Read stdin into buffer
for ch := range c {
if ch == '\n' || ch == '\r' || ch == ' ' || ch == '\t' {
continue
}
if ch == '{' {
openBracket++
inObject = true
}
if ch == '}' {
openBracket--
}
if !inObject && (ch == '[' || ch == ']') {
continue
}
if ch == ',' && !inObject {
continue
}
buf[count] = ch
count++
if openBracket == 0 && inObject {
// flatten buffer and print
flat, err := flatten.FlattenString(string(buf[:count]), "", flatten.DotStyle)
if err != nil {
log.Println(err, string(buf[:count]))
}
fmt.Fprintln(fd, flat)
buf = make([]byte, maxBufferSize)
inObject = false
count = 0
}
}
}
var testJSON1BB64GZ = "H4sIAAAAAAACA+2QvQ6CQBCE+3uKzdZQiD+FNdHEwgasCMUBK7fJcZfAUhDiu3tijIWFPoBbbPPtzGammJGHyuEecJWs4812FydJghGAAtSjGN8HpiDMvGwAtHoQpzt6iFJPGL3Alfs3OWlHuJBbpJAali9WWcdifjELUFjsAnJDcLHCnRaCVIuu9ECQydhMcBy5oWcUwDoctL6fgqjAs3fxgWth7wLHnGrjvPXthKUKH/6dfHRSqjuB6mvcKgIAAA=="
func gzipDecode(data []byte) ([]byte, error) {
gz, err := gzip.NewReader(bytes.NewReader(data))
if err != nil {
return nil, err
}
defer gz.Close()
return io.ReadAll(gz)
}
func BenchmarkMain(b *testing.B) {
//un-base64 and un-gzip the test data
testJSON1B, _ := base64.StdEncoding.DecodeString(testJSON1BB64GZ)
testJSON1B, _ = gzipDecode(testJSON1B)
c := make(chan byte)
go func() {
for _, ch := range testJSON1B {
c <- ch
}
close(c)
}()
nullOut := io.Discard
for i := 0; i < b.N; i++ {
start(c, nullOut)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment