|
| 1 | +# JSONX - Simple JSON Parser |
| 2 | + |
| 3 | +A simple, no-dependency JSON parser that can be vendored (copied/pasted) into other packages. |
| 4 | + |
| 5 | +## Features |
| 6 | + |
| 7 | +### Parsing |
| 8 | +- `JSONX.parse(json_str::String)` - Parse a JSON string |
| 9 | +- `JSONX.parse(bytes::AbstractVector{UInt8})` - Parse JSON from byte array |
| 10 | +- `JSONX.parsefile(filename::String)` - Parse JSON from a file |
| 11 | + |
| 12 | +### Writing |
| 13 | +- `JSONX.json(value)` - Convert a Julia value to JSON string |
| 14 | + |
| 15 | +### Supported Types |
| 16 | + |
| 17 | +**Reading (JSON → Julia):** |
| 18 | +- `null` → `nothing` |
| 19 | +- `true`/`false` → `Bool` |
| 20 | +- Numbers → `Float64` (all numbers are parsed as Float64) |
| 21 | +- Strings → `String` (with full Unicode support) |
| 22 | +- Arrays → `Vector{Any}` |
| 23 | +- Objects → `Dict{String, Any}` |
| 24 | + |
| 25 | +**Writing (Julia → JSON):** |
| 26 | +- `nothing`/`missing` → `null` |
| 27 | +- `Bool` → `true`/`false` |
| 28 | +- `Number` → JSON number |
| 29 | +- `AbstractString` → JSON string |
| 30 | +- `AbstractVector`/`AbstractSet`/`Tuple` → JSON array |
| 31 | +- `AbstractDict`/`NamedTuple` → JSON object |
| 32 | +- `Symbol`/`Enum` → JSON string |
| 33 | + |
| 34 | +### Unicode Support |
| 35 | + |
| 36 | +JSONX includes full Unicode support: |
| 37 | +- Proper Unicode escape sequence parsing (`\uXXXX`) |
| 38 | +- UTF-16 surrogate pair handling |
| 39 | +- Lone surrogate handling |
| 40 | +- All standard JSON escape sequences (`\"`, `\\`, `\/`, `\b`, `\f`, `\n`, `\r`, `\t`) |
| 41 | + |
| 42 | +## Usage |
| 43 | + |
| 44 | +```julia |
| 45 | +using JSONX |
| 46 | + |
| 47 | +# Parse JSON |
| 48 | +data = JSONX.parse("{\"name\":\"John\",\"age\":30}") |
| 49 | +# Returns: Dict("name" => "John", "age" => 30.0) |
| 50 | + |
| 51 | +# Parse from bytes |
| 52 | +bytes = Vector{UInt8}("{\"key\":\"value\"}") |
| 53 | +data = JSONX.parse(bytes) |
| 54 | + |
| 55 | +# Parse from file |
| 56 | +data = JSONX.parsefile("data.json") |
| 57 | + |
| 58 | +# Write JSON |
| 59 | +json_str = JSONX.json(Dict("a" => 1, "b" => 2)) |
| 60 | +# Returns: "{\"a\":1,\"b\":2}" |
| 61 | + |
| 62 | +# Unicode examples |
| 63 | +JSONX.parse("\"Hello 世界! 🌍\"") # Full Unicode support |
| 64 | +JSONX.parse("\"\\u0048\\u0065\\u006C\\u006C\\u006F\"") # Unicode escapes |
| 65 | +``` |
| 66 | + |
| 67 | +## Error Handling |
| 68 | + |
| 69 | +JSONX provides detailed error messages for invalid JSON: |
| 70 | +- Unexpected end of input |
| 71 | +- Invalid escape sequences |
| 72 | +- Malformed Unicode escapes |
| 73 | +- Trailing commas |
| 74 | +- Control characters in strings |
| 75 | +- Invalid number formats |
| 76 | + |
| 77 | +## Limitations |
| 78 | + |
| 79 | +Compared to the full JSON.jl package, JSONX is intentionally simplified: |
| 80 | + |
| 81 | +- **No integer parsing**: All numbers are parsed as Float64 |
| 82 | +- **No custom type parsing**: Only returns basic Julia types |
| 83 | +- **No configuration options**: Uses fixed defaults |
| 84 | +- **No streaming**: Loads entire input into memory |
| 85 | +- **No pretty printing**: Output is compact only |
| 86 | +- **No schema validation**: Basic JSON validation only |
| 87 | +- **No performance optimizations**: Simple, readable implementation |
| 88 | + |
| 89 | +## Implementation Notes |
| 90 | + |
| 91 | +- **No dependencies**: Uses only Base Julia functionality |
| 92 | +- **Byte-level processing**: Uses `codeunit` for accurate string handling |
| 93 | +- **Memory efficient**: Avoids unnecessary string concatenation |
| 94 | +- **Error robust**: Comprehensive error checking and reporting |
| 95 | + |
| 96 | +Note: Functions are not exported, so use `JSONX.parse` and `JSONX.json` with the module prefix. |
0 commit comments