# Parsequoted=true in JSON.jl

**URL:** <https://discourse.julialang.org/t/parsequoted-true-in-json-jl/139486>\
**Category:** Data\
**Tags:** json, data\
**Created:** [September 15, 2026, 3:32pm UTC](https://discourse.julialang.org/t/parsequoted-true-in-json-jl/139486 "2026-09-15T15:32:16Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![freeman](https://avatars.discourse-cdn.com/v4/letter/f/ec9cab/32.png) [@freeman](https://discourse.julialang.org/u/freeman)\
**Post date:** [September 15, 2026, 3:32pm UTC](https://discourse.julialang.org/t/parsequoted-true-in-json-jl/139486/1 "2026-09-15T15:32:16Z")

</div>

JSON3 had the ability to automatically handle quoted numbers. For example

```julia-auto
import JSON3

struct MyType
    x::Float64
end

s = "{\"x\":\"4.0\"}" # note quoted "4.0"

JSON3.read(s, MyType; parsequoted=true) # MyType(4.0)

```

Is this possible to achieve with `JSON.parse`? I haven’t been able to find it in the migration guide[1].

[1] [Migration Guides · JSON.jl](https://juliaio.github.io/JSON.jl/stable/migrate/#Reading-JSON)

---

<div class="post-metadata">

**Author:** ![quinnj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/quinnj/32/11_2.png) [@quinnj](https://discourse.julialang.org/u/quinnj)\
**Post date:** [September 15, 2026, 4:20pm UTC](https://discourse.julialang.org/t/parsequoted-true-in-json-jl/139486/2 "2026-09-15T16:20:03Z")

</div>

There’s no `parsequoted` keyword argument in JSON.jl 1.0 — but you can get the capability yourself, via a custom _style_ instead of a keyword argument:

```Julia
using JSON

struct MyType
    x::Float64
end

struct QuotedNumbers <: JSON.JSONStyle end
JSON.lift(::QuotedNumbers, ::Type{T}, x::AbstractString) where {T<:Real} = parse(T, x)

JSON.parse("{\"x\":\"4.0\"}", MyType; style=QuotedNumbers()) # MyType(4.0)

```

The style applies everywhere in the document, so it handles the nested cases too — struct fields, `Vector{Float64}`, `Dict` values, `Union{Float64, Nothing}` fields, and top-level scalars. `String` fields are unaffected, and `null` still comes through as `nothing`:

```Julia
struct Inner; y::Int; end
struct Outer; a::Float64; b::Inner; c::Vector{Float64}; d::Union{Float64,Nothing}; e::String; end

JSON.parse("""{"a":"1.5","b":{"y":"7"},"c":["1","2.5"],"d":null,"e":"hello"}""",
           Outer; style=QuotedNumbers())
# Outer(1.5, Inner(7), [1.0, 2.5], nothing, "hello")

```

One thing this gets you that `parsequoted` never did: add the matching `lower` and the numbers **round-trip back out quoted** , instead of silently becoming unquoted on write.

```Julia
JSON.lower(::QuotedNumbers, x::Real) = string(x)

v = JSON.parse("{\"x\":\"4.0\"}", MyType; style=QuotedNumbers())
JSON.json(v; style=QuotedNumbers()) # {"x":"4.0"}
JSON.json(v) # {"x":4.0} (default style, unchanged)

```

If only one field is quoted rather than the whole document, you can skip the style entirely and put a `lift` on that field (using StructUtils `@tags` macro and the “field tag” syntax starting with `&`):

```Julia
@tags struct Mixed
    x::Float64 &(lift = v -> v isa AbstractString ? parse(Float64, v) : Float64(v),)
    y::Float64
end

JSON.parse("{\"x\":\"4.0\",\"y\":5.0}", Mixed) # Mixed(4.0, 5.0)

```

A caveat worth knowing: you now own the corner cases, because `parse(T, x)` decides them. In particular `""` will throw rather than give you `nothing`, and `"7.0"` into an `Int` field will throw. Both are easy to handle in the `lift` body if your source does that — which is honestly an improvement over JSON3, where a couple of those cases escaped as a bare `AssertionError: b == UInt8('"')`.

---

<div class="post-metadata">

**Author:** ![freeman](https://avatars.discourse-cdn.com/v4/letter/f/ec9cab/32.png) [@freeman](https://discourse.julialang.org/u/freeman)\
**Post date:** [September 15, 2026, 8:13pm UTC](https://discourse.julialang.org/t/parsequoted-true-in-json-jl/139486/3 "2026-09-15T20:13:12Z")

</div>

Works, thank you!

---

<div class="post-metadata">

**Author:** ![freeman](https://avatars.discourse-cdn.com/v4/letter/f/ec9cab/32.png) [@freeman](https://discourse.julialang.org/u/freeman)\
**Post date:** [September 16, 2026, 5:15pm UTC](https://discourse.julialang.org/t/parsequoted-true-in-json-jl/139486/4 "2026-09-16T17:15:51Z")

</div>

If you have the patience for one more, here’s a similar question for FixedDecimal:

```julia-auto
import FixedPointDecimals: FixedDecimal

struct MyType
    x::FixedDecimal{Int,8}
end

s = "{\"x\":4.0}"
JSON.parse(s, MyType)

```

```julia-auto
ERROR: ArgumentError: applyeach not applicable for `JSON.LazyValue{String}` with JSON type = `JSONTypes.NUMBER`

```

In this case, this didn’t solve it:

```julia-auto
JSON.lift(::Type{FixedDecimal{Int,8}}, x::AbstractString) = parse(FixedDecimal{Int,8}, x)

```

(and would be type-piracy)

Also doesn’t work:

```julia-auto
struct FixedDecimalStyle <: JSON.JSONStyle end

JSON.lift(
    ::FixedDecimalStyle,
    ::Type{FixedDecimal{Int,8}},
    x::Number,
) = FixedDecimal{Int,8}(x)

JSON.parse(s, MyType; style=FixedDecimalStyle())

```

Actually, I don’t understand why this last one doesn’t work…

---

<div class="post-metadata">

**Author:** ![quinnj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/quinnj/32/11_2.png) [@quinnj](https://discourse.julialang.org/u/quinnj)\
**Post date:** [September 17, 2026, 2:22pm UTC](https://discourse.julialang.org/t/parsequoted-true-in-json-jl/139486/5 "2026-09-17T14:22:13Z")

</div>

This should work now! I dug into it a bit, and found we actually had a bug in StructUtils where the `structlike` definition was on `Type{Number}` instead of the intended `Type{<:Number}`. With that fixed, there are new patch releases of StructUtils.jl and JSON.jl and your original example should work. Thanks for the report that helped catch a bug!
