87 lines
3.0 KiB
Julia
87 lines
3.0 KiB
Julia
""" Recursively convert dictionary-like variable (e.g. JSON.Object) into a dictionary.
|
|
The function walks any nested structure composed of `AbstractDict` (e.g., `JSON.Object`,
|
|
`Dict`, `OrderedDict`) and `AbstractArray` and produces a new tree where
|
|
every dictionary-like node is a plain `Dict` and every array-like node is a
|
|
`Vector{Any}`. Scalar values (numbers, strings, booleans, `nothing`, etc.)
|
|
are returned unchanged.
|
|
Does **not** mutate the input; it always allocates new containers.
|
|
|
|
# Arguments
|
|
- `x`
|
|
Any Julia value. If `x` is an `AbstractDict` it will be converted to a `Dict`;
|
|
if it is an `AbstractArray` its elements will be processed recursively.
|
|
|
|
# Keyword Arguments
|
|
- `keytype::Type=Any`
|
|
The key type for the output Dict. Use `String` for `Dict{String,Any}`, `Symbol` for `Dict{Symbol,Any}`, or `Any` to preserve original key types.
|
|
- `stringkey::Bool=false`
|
|
If `true`, every dictionary key is converted to `String` via `string(k)`. This parameter is ignored when `keytype` is explicitly set.
|
|
|
|
# Return
|
|
- A newly allocated nested structure composed of `Dict{keytype,Any}` and
|
|
`Vector{Any}` that mirrors the input shape but uses plain Julia containers.
|
|
|
|
# Notes
|
|
- The function treats any `AbstractDict` as a mapping source, so it works with
|
|
`JSON.Object`, `Dict`, `OrderedDict`, etc.
|
|
- Arrays are returned as `Vector{Any}` with their elements processed
|
|
recursively.
|
|
|
|
# Examples
|
|
```jldoctest
|
|
julia> using JSON
|
|
julia> d = Dict(
|
|
"a" => 4,
|
|
"b" => 6,
|
|
"c" => Dict(
|
|
"d"=>7,
|
|
:e=>Dict(
|
|
"f"=>"hey",
|
|
"g"=>Dict(
|
|
"world"=>[1, "2", 3, Dict(:dd=>4.7)]
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
julia jsonstring = JSON.json(d)
|
|
julia> A1 = JSON.parse(jsonstring) # A1 type is JSON.Object
|
|
julia> A2 = dictify(A1; keytype=String)
|
|
Dict{String,Any} with 3 entries:
|
|
"a" => 4
|
|
"b" => 6
|
|
"c" => Dict("d"=>7, "e"=>Dict("f"=>"hey", "g"=>Dict("world"=>[1, "2", 3, 4.7])))
|
|
|
|
julia> A3 = dictify(A1; keytype=Symbol)
|
|
Dict{Symbol,Any} with 3 entries:
|
|
:a => 4
|
|
:b => 6
|
|
:c => Dict(:d=>7, :e=>Dict("f"=>"hey", "g"=>Dict("world"=>[1, "2", 3, 4.7])))
|
|
|
|
julia> B1 = dictify(d; keytype=String)
|
|
Dict{String, Any} with 3 entries:
|
|
"""
|
|
function dictify(x; keytype::Type=Any)
|
|
# Dict-like objects
|
|
if x isa AbstractDict
|
|
# choose output key type container
|
|
out = Dict{keytype,Any}()
|
|
for (k,v) in x
|
|
if keytype === String
|
|
newk = string(k)
|
|
elseif keytype === Symbol
|
|
newk = Symbol(string(k))
|
|
else
|
|
newk = k
|
|
end
|
|
out[newk] = dictify(v; keytype=keytype)
|
|
end
|
|
return out
|
|
# Arrays / vectors: map elements recursively and return a Vector{Any}
|
|
elseif x isa AbstractArray
|
|
return [dictify(element; keytype=keytype) for element in x]
|
|
# everything else: return as-is (primitives, numbers, strings, etc.)
|
|
else
|
|
return x
|
|
end
|
|
end |