1/* Part of SWI-Prolog 2 3 Author: Jan Wielemaker 4 E-mail: J.Wielemaker@vu.nl 5 WWW: http://www.swi-prolog.org 6 Copyright (c) 2007-2023, University of Amsterdam 7 VU University Amsterdam 8 CWI, Amsterdam 9 SWI-Prolog Solutions b.v. 10 All rights reserved. 11 12 Redistribution and use in source and binary forms, with or without 13 modification, are permitted provided that the following conditions 14 are met: 15 16 1. Redistributions of source code must retain the above copyright 17 notice, this list of conditions and the following disclaimer. 18 19 2. Redistributions in binary form must reproduce the above copyright 20 notice, this list of conditions and the following disclaimer in 21 the documentation and/or other materials provided with the 22 distribution. 23 24 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 27 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 28 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 29 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 30 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 34 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 POSSIBILITY OF SUCH DAMAGE. 36*/ 37 38:- module(json, 39 [ json_read/2, % +Stream, -JSONTerm 40 json_read/3, % +Stream, -JSONTerm, +Options 41 atom_json_term/3, % ?Atom, ?JSONTerm, +Options 42 json_write/2, % +Stream, +Term 43 json_write/3, % +Stream, +Term, +Options 44 is_json_term/1, % @Term 45 is_json_term/2, % @Term, +Options 46 % Version 7 dict support 47 json_read_dict/2, % +Stream, -Dict 48 json_read_dict/3, % +Stream, -Dict, +Options 49 json_write_dict/2, % +Stream, +Dict 50 json_write_dict/3, % +Stream, +Dict, +Options 51 atom_json_dict/3 % ?Atom, ?JSONDict, +Options 52 ]). 53:- use_module(library(record)). 54:- use_module(library(error)). 55:- use_module(library(option)). 56:- use_module(library(lists)). 57 58:- use_foreign_library(foreign(json)). 59 60:- multifile 61 json_write_hook/4, % +Term, +Stream, +State, +Options 62 json_dict_pairs/2. % +Dict, -Pairs 63 64:- predicate_options(json_read/3, 3, 65 [ null(ground), 66 true(ground), 67 false(ground), 68 value_string_as(oneof([atom,string])) 69 ]). 70:- predicate_options(json_write/3, 3, 71 [ indent(nonneg), 72 step(positive_integer), 73 tab(positive_integer), 74 width(nonneg), 75 null(ground), 76 true(ground), 77 false(ground), 78 serialize_unknown(boolean) 79 ]). 80:- predicate_options(json_read_dict/3, 3, 81 [ tag(atom), 82 default_tag(atom), 83 pass_to(json_read/3, 3) 84 ]). 85:- predicate_options(json_write_dict/3, 3, 86 [ tag(atom), 87 pass_to(json_write/3, 3) 88 ]). 89:- predicate_options(is_json_term/2, 2, 90 [ null(ground), 91 true(ground), 92 false(ground) 93 ]). 94:- predicate_options(atom_json_term/3, 3, 95 [ as(oneof([atom,string,codes])), 96 pass_to(json_read/3, 3), 97 pass_to(json_write/3, 3) 98 ]).
122:- record json_options( 123 null:ground = @(null), 124 true:ground = @(true), 125 false:ground = @(false), 126 end_of_file:ground = error, 127 value_string_as:oneof([atom,string]) = atom, 128 tag:atom = '', 129 default_tag:atom). 130 131default_json_dict_options( 132 json_options(null, true, false, error, string, '', _)). 133 134 135 /******************************* 136 * MAP TO/FROM TEXT * 137 *******************************/
atom
(default),
string
, codes
or chars
.148atom_json_term(Atom, Term, Options) :- 149 ground(Atom), 150 !, 151 setup_call_cleanup( 152 open_string(Atom, In), 153 json_read(In, Term, Options), 154 close(In)). 155atom_json_term(Result, Term, Options) :- 156 select_option(as(Type), Options, Options1, atom), 157 ( type_term(Type, Result, Out) 158 -> true 159 ; must_be(oneof([atom,string,codes,chars]), Type) 160 ), 161 with_output_to(Out, 162 json_write(current_output, Term, Options1)). 163 164type_term(atom, Result, atom(Result)). 165type_term(string, Result, string(Result)). 166type_term(codes, Result, codes(Result)). 167type_term(chars, Result, chars(Result)). 168 169 170 /******************************* 171 * READING * 172 *******************************/
json(NameValueList)
, where
NameValueList is a list of Name=Value. Name is an atom
created from the JSON string.true
and false
are mapped -like JPL-
to @(true) and @(false).null
is mapped to the Prolog term
@(null)Here is a complete example in JSON and its corresponding Prolog term.
{ "name":"Demo term", "created": { "day":null, "month":"December", "year":2007 }, "confirmed":true, "members":[1,2,3] }
json([ name='Demo term', created=json([day= @null, month='December', year=2007]), confirmed= @true, members=[1, 2, 3] ])
The following options are processed:
null
. Default @(null)true
. Default @(true)false
. Default @(false)error
):
error
, throw an unexpected
end of file syntax error
Returning an status term is required to process
Concatenated
JSON.
Suggested values are @(eof)
or end_of_file
.
atom
.
The alternative is string
, producing a packed string object.
Please note that codes
or chars
would produce ambiguous
output and are therefore not supported.247json_read(Stream, Term) :- 248 default_json_options(Options), 249 ( json_value_top(Stream, Term, Options) 250 -> true 251 ; syntax_error(illegal_json, Stream) 252 ). 253json_read(Stream, Term, Options) :- 254 make_json_options(Options, OptionTerm, _RestOptions), 255 ( json_value_top(Stream, Term, OptionTerm) 256 -> true 257 ; syntax_error(illegal_json, Stream) 258 ). 259 260json_value_top(Stream, Term, Options) :- 261 stream_property(Stream, type(binary)), 262 !, 263 setup_call_cleanup( 264 set_stream(Stream, encoding(utf8)), 265 json_value_top_(Stream, Term, Options), 266 set_stream(Stream, type(binary))). 267json_value_top(Stream, Term, Options) :- 268 json_value_top_(Stream, Term, Options). 269 270json_value_top_(Stream, Term, Options) :- 271 get_code(Stream, C0), 272 ws(C0, Stream, C1), 273 ( C1 == -1 274 -> json_options_end_of_file(Options, Action), 275 ( Action == error 276 -> syntax_error(unexpected_end_of_file, Stream) 277 ; Term = Action 278 ) 279 ; json_term_top(C1, Stream, Term, Options) 280 ). 281 282json_value(Stream, Term, Next, Options) :- 283 get_code(Stream, C0), 284 ws(C0, Stream, C1), 285 ( C1 == -1 286 -> syntax_error(unexpected_end_of_file, Stream) 287 ; json_term(C1, Stream, Term, Next, Options) 288 ). 289 290json_term(C0, Stream, JSON, Next, Options) :- 291 json_term_top(C0, Stream, JSON, Options), 292 get_code(Stream, Next). 293 294json_term_top(0'{, Stream, json(Pairs), Options) :- 295 !, 296 ws(Stream, C), 297 json_pairs(C, Stream, Pairs, Options). 298json_term_top(0'[, Stream, Array, Options) :- 299 !, 300 ws(Stream, C), 301 json_array(C, Stream, Array, Options). 302json_term_top(0'", Stream, String, Options) :- 303 !, 304 get_code(Stream, C1), 305 json_string_codes(C1, Stream, Codes), 306 json_options_value_string_as(Options, Type), 307 codes_to_type(Type, Codes, String). 308json_term_top(0'-, Stream, Number, _Options) :- 309 !, 310 json_read_number(Stream, 0'-, Number). 311json_term_top(D, Stream, Number, _Options) :- 312 between(0'0, 0'9, D), 313 !, 314 json_read_number(Stream, D, Number). 315json_term_top(C, Stream, Constant, Options) :- 316 json_read_constant(C, Stream, ID), 317 json_constant(ID, Constant, Options). 318 319json_pairs(0'}, _, [], _) :- !. 320json_pairs(C0, Stream, [Pair|Tail], Options) :- 321 json_pair(C0, Stream, Pair, C, Options), 322 ws(C, Stream, Next), 323 ( Next == 0', 324 -> ws(Stream, C2), 325 json_pairs(C2, Stream, Tail, Options) 326 ; Next == 0'} 327 -> Tail = [] 328 ; syntax_error(illegal_object, Stream) 329 ). 330 331json_pair(C0, Stream, Name=Value, Next, Options) :- 332 json_string_as_atom(C0, Stream, Name), 333 ws(Stream, C), 334 C == 0':, 335 json_value(Stream, Value, Next, Options). 336 337 338json_array(0'], _, [], _) :- !. 339json_array(C0, Stream, [Value|Tail], Options) :- 340 json_term(C0, Stream, Value, C, Options), 341 ws(C, Stream, Next), 342 ( Next == 0', 343 -> ws(Stream, C1), 344 json_array(C1, Stream, Tail, Options) 345 ; Next == 0'] 346 -> Tail = [] 347 ; syntax_error(illegal_array, Stream) 348 ). 349 350codes_to_type(atom, Codes, Atom) :- 351 atom_codes(Atom, Codes). 352codes_to_type(string, Codes, Atom) :- 353 string_codes(Atom, Codes). 354codes_to_type(codes, Codes, Codes). 355 356json_string_as_atom(0'", Stream, Atom) :- 357 get_code(Stream, C1), 358 json_string_codes(C1, Stream, Codes), 359 atom_codes(Atom, Codes). 360 361json_string_codes(0'", _, []) :- !. 362json_string_codes(0'\\, Stream, [H|T]) :- 363 !, 364 get_code(Stream, C0), 365 ( escape(C0, Stream, H) 366 -> true 367 ; syntax_error(illegal_string_escape, Stream) 368 ), 369 get_code(Stream, C1), 370 json_string_codes(C1, Stream, T). 371json_string_codes(-1, Stream, _) :- 372 !, 373 syntax_error(eof_in_string, Stream). 374json_string_codes(C, Stream, [C|T]) :- 375 get_code(Stream, C1), 376 json_string_codes(C1, Stream, T). 377 378escape(0'", _, 0'") :- !. 379escape(0'\\, _, 0'\\) :- !. 380escape(0'/, _, 0'/) :- !. 381escape(0'b, _, 0'\b) :- !. 382escape(0'f, _, 0'\f) :- !. 383escape(0'n, _, 0'\n) :- !. 384escape(0'r, _, 0'\r) :- !. 385escape(0't, _, 0'\t) :- !. 386escape(0'u, Stream, C) :- 387 get_XXXX(Stream, H), 388 ( hi_surrogate(H) 389 -> get_surrogate_tail(Stream, H, C) 390 ; C = H 391 ). 392 393get_XXXX(Stream, C) :- 394 get_xdigit(Stream, D1), 395 get_xdigit(Stream, D2), 396 get_xdigit(Stream, D3), 397 get_xdigit(Stream, D4), 398 C is D1<<12+D2<<8+D3<<4+D4. 399 400get_xdigit(Stream, D) :- 401 get_code(Stream, C), 402 code_type(C, xdigit(D)), 403 !. 404get_xdigit(Stream, _) :- 405 syntax_error(hexdigit_expected, Stream). 406 407get_surrogate_tail(Stream, Hi, Codepoint) :- 408 ( get_code(Stream, 0'\\), 409 get_code(Stream, 0'u), 410 get_XXXX(Stream, Lo), 411 surrogate([Hi, Lo], Codepoint) 412 -> true 413 ; syntax_error(illegal_surrogate_pair, Stream) 414 ). 415 416 417hi_surrogate(C) :- 418 C >= 0xD800, C < 0xDC00. 419 420lo_surrogate(C) :- 421 C >= 0xDC00, C < 0xE000. 422 423surrogate([Hi, Lo], Codepoint) :- 424 hi_surrogate(Hi), 425 lo_surrogate(Lo), 426 Codepoint is (Hi - 0xD800) * 0x400 + (Lo - 0xDC00) + 0x10000. 427 428json_read_constant(0't, Stream, true) :- 429 !, 430 must_see(`rue`, Stream, true). 431json_read_constant(0'f, Stream, false) :- 432 !, 433 must_see(`alse`, Stream, false). 434json_read_constant(0'n, Stream, null) :- 435 !, 436 must_see(`ull`, Stream, null). 437 438must_see([], _Stream, _). 439must_see([H|T], Stream, Name) :- 440 get_code(Stream, C), 441 ( C == H 442 -> true 443 ; syntax_error(json_expected(Name), Stream) 444 ), 445 must_see(T, Stream, Name). 446 447json_constant(true, Constant, Options) :- 448 !, 449 json_options_true(Options, Constant). 450json_constant(false, Constant, Options) :- 451 !, 452 json_options_false(Options, Constant). 453json_constant(null, Constant, Options) :- 454 !, 455 json_options_null(Options, Constant).
//
... comments.463ws(Stream, Next) :- 464 get_code(Stream, C0), 465 json_skip_ws(Stream, C0, Next). 466 467ws(C0, Stream, Next) :- 468 json_skip_ws(Stream, C0, Next). 469 470syntax_error(Message, Stream) :- 471 stream_error_context(Stream, Context), 472 throw(error(syntax_error(json(Message)), Context)). 473 474stream_error_context(Stream, stream(Stream, Line, LinePos, CharNo)) :- 475 stream_pair(Stream, Read, _), 476 character_count(Read, CharNo), 477 line_position(Read, LinePos), 478 line_count(Read, Line). 479 480 481 /******************************* 482 * JSON OUTPUT * 483 *******************************/
490% foreign json_write_string/2.
line_position(Stream, Pos)
is not 0. Then it writes Indent //
TabDistance tab characters and Indent mode TabDistance spaces.
498% foreign json_write_indent/3.
Values can be of the form #(Term), which causes Term to be stringified if it is not an atom or string. Stringification is based on term_string/2.
Rational numbers are emitted as floating point numbers. The hook json_write_hook/4 can be used to realize domain specific alternatives.
The version 7 dict type is supported as well. Optionally, if the
dict has a tag, a property "type":"tag" can be added to the
object. This behaviour can be controlled using the tag
option (see
below). For example:
?- json_write(current_output, point{x:1,y:2}). { "x":1, "y":2 }
?- json_write(current_output, point{x:1,y:2}, [tag(type)]). { "type":"point", "x":1, "y":2 }
In addition to the options recognised by json_read/3, we process the following options are recognised:
true
(default false
), serialize unknown terms and
print them as a JSON string. The default raises a type
error. Note that this option only makes sense if you can
guarantee that the passed value is not an otherwise valid
Prolog reporesentation of a Prolog term.
If a string is emitted, the sequence </
is emitted as
<\/
. This is valid JSON syntax which ensures that JSON
objects can be safely embedded into an HTML <script>
element.
Note that this hook is shared by all users of this library. It is generally adviced to map a unique compound term to avoid interference with normal output.
589:- record json_write_state(indent:nonneg = 0, 590 step:positive_integer = 2, 591 tab:positive_integer = 8, 592 width:nonneg = 72, 593 serialize_unknown:boolean = false 594 ). 595 596json_write(Stream, Term) :- 597 json_write(Stream, Term, []). 598json_write(Stream, Term, Options) :- 599 make_json_write_state(Options, State, Options1), 600 make_json_options(Options1, OptionTerm, _RestOptions), 601 json_write_term(Term, Stream, State, OptionTerm). 602 603json_write_term(Var, _, _, _) :- 604 var(Var), 605 !, 606 instantiation_error(Var). 607json_write_term(json(Pairs), Stream, State, Options) :- 608 !, 609 json_write_object(Pairs, Stream, State, Options). 610json_write_term(Dict, Stream, State, Options) :- 611 is_dict(Dict, Tag), 612 !, 613 json_pairs(Dict, Pairs0), 614 ( nonvar(Tag), 615 json_options_tag(Options, Name), 616 Name \== '' 617 -> Pairs = [Name-Tag|Pairs0] 618 ; Pairs = Pairs0 619 ), 620 json_write_object(Pairs, Stream, State, Options). 621json_write_term(List, Stream, State, Options) :- 622 is_list(List), 623 !, 624 space_if_not_at_left_margin(Stream, State), 625 write(Stream, '['), 626 ( json_write_state_width(State, Width), 627 ( Width == 0 628 -> true 629 ; json_write_state_indent(State, Indent), 630 json_print_length(List, Options, Width, Indent, _) 631 ) 632 -> set_width_of_json_write_state(0, State, State2), 633 write_array_hor(List, Stream, State2, Options), 634 write(Stream, ']') 635 ; step_indent(State, State2), 636 write_array_ver(List, Stream, State2, Options), 637 indent(Stream, State), 638 write(Stream, ']') 639 ). 640 641json_write_term(Term, Stream, State, Options) :- 642 json_write_hook(Term, Stream, State, Options), 643 !. 644json_write_term(Number, Stream, _State, _Options) :- 645 number(Number), 646 !, 647 ( float(Number) 648 -> write(Stream, Number) 649 ; integer(Number) 650 -> write(Stream, Number) 651 ; Float is float(Number) % rational number 652 -> write(Stream, Float) 653 ). 654json_write_term(True, Stream, _State, Options) :- 655 json_options_true(Options, True), 656 !, 657 write(Stream, true). 658json_write_term(False, Stream, _State, Options) :- 659 json_options_false(Options, False), 660 !, 661 write(Stream, false). 662json_write_term(Null, Stream, _State, Options) :- 663 json_options_null(Options, Null), 664 !, 665 write(Stream, null). 666json_write_term(#(Text), Stream, _State, _Options) :- 667 !, 668 ( ( atom(Text) 669 ; string(Text) 670 ) 671 -> json_write_string(Stream, Text) 672 ; term_string(Text, String), 673 json_write_string(Stream, String) 674 ). 675json_write_term(String, Stream, _State, _Options) :- 676 atom(String), 677 !, 678 json_write_string(Stream, String). 679json_write_term(String, Stream, _State, _Options) :- 680 string(String), 681 !, 682 json_write_string(Stream, String). 683json_write_term(AnyTerm, Stream, State, _Options) :- 684 ( json_write_state_serialize_unknown(State, true) 685 -> term_string(AnyTerm, String), 686 json_write_string(Stream, String) 687 ; type_error(json_term, AnyTerm) 688 ). 689 690json_pairs(Dict, Pairs) :- 691 json_dict_pairs(Dict, Pairs), 692 !. 693json_pairs(Dict, Pairs) :- 694 dict_pairs(Dict, _, Pairs). 695 696json_write_object(Pairs, Stream, State, Options) :- 697 space_if_not_at_left_margin(Stream, State), 698 write(Stream, '{'), 699 ( json_write_state_width(State, Width), 700 ( Width == 0 701 -> true 702 ; json_write_state_indent(State, Indent), 703 json_print_length(json(Pairs), Options, Width, Indent, _) 704 ) 705 -> set_width_of_json_write_state(0, State, State2), 706 write_pairs_hor(Pairs, Stream, State2, Options), 707 write(Stream, '}') 708 ; step_indent(State, State2), 709 write_pairs_ver(Pairs, Stream, State2, Options), 710 indent(Stream, State), 711 write(Stream, '}') 712 ). 713 714 715write_pairs_hor([], _, _, _). 716write_pairs_hor([H|T], Stream, State, Options) :- 717 json_pair(H, Name, Value), 718 json_write_string(Stream, Name), 719 write(Stream, ':'), 720 json_write_term(Value, Stream, State, Options), 721 ( T == [] 722 -> true 723 ; ( json_write_state_width(State, 0) 724 -> write(Stream, ',') 725 ; write(Stream, ', ') 726 ), 727 write_pairs_hor(T, Stream, State, Options) 728 ). 729 730write_pairs_ver([], _, _, _). 731write_pairs_ver([H|T], Stream, State, Options) :- 732 indent(Stream, State), 733 json_pair(H, Name, Value), 734 json_write_string(Stream, Name), 735 write(Stream, ':'), 736 json_write_term(Value, Stream, State, Options), 737 ( T == [] 738 -> true 739 ; write(Stream, ','), 740 write_pairs_ver(T, Stream, State, Options) 741 ). 742 743 744json_pair(Var, _, _) :- 745 var(Var), 746 !, 747 instantiation_error(Var). 748json_pair(Name=Value, Name, Value) :- !. 749json_pair(Name-Value, Name, Value) :- !. 750json_pair(NameValue, Name, Value) :- 751 compound(NameValue), 752 NameValue =.. [Name, Value], 753 !. 754json_pair(Pair, _, _) :- 755 type_error(json_pair, Pair). 756 757 758write_array_hor([], _, _, _). 759write_array_hor([H|T], Stream, State, Options) :- 760 json_write_term(H, Stream, State, Options), 761 ( T == [] 762 -> write(Stream, ' ') 763 ; write(Stream, ', '), 764 write_array_hor(T, Stream, State, Options) 765 ). 766 767write_array_ver([], _, _, _). 768write_array_ver([H|T], Stream, State, Options) :- 769 indent(Stream, State), 770 json_write_term(H, Stream, State, Options), 771 ( T == [] 772 -> true 773 ; write(Stream, ','), 774 write_array_ver(T, Stream, State, Options) 775 ). 776 777 778indent(Stream, State) :- 779 json_write_state_indent(State, Indent), 780 json_write_state_tab(State, Tab), 781 json_write_indent(Stream, Indent, Tab). 782 783step_indent(State0, State) :- 784 json_write_state_indent(State0, Indent), 785 json_write_state_step(State0, Step), 786 NewIndent is Indent+Step, 787 set_indent_of_json_write_state(NewIndent, State0, State). 788 789space_if_not_at_left_margin(Stream, State) :- 790 stream_pair(Stream, _, Write), 791 line_position(Write, LinePos), 792 ( LinePos == 0 793 ; json_write_state_indent(State, LinePos) 794 ), 795 !. 796space_if_not_at_left_margin(Stream, _) :- 797 put_char(Stream, ' ').
807json_print_length(Var, _, _, _, _) :- 808 var(Var), 809 !, 810 instantiation_error(Var). 811json_print_length(json(Pairs), Options, Max, Len0, Len) :- 812 !, 813 Len1 is Len0 + 2, 814 Len1 =< Max, 815 must_be(list, Pairs), 816 pairs_print_length(Pairs, Options, Max, Len1, Len). 817json_print_length(Dict, Options, Max, Len0, Len) :- 818 is_dict(Dict), 819 !, 820 dict_pairs(Dict, _Tag, Pairs), 821 Len1 is Len0 + 2, 822 Len1 =< Max, 823 pairs_print_length(Pairs, Options, Max, Len1, Len). 824json_print_length(Array, Options, Max, Len0, Len) :- 825 is_list(Array), 826 !, 827 Len1 is Len0 + 2, 828 Len1 =< Max, 829 array_print_length(Array, Options, Max, Len1, Len). 830json_print_length(Null, Options, Max, Len0, Len) :- 831 json_options_null(Options, Null), 832 !, 833 Len is Len0 + 4, 834 Len =< Max. 835json_print_length(False, Options, Max, Len0, Len) :- 836 json_options_false(Options, False), 837 !, 838 Len is Len0 + 5, 839 Len =< Max. 840json_print_length(True, Options, Max, Len0, Len) :- 841 json_options_true(Options, True), 842 !, 843 Len is Len0 + 4, 844 Len =< Max. 845json_print_length(Number, _Options, Max, Len0, Len) :- 846 number(Number), 847 !, 848 write_length(Number, AL, []), 849 Len is Len0 + AL, 850 Len =< Max. 851json_print_length(@(Id), _Options, Max, Len0, Len) :- 852 atom(Id), 853 !, 854 atom_length(Id, IdLen), 855 Len is Len0+IdLen, 856 Len =< Max. 857json_print_length(String, _Options, Max, Len0, Len) :- 858 string_len(String, Len0, Len), 859 !, 860 Len =< Max. 861json_print_length(AnyTerm, _Options, Max, Len0, Len) :- 862 write_length(AnyTerm, AL, []), % will be serialized 863 Len is Len0 + AL+2, 864 Len =< Max. 865 866pairs_print_length([], _, _, Len, Len). 867pairs_print_length([H|T], Options, Max, Len0, Len) :- 868 pair_len(H, Options, Max, Len0, Len1), 869 ( T == [] 870 -> Len = Len1 871 ; Len2 is Len1 + 2, 872 Len2 =< Max, 873 pairs_print_length(T, Options, Max, Len2, Len) 874 ). 875 876pair_len(Pair, Options, Max, Len0, Len) :- 877 compound(Pair), 878 pair_nv(Pair, Name, Value), 879 !, 880 string_len(Name, Len0, Len1), 881 Len2 is Len1+2, 882 Len2 =< Max, 883 json_print_length(Value, Options, Max, Len2, Len). 884pair_len(Pair, _Options, _Max, _Len0, _Len) :- 885 type_error(pair, Pair). 886 887pair_nv(Name=Value, Name, Value) :- !. 888pair_nv(Name-Value, Name, Value) :- !. 889pair_nv(Term, Name, Value) :- 890 compound_name_arguments(Term, Name, [Value]). 891 892array_print_length([], _, _, Len, Len). 893array_print_length([H|T], Options, Max, Len0, Len) :- 894 json_print_length(H, Options, Max, Len0, Len1), 895 ( T == [] 896 -> Len = Len1 897 ; Len2 is Len1+2, 898 Len2 =< Max, 899 array_print_length(T, Options, Max, Len2, Len) 900 ). 901 902string_len(String, Len0, Len) :- 903 atom(String), 904 !, 905 atom_length(String, AL), 906 Len is Len0 + AL + 2. 907string_len(String, Len0, Len) :- 908 string(String), 909 !, 910 string_length(String, AL), 911 Len is Len0 + AL + 2. 912 913 914 /******************************* 915 * TEST * 916 *******************************/
true
, false
and null
constants.925is_json_term(Term) :- 926 default_json_options(Options), 927 is_json_term2(Options, Term). 928 929is_json_term(Term, Options) :- 930 make_json_options(Options, OptionTerm, _RestOptions), 931 is_json_term2(OptionTerm, Term). 932 933is_json_term2(_, Var) :- 934 var(Var), !, fail. 935is_json_term2(Options, json(Pairs)) :- 936 !, 937 is_list(Pairs), 938 maplist(is_json_pair(Options), Pairs). 939is_json_term2(Options, List) :- 940 is_list(List), 941 !, 942 maplist(is_json_term2(Options), List). 943is_json_term2(_, Primitive) :- 944 atomic(Primitive), 945 !. % atom, string or number 946is_json_term2(Options, True) :- 947 json_options_true(Options, True). 948is_json_term2(Options, False) :- 949 json_options_false(Options, False). 950is_json_term2(Options, Null) :- 951 json_options_null(Options, Null). 952 953is_json_pair(_, Var) :- 954 var(Var), !, fail. 955is_json_pair(Options, Name=Value) :- 956 atom(Name), 957 is_json_term2(Options, Value). 958 959 /******************************* 960 * DICT SUPPORT * 961 *******************************/
true
, false
and null
are represented using these
Prolog atoms.type
field in an object assigns a tag for
the dict.
The predicate json_read_dict/3 processes the same options as
json_read/3, but with different defaults. In addition, it
processes the tag
option. See json_read/3 for details about
the shared options.
tag
option does not
apply.null
.true
.false
string
. The alternative is atom
, producing a
packed string object.1002json_read_dict(Stream, Dict) :- 1003 json_read_dict(Stream, Dict, []). 1004 1005json_read_dict(Stream, Dict, Options) :- 1006 make_json_dict_options(Options, OptionTerm, _RestOptions), 1007 ( json_value_top(Stream, Term, OptionTerm) 1008 -> true 1009 ; syntax_error(illegal_json, Stream) 1010 ), 1011 term_to_dict(Term, Dict, OptionTerm). 1012 1013term_to_dict(json(Pairs), Dict, Options) :- 1014 !, 1015 ( json_options_tag(Options, TagName), 1016 Tag \== '', 1017 select(TagName = Tag0, Pairs, NVPairs), 1018 to_atom(Tag0, Tag) 1019 -> json_dict_pairs(NVPairs, DictPairs, Options) 1020 ; json_options_default_tag(Options, DefTag), 1021 ( var(DefTag) 1022 -> true 1023 ; Tag = DefTag 1024 ), 1025 json_dict_pairs(Pairs, DictPairs, Options) 1026 ), 1027 dict_create(Dict, Tag, DictPairs). 1028term_to_dict(Value0, Value, _Options) :- 1029 atomic(Value0), Value0 \== [], 1030 !, 1031 Value = Value0. 1032term_to_dict(List0, List, Options) :- 1033 is_list(List0), 1034 !, 1035 terms_to_dicts(List0, List, Options). 1036term_to_dict(Special, Special, Options) :- 1037 ( json_options_true(Options, Special) 1038 ; json_options_false(Options, Special) 1039 ; json_options_null(Options, Special) 1040 ; json_options_end_of_file(Options, Special) 1041 ), 1042 !. 1043 1044json_dict_pairs([], [], _). 1045json_dict_pairs([Name=Value0|T0], [Name=Value|T], Options) :- 1046 term_to_dict(Value0, Value, Options), 1047 json_dict_pairs(T0, T, Options). 1048 1049terms_to_dicts([], [], _). 1050terms_to_dicts([Value0|T0], [Value|T], Options) :- 1051 term_to_dict(Value0, Value, Options), 1052 terms_to_dicts(T0, T, Options). 1053 1054to_atom(Tag, Atom) :- 1055 string(Tag), 1056 !, 1057 atom_string(Atom, Tag). 1058to_atom(Atom, Atom) :- 1059 atom(Atom).
1068json_write_dict(Stream, Dict) :- 1069 json_write_dict(Stream, Dict, []). 1070 1071json_write_dict(Stream, Dict, Options) :- 1072 make_json_write_state(Options, State, Options1), 1073 make_json_dict_options(Options1, OptionTerm, _RestOptions), 1074 json_write_term(Dict, Stream, State, OptionTerm). 1075 1076 1077make_json_dict_options(Options, Record, RestOptions) :- 1078 default_json_dict_options(Record0), 1079 set_json_options_fields(Options, Record0, Record, RestOptions).
atom
,
string
or codes
.1092atom_json_dict(Atom, Term, Options) :- 1093 ground(Atom), 1094 !, 1095 setup_call_cleanup( 1096 open_string(Atom, In), 1097 json_read_dict(In, Term, Options), 1098 close(In)). 1099atom_json_dict(Result, Term, Options) :- 1100 select_option(as(Type), Options, Options1, atom), 1101 ( type_term(Type, Result, Out) 1102 -> true 1103 ; must_be(oneof([atom,string,codes]), Type) 1104 ), 1105 with_output_to(Out, 1106 json_write_dict(current_output, Term, Options1)). 1107 1108 1109 /******************************* 1110 * MESSAGES * 1111 *******************************/ 1112 1113:- multifile 1114 prolog:error_message/3. 1115 1116prologerror_message(syntax_error(json(Id))) --> 1117 [ 'JSON syntax error: ' ], 1118 json_syntax_error(Id). 1119 1120json_syntax_error(illegal_comment) --> 1121 [ 'Illegal comment' ]. 1122json_syntax_error(illegal_string_escape) --> 1123 [ 'Illegal escape sequence in string' ]. 1124json_syntax_error(illegal_surrogate_pair) --> 1125 [ 'Illegal escaped surrogate pair in string' ]
Reading and writing JSON serialization
This module supports reading and writing JSON objects. This library supports two Prolog representations (the new representation is only supported in SWI-Prolog version 7 and later):
json(NameValueList)
, a JSON string as an atom and the JSON constantsnull
,true
andfalse
as @(null), @(true) and @false.null
,true
andfalse
.http_json.pl
links JSON to the HTTP client and server modules.json_convert.pl
converts JSON Prolog terms to more comfortable terms. */