# Json\_dict/2 - Helpful for learning how to use JSON with SWI-Prolog dict

**URL:** <https://swi-prolog.discourse.group/t/json-dict-2-helpful-for-learning-how-to-use-json-with-swi-prolog-dict/4450>\
**Category:** Useful Code\
**Created:** [September 15, 2021, 3:41pm UTC](https://swi-prolog.discourse.group/t/json-dict-2-helpful-for-learning-how-to-use-json-with-swi-prolog-dict/4450 "2021-09-15T15:41:26Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [September 15, 2021, 3:41pm UTC](https://swi-prolog.discourse.group/t/json-dict-2-helpful-for-learning-how-to-use-json-with-swi-prolog-dict/4450/1 "2021-09-15T15:41:26Z")

</div>

The predicate json\_dict/2 was created to understand some of the finer intricacies for consistently converting JSON to an SWI-Prolog dict and/or converting an SWI-Prolog dict to JSON . It is not meant to be used directly in code, it is for learning.

```prolog
json_dict(Json0,Dict1) :-
    % mode(+,-)
    nonvar(Json0),
    var(Dict1), !,
    % is_json_term/1 expects an atom and not a term
    % so convert term to an atom.
    term_to_atom(Json0,Json_atom0),
    is_json_term(Json_atom0),
    % When using atom_json_dict/3 to create a dict, use the option value_string_as(atom) to get a consistent tractable representation.
    atom_json_dict(Json_atom0,Dict0,[value_string_as(atom)]),
    atom_json_dict(Json_atom1,Dict0,[]),
    % When using atom_json_dict/3 to create a dict, use the option value_string_as(atom) to get a consistent tractable representation.
    atom_json_dict(Json_atom1,Dict1,[value_string_as(atom)]),
    is_dict(Dict1),
    % Since atoms and strings can be used interchangeably for most SWI-Prolog built-in predicate arguments
    % one can think of term_string/2 as term_atom/2.
    % This can be used as the reverse of term_to_atom/2, (think atom_to_term/2)
    term_string(Json1,Json_atom1),
    % =@= used to allow for difference in system generated tags, e.g. _65108{} and _36929{} are the same.
    assertion( Dict0 =@= Dict1 ),
    assertion( Json0 == Json1 ).
json_dict(Json1,Dict0) :-
    % mode(-,+)
    var(Json1),
    nonvar(Dict0), !,
    % atom_json_dict/3 will accept some values that are not valid dicts, e.g. {}
    % Since the goal is to consistently convert the values, only valid dicts are allowed.
    is_dict(Dict0),
    atom_json_dict(Json_atom0,Dict0,[]),
    % When using atom_json_dict/3 to create a dict, use the option value_string_as(atom) to get a consistent tractable representation.
    atom_json_dict(Json_atom0,Dict1,[value_string_as(atom)]),
    atom_json_dict(Json_atom1,Dict1,[]),
    is_json_term(Json_atom1),
    % Since atoms and strings can be used interchangeably for most SWI-Prolog built-in predicate arguments
    % one can think of term_string/2 as term_atom/2.
    % This can be used as the reverse of term_to_atom/2, (think atom_to_term/2)
    term_string(Json0,Json_atom0),
    term_string(Json1,Json_atom1),
    % =@= used to allow for difference in system generated tags, e.g. _65108{} and _36929{} are the same.
    assertion( Dict0 =@= Dict1 ),
    assertion( Json0 == Json1 ).
json_dict(Json0,Dict0) :-
    % mode(+,+)
    nonvar(Json0),
    nonvar(Dict0), !,
    % check mode(+,-)
    json_dict(Json0,Dict1),
    % check mode(-,+)
    json_dict(Json1,Dict0),
    assertion( Dict0 =@= Dict1 ),
    assertion( Json0 == Json1 ).
json_dict(Json,Dict) :-
    format('Invalid input:\n Json: ~w\n Dict: ~w~n',[Json,Dict]).

```

* * *

> **Notes (Click triangle to exapand)**
>
> SWI-Prolog dicts are for holding key-value pairs so an SWI-Prolog dict can only represent JSON starting as an object, an SWI-Prolog dict can not represent some stand alone JSON values like `[]`.
> 
> * * *
> 
> atom\_json\_dict/3 will accept `'[]'` as the first argument and correctly convert it to a term but the term is not a valid SWI-Prolog dict.  
> e.g.
> 
> ```prolog
> ?- json:atom_json_dict('[]',Dict,[]).
> Dict = [].
> ?- json:atom_json_dict('[]',Dict,[]),is_dict(Dict).
> false.
> 
> ```
> 
> * * *
> 
> `{}` is not a SW-Prolog dict however atom\_json\_dict/2 will correctly convert it to an SWI-Prolog dict.  
> `_{}` is a dict.  
> e.g.
> 
> ```prolog
> ?- Json = '{}',json:atom_json_dict(Json,Dict,[]),is_dict(Dict).
> Json = {},
> Dict = _19260{}.
> 
> ```
> 
> * * *
> 
> When reading a JSON file using json\_read\_dict/3 one may find that converting the internal representation into atoms using option `value_string_as(atom)` works more intuitively with the built-in SWI-Prolog predicates.
> 
> * * *
> 
> SWI-Prolog dicts allow for numbers as keys but JSON only allows for strings as keys.  
> If an SWI-Prolog dict uses a number for a key then json\_write\_dict/3 will throw an error.  
> e.g.
> 
> ```prolog
> ?- Dict = _{ 1:"a" },json:json_write_dict(current_output,Dict).
> {
> ERROR: Type error: `text' expected, found `1' (an integer)
> 
> ```
> 
> * * *
> 
> is\_json\_term/1 will correctly process the JSON `{"key":value}` as an atom and not as a term.  
> e.g.
> 
> ```prolog
> ?- json:is_json_term({"key":value}).
> false.
> ?- json:is_json_term('{"key":value}').
> true.
> 
> ```
> 
> * * *
> 
> [Parsing JSON is a Minefield](http://seriot.ch/projects/parsing_json.html#41)  
> [Why JSON isn’t a good configuration language](https://www.lucidchart.com/techblog/2018/07/16/why-json-isnt-a-good-configuration-language/)
> 
> * * *
> 
> I wanted to save this somewhere related to SWI-Prolog and JSON this looked like an easy to find location.
> 
> [Tips on Adding JSON Output to Your CLI App](https://blog.kellybrazil.com/2021/12/03/tips-on-adding-json-output-to-your-cli-app/)
