Advanced Feature Examples
This document provides complete examples of advanced features: batch encoding, pre-parsing, hooks, advanced configuration, and more.
Batch Encoding
EncodeBatch
Quickly encode multiple key-value pairs into a JSON object:
package main
import (
"fmt"
"github.com/cybergodev/json"
)
func main() {
// Build JSON from scattered data
pairs := map[string]any{
"id": 1001,
"name": "Alice",
"email": "[email protected]",
"active": true,
"tags": []string{"admin", "user"},
"balance": 1250.50,
}
// Batch-encode into a JSON object with EncodeBatch
result, err := json.EncodeBatch(pairs)
if err != nil {
panic(err)
}
fmt.Println(result)
// Pretty-printed output with EncodeBatch + PrettyConfig
pretty, err := json.EncodeBatch(pairs, json.PrettyConfig())
if err != nil {
panic(err)
}
fmt.Println(pretty)
}Encoding Selected Fields
EncodeFields
Encode only the specified fields of a struct — good for filtering sensitive information from API responses:
package main
import (
"fmt"
"github.com/cybergodev/json"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
Password string `json:"password"`
Salt string `json:"salt"`
}
func main() {
user := User{
ID: 1,
Name: "Alice",
Email: "[email protected]",
Password: "secret123",
Salt: "randomsalt",
}
// Encode only public fields (excluding sensitive information)
publicFields := []string{"id", "name", "email"}
result, err := json.EncodeFields(user, publicFields)
if err != nil {
panic(err)
}
fmt.Println(result)
// {"id":1,"name":"Alice","email":"[email protected]"}
}Pre-Parse Optimization
PreParse
Pre-parse JSON to avoid repeated parsing and speed up multiple queries:
package main
import (
"fmt"
"github.com/cybergodev/json"
)
func main() {
// Large JSON data
largeJSON := `{
"users": [
{"id": 1, "name": "Alice", "email": "[email protected]"},
{"id": 2, "name": "Bob", "email": "[email protected]"},
{"id": 3, "name": "Charlie", "email": "[email protected]"}
],
"metadata": {
"total": 3,
"page": 1,
"perPage": 10
}
}`
p, err := json.New()
if err != nil {
panic(err)
}
defer p.Close()
// Pre-parse (parse once); Release when done to drop the parse-tree reference
parsed, err := p.PreParse(largeJSON)
if err != nil {
panic(err)
}
defer parsed.Release()
// Reuse the pre-parsed result across queries
total, _ := p.GetFromParsed(parsed, "metadata.total")
page, _ := p.GetFromParsed(parsed, "metadata.page")
// Walk the users
for i := 0; i < 3; i++ {
path := fmt.Sprintf("users.%d.name", i)
name, _ := p.GetFromParsed(parsed, path)
fmt.Printf("User %d: %v\n", i, name)
}
fmt.Printf("Total: %v, Page: %v\n", total, page)
}Pre-Compiling Hot Paths
CompilePath + GetCompiled
PreParse optimizes "many paths against one JSON"; conversely, when the same path queries many different JSONs (e.g. every request reads user.name), use CompilePath to pre-compile and reuse the path-parsing result, saving the per-call path parsing:
package main
import (
"fmt"
"github.com/cybergodev/json"
)
func main() {
p, err := json.New()
if err != nil {
panic(err)
}
defer p.Close()
// Simulate continuously arriving, distinct JSON documents
docs := []string{
`{"user":{"name":"Alice","age":28}}`,
`{"user":{"name":"Bob","age":34}}`,
`{"user":{"name":"Carol","age":25}}`,
}
// Compile once; the path-parsing result enters the global compiled cache;
// Release when done
cp, err := p.CompilePath("user.name")
if err != nil {
panic(err)
}
defer cp.Release()
for _, doc := range docs {
name, err := p.GetCompiled(doc, cp)
if err != nil {
panic(err)
}
fmt.Println("name =", name)
}
}
// Output:
// name = Alice
// name = Bob
// name = CarolDivision of labor with PreParse
GetCompiled still runs input security validation and JSON parsing on every call — what it saves is only the path parsing. Choose by hotspot direction: repeated queries on one document → PreParse; repeated use of one path → CompilePath. Set/Delete currently have no Compiled variants; pre-compiled paths are query-only.
Safe Access
SafeGet
Returns a structured result supporting chained calls and type conversion:
package main
import (
"fmt"
"github.com/cybergodev/json"
)
func main() {
data := `{
"user": {
"id": 1001,
"name": "Alice",
"age": 28,
"active": true,
"balance": 1250.50
}
}`
p, err := json.New()
if err != nil {
panic(err)
}
defer p.Close()
// Safely get a single field
nameResult := p.SafeGet(data, "user.name")
if nameResult.Ok() {
name, _ := nameResult.AsString()
fmt.Println("Name:", name)
}
// Safely get with type conversion
ageResult := p.SafeGet(data, "user.age")
if ageResult.Ok() {
age, _ := ageResult.AsInt()
fmt.Println("Age:", age)
}
// Safely get a boolean
activeResult := p.SafeGet(data, "user.active")
if activeResult.Ok() {
active, _ := activeResult.AsBool()
fmt.Println("Active:", active)
}
// A missing path does not panic
emailResult := p.SafeGet(data, "user.email")
fmt.Println("Email exists:", emailResult.Ok()) // false
// Use a default value
email := emailResult.UnwrapOr("N/A")
fmt.Println("Email:", email)
}Cache Warm-Up
WarmupCache
Warm up the cache of commonly used paths to speed up later queries:
package main
import (
"fmt"
"github.com/cybergodev/json"
)
func main() {
// Large JSON data (simulated)
largeJSON := `{
"products": [
{"id": 1, "name": "Product A", "price": 100},
{"id": 2, "name": "Product B", "price": 200},
{"id": 3, "name": "Product C", "price": 300}
],
"categories": ["electronics", "books", "clothing"],
"settings": {"currency": "USD", "taxRate": 0.1}
}`
p, err := json.New()
if err != nil {
panic(err)
}
defer p.Close()
// Define the common paths
commonPaths := []string{
"products",
"products.0.id",
"products.0.name",
"products.1.id",
"products.1.name",
"categories",
"settings.currency",
}
// Warm up the cache
result, err := p.WarmupCache(largeJSON, commonPaths)
if err != nil {
panic(err)
}
fmt.Printf("Warm-up complete: %d/%d succeeded\n", result.Successful, result.TotalPaths)
if len(result.FailedPaths) > 0 {
fmt.Println("Failed paths:", result.FailedPaths)
}
// Subsequent queries hit the cache
for i := 0; i < 3; i++ {
path := fmt.Sprintf("products.%d.name", i)
name := p.GetString(largeJSON, path)
fmt.Printf("Product %d: %s\n", i, name)
}
}Batch Operations
ProcessBatch
Execute multiple operations in one batch for efficiency:
package main
import (
"fmt"
"github.com/cybergodev/json"
)
func main() {
data := `{"users": [{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}]}`
// Define the batch operations (the ID identifies each operation in the results)
operations := []json.BatchOperation{
{ID: "get-name", Type: "get", Path: "users.0.name", JSONStr: data},
{ID: "get-users", Type: "get", Path: "users", JSONStr: data},
{ID: "set-name", Type: "set", Path: "users.0.name", Value: "Updated", JSONStr: data},
{ID: "del-id", Type: "delete", Path: "users.0.id", JSONStr: data},
}
// Execute the batch
results, err := json.ProcessBatch(operations)
if err != nil {
panic(err)
}
// Inspect the results
for _, r := range results {
fmt.Printf("ID: %s\n", r.ID)
if r.Error != nil {
fmt.Printf(" Error: %v\n", r.Error)
} else if r.Result != nil {
fmt.Printf(" Value: %v\n", r.Result)
}
}
}Key/Value Memory Optimization
The library internally uses a string interning pool to automatically reduce memory used by repeated keys and values. No manual management needed.
package main
import (
"fmt"
"github.com/cybergodev/json"
)
func main() {
// The library automatically interns repeated key/value strings
// When processing large volumes, repeated string keys reuse memory
records := make([]map[string]any, 10000)
for i := range records {
records[i] = map[string]any{
"status": "active",
"type": "user",
"role": "member",
}
}
// Memory is optimized internally during batch encoding
result, _ := json.Marshal(map[string]any{
"status": "active",
"type": "user",
})
fmt.Println("Sample:", string(result))
}Next Steps
- Path Expression Syntax — Complete path syntax reference
- Large File Handling — Streaming guide
- API Reference — Complete API reference