Using JSON with SWI-Prolog

This is a topic that was split off from How to avoid escaping characters in Prolog strings


The need is to create JSON for use with Cytoscape.js graphs which uses JSON to define the nodes and edges of the graph. (ref) As was done with creating nodes and edges for use with GraphViz using DCGs, the plan is to create Cytoscape.js graphs with DCGs. (ref).


Personal Notes

Supporting JSON
library(http/json): Reading and writing JSON serialization
library(http/json_convert): Convert between JSON terms and Prolog application terms
library(http/http_json): HTTP JSON Plugin module - If you are not using an HTTP server then instead look at library(http/json)

library(http/js_write): Utilities for including JavaScript

Anne’s site (JSON)

JSONLint - The JSON Validator

library(quasi_quotations): Define Quasi Quotation syntax
Why It’s Nice to be Quoted: Quasiquoting for Haskell (pdf)
Why It’s Nice to be Quoted: Quasiquoting for Prolog (pdf)
Implementing GraphQL as a Query Language for Deductive Databases in SWI–Prolog Using DCGs, Quasi Quotations, and Dicts (pdf)

Quasi-quotation (Wikipedia)
String interpolation (Wikipedia)

Expansion of the string usually occurs at run time.

Template processor (Wikipedia)

A template engine is ordinarily included as a part of a web template system or application framework, and may be used also as a preprocessor or filter.

Code examples using Quasi Quotations
https://github.com/xpxaxsxi/qqospath/blob/branch1/qqospath.pl
https://github.com/mndrix/uri_qq/blob/master/prolog/uri_qq.pl
http://www.pathwayslms.com/swipltuts/html/index.html#_inclusion
https://github.com/NaohiroTamura/graphql/blob/622ddbb111a7583a0d9edfb5b33a06e68baacdfd/prolog/graphql.pl
https://github.com/TeamSPoon/logicmoo_nlu/blob/a9924b3d14fd97bcd900e4a8cb4ceefd2d51f93e/prolog/marty_white/adv_quasiquote.pl
https://github.com/NaohiroTamura/openwhisk-runtime-prolog/blob/dc35da81020e722081c100ac14d4dcc924f8b340/samples/actions/graphql.pl
https://github.com/Hookscript/lang-prolog-swi/blob/390fa1b9e345f0e7112733953205fcf58e920769/packs/uri_qq/prolog/uri_qq.pl
https://github.com/JanWielemaker/rserve_client/blob/f5df41128164258a03158928d41eb81eeed0f24b/prolog/r/r_call.pl
https://github.com/samer--/prolog/blob/574caf40a99afcd0e6fe2b5aeda2c725cd2fcd3b/pldb/prolog/pldb_core.pl

Why not create the equivalent SWI-Prolog dict objects and leave the transformation to JSON to json_write_dict/2? In the HTTP server context the skeleton is typically

handler(Request) :-
    <get parameters>.
    <compute reply as a dict>,
    reply_json(Dict).
1 Like

Yes that is one option I plan to explore but find that doing some of the parts manually at first makes it easier to understand what is happening when the need to fix problems later happens.

I am more in the experimental stage than anything right now and have never really used JSON, SWI-Prolog dicts or Cytoscape.js to a level that I feel comfortable so this is like doing lots of homework problems to learn.

I didn’t even know json_write_dict/2 existed until just yesterday when trying to answer this other question.

There is also the code by CapelliC (GitHub - CapelliC/swish_cytoscape_js: SWISH graph rendering by means of cytoscape_js) which I want to better understand.

This subject is very important at the moment I handle json with prolog locally and I also use json_object to create my json a and prolog_to_json objects as well as reply_json with my local server it works but with aws I have to parse by hand json objects really it would be to be able to provide an answer to this problem

1 Like

Can you elaborate?

1 Like

To return the answer under aws with prolog I create the json object by hand with the concatenation using string_concat and that not works in aws

While my use case is not the exact same as yours, we do have touch points on

  1. The format external to Prolog is JSON.
  2. The internal format does not have to be JSON.

SWI-Prolog internal representation

The internal representations that I need is currently facts in the Prolog database, see: Convert facts to GraphViz dot file using DCGs.

The SWI-Prolog library(http/json) does this with the internal representation being a dictionary and this is a reliable conversion. So if you are open to the format used with SWI-Prolog then using a dictionary, these predicates are handy.

AFAIK CapelliC uses Unweighted Graphs, see: library(ugraphs)


Conversion

library(http/json) comes with predicates that convert to and from SWI-Prolog dictionaries.

I am using DCGs.

AFAIK CapelliC uses Quasi Quotation, see library(quasi_quotations)

Using a functional approach with library(yall) is also a possibility but not one I plan to explore.


While I do like the reliability and ease of using library(http/json), for my specific use case that means I have to deal with dictionaries along the way. Since most of what I plan to generate will be boilerplate code the DCG still seems reasonable.

In local that works fine i have the result on aws a have this error

When sending JSON to a Javascript from end using json_write_dict/3, I find these options useful: [width(0),true(#(true)),false(#(false)),null(#(null))].

For reading with json_read_dict/3, I find these options useful:
[value_string_as(atom), end_of_file(@(end)), default_tag(json), true(#(true)),false(#(false)),null(#(null))].

(The default_tag is a small thing, but it gives me more peace of mind when using unification to compare two JSON-created dicts).

2 Likes

In this case I use reply_json to send json response i create the json object with json_object in my computer i don’t have error when test it in aws i have an error.

My goal is create a lambda function in aws with prolog and the response have to respect this format :{ "isBase64Encoded":true|false, "statusCode":httpStatusCode, "headers": { "headerName": "headerValue", ... }, "multiValueHeaders": { "headerName": ["headerValue", "headerValue2", ...], ... }, "body": " " } this the spec of aws in local i have the expected response

Suggest there is a bad call to format/3 in your code somewhere. Often you get more info if you load library(http/http_error) in addition. That should add a backtrace to the output.

For interactive debugging, run the server with access to the toplevel and graphics (depends on platform how) and run

?- tspy(NameOfHandler).

That should open the debugger if you make the HTTP request.

1 Like