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-2021, 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(memfile)). 55:- use_module(library(error)). 56:- use_module(library(option)). 57:- use_module(library(lists)). 58 59:- use_foreign_library(foreign(json)). 60 61:- multifile 62 json_write_hook/4, % +Term, +Stream, +State, +Options 63 json_dict_pairs/2. % +Dict, -Pairs 64 65:- predicate_options(json_read/3, 3, 66 [ null(ground), 67 true(ground), 68 false(ground), 69 value_string_as(oneof([atom,string])) 70 ]). 71:- predicate_options(json_write/3, 3, 72 [ indent(nonneg), 73 step(positive_integer), 74 tab(positive_integer), 75 width(nonneg), 76 null(ground), 77 true(ground), 78 false(ground), 79 serialize_unknown(boolean) 80 ]). 81:- predicate_options(json_read_dict/3, 3, 82 [ tag(atom), 83 default_tag(atom), 84 pass_to(json_read/3, 3) 85 ]). 86:- predicate_options(json_write_dict/3, 3, 87 [ tag(atom), 88 pass_to(json_write/3, 3) 89 ]). 90:- predicate_options(is_json_term/2, 2, 91 [ null(ground), 92 true(ground), 93 false(ground) 94 ]). 95:- predicate_options(atom_json_term/3, 3, 96 [ as(oneof([atom,string,codes])), 97 pass_to(json_read/3, 3), 98 pass_to(json_write/3, 3) 99 ]).
123:- record json_options( 124 null:ground = @(null), 125 true:ground = @(true), 126 false:ground = @(false), 127 end_of_file:ground = error, 128 value_string_as:oneof([atom,string]) = atom, 129 tag:atom = '', 130 default_tag:atom). 131 132default_json_dict_options( 133 json_options(null, true, false, error, string, '', _)). 134 135 136 /******************************* 137 * MAP TO/FROM TEXT * 138 *******************************/
atom
(default),
string
, codes
or chars
.149atom_json_term(Atom, Term, Options) :- 150 ground(Atom), 151 !, 152 setup_call_cleanup( 153 ( atom_to_memory_file(Atom, MF), 154 open_memory_file(MF, read, In, [free_on_close(true)]) 155 ), 156 json_read(In, Term, Options), 157 close(In)). 158atom_json_term(Result, Term, Options) :- 159 select_option(as(Type), Options, Options1, atom), 160 ( type_term(Type, Result, Out) 161 -> true 162 ; must_be(oneof([atom,string,codes,chars]), Type) 163 ), 164 with_output_to(Out, 165 json_write(current_output, Term, Options1)). 166 167type_term(atom, Result, atom(Result)). 168type_term(string, Result, string(Result)). 169type_term(codes, Result, codes(Result)). 170type_term(chars, Result, chars(Result)). 171 172 173 /******************************* 174 * READING * 175 *******************************/
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.250json_read(Stream, Term) :- 251 default_json_options(Options), 252 ( json_value_top(Stream, Term, Options) 253 -> true 254 ; syntax_error(illegal_json, Stream) 255 ). 256json_read(Stream, Term, Options) :- 257 make_json_options(Options, OptionTerm, _RestOptions), 258 ( json_value_top(Stream, Term, OptionTerm) 259 -> true 260 ; syntax_error(illegal_json, Stream) 261 ). 262 263json_value_top(Stream, Term, Options) :- 264 stream_property(Stream, type(binary)), 265 !, 266 setup_call_cleanup( 267 set_stream(Stream, encoding(utf8)), 268 json_value_top_(Stream, Term, Options), 269 set_stream(Stream, type(binary))). 270json_value_top(Stream, Term, Options) :- 271 json_value_top_(Stream, Term, Options). 272 273json_value_top_(Stream, Term, Options) :- 274 get_code(Stream, C0), 275 ws(C0, Stream, C1), 276 ( C1 == -1 277 -> json_options_end_of_file(Options, Action), 278 ( Action == error 279 -> syntax_error(unexpected_end_of_file, Stream) 280 ; Term = Action 281 ) 282 ; json_term_top(C1, Stream, Term, Options) 283 ). 284 285json_value(Stream, Term, Next, Options) :- 286 get_code(Stream, C0), 287 ws(C0, Stream, C1), 288 ( C1 == -1 289 -> syntax_error(unexpected_end_of_file, Stream) 290 ; json_term(C1, Stream, Term, Next, Options) 291 ). 292 293json_term(C0, Stream, JSON, Next, Options) :- 294 json_term_top(C0, Stream, JSON, Options), 295 get_code(Stream, Next). 296 297json_term_top(0'{, Stream, json(Pairs), Options) :- 298 !, 299 ws(Stream, C), 300 json_pairs(C, Stream, Pairs, Options). 301json_term_top(0'[, Stream, Array, Options) :- 302 !, 303 ws(Stream, C), 304 json_array(C, Stream, Array, Options). 305json_term_top(0'", Stream, String, Options) :- 306 !, 307 get_code(Stream, C1), 308 json_string_codes(C1, Stream, Codes), 309 json_options_value_string_as(Options, Type), 310 codes_to_type(Type, Codes, String). 311json_term_top(0'-, Stream, Number, _Options) :- 312 !, 313 json_read_number(Stream, 0'-, Number). 314json_term_top(D, Stream, Number, _Options) :- 315 between(0'0, 0'9, D), 316 !, 317 json_read_number(Stream, D, Number). 318json_term_top(C, Stream, Constant, Options) :- 319 json_read_constant(C, Stream, ID), 320 json_constant(ID, Constant, Options). 321 322json_pairs(0'}, _, [], _) :- !. 323json_pairs(C0, Stream, [Pair|Tail], Options) :- 324 json_pair(C0, Stream, Pair, C, Options), 325 ws(C, Stream, Next), 326 ( Next == 0', 327 -> ws(Stream, C2), 328 json_pairs(C2, Stream, Tail, Options) 329 ; Next == 0'} 330 -> Tail = [] 331 ; syntax_error(illegal_object, Stream) 332 ). 333 334json_pair(C0, Stream, Name=Value, Next, Options) :- 335 json_string_as_atom(C0, Stream, Name), 336 ws(Stream, C), 337 C == 0':, 338 json_value(Stream, Value, Next, Options). 339 340 341json_array(0'], _, [], _) :- !. 342json_array(C0, Stream, [Value|Tail], Options) :- 343 json_term(C0, Stream, Value, C, Options), 344 ws(C, Stream, Next), 345 ( Next == 0', 346 -> ws(Stream, C1), 347 json_array(C1, Stream, Tail, Options) 348 ; Next == 0'] 349 -> Tail = [] 350 ; syntax_error(illegal_array, Stream) 351 ). 352 353codes_to_type(atom, Codes, Atom) :- 354 atom_codes(Atom, Codes). 355codes_to_type(string, Codes, Atom) :- 356 string_codes(Atom, Codes). 357codes_to_type(codes, Codes, Codes). 358 359json_string_as_atom(0'", Stream, Atom) :- 360 get_code(Stream, C1), 361 json_string_codes(C1, Stream, Codes), 362 atom_codes(Atom, Codes). 363 364json_string_codes(0'", _, []) :- !. 365json_string_codes(0'\\, Stream, [H|T]) :- 366 !, 367 get_code(Stream, C0), 368 ( escape(C0, Stream, H) 369 -> true 370 ; syntax_error(illegal_string_escape, Stream) 371 ), 372 get_code(Stream, C1), 373 json_string_codes(C1, Stream, T). 374json_string_codes(-1, Stream, _) :- 375 !, 376 syntax_error(eof_in_string, Stream). 377json_string_codes(C, Stream, [C|T]) :- 378 get_code(Stream, C1), 379 json_string_codes(C1, Stream, T). 380 381escape(0'", _, 0'") :- !. 382escape(0'\\, _, 0'\\) :- !. 383escape(0'/, _, 0'/) :- !. 384escape(0'b, _, 0'\b) :- !. 385escape(0'f, _, 0'\f) :- !. 386escape(0'n, _, 0'\n) :- !. 387escape(0'r, _, 0'\r) :- !. 388escape(0't, _, 0'\t) :- !. 389escape(0'u, Stream, C) :- 390 !, 391 get_code(Stream, C1), 392 get_code(Stream, C2), 393 get_code(Stream, C3), 394 get_code(Stream, C4), 395 code_type(C1, xdigit(D1)), 396 code_type(C2, xdigit(D2)), 397 code_type(C3, xdigit(D3)), 398 code_type(C4, xdigit(D4)), 399 C is D1<<12+D2<<8+D3<<4+D4. 400 401json_read_constant(0't, Stream, true) :- 402 !, 403 must_see(`rue`, Stream, true). 404json_read_constant(0'f, Stream, false) :- 405 !, 406 must_see(`alse`, Stream, false). 407json_read_constant(0'n, Stream, null) :- 408 !, 409 must_see(`ull`, Stream, null). 410 411must_see([], _Stream, _). 412must_see([H|T], Stream, Name) :- 413 get_code(Stream, C), 414 ( C == H 415 -> true 416 ; syntax_error(json_expected(Name), Stream) 417 ), 418 must_see(T, Stream, Name). 419 420json_constant(true, Constant, Options) :- 421 !, 422 json_options_true(Options, Constant). 423json_constant(false, Constant, Options) :- 424 !, 425 json_options_false(Options, Constant). 426json_constant(null, Constant, Options) :- 427 !, 428 json_options_null(Options, Constant).
//
... comments.436ws(Stream, Next) :- 437 get_code(Stream, C0), 438 json_skip_ws(Stream, C0, Next). 439 440ws(C0, Stream, Next) :- 441 json_skip_ws(Stream, C0, Next). 442 443syntax_error(Message, Stream) :- 444 stream_error_context(Stream, Context), 445 throw(error(syntax_error(json(Message)), Context)). 446 447stream_error_context(Stream, stream(Stream, Line, LinePos, CharNo)) :- 448 stream_pair(Stream, Read, _), 449 character_count(Read, CharNo), 450 line_position(Read, LinePos), 451 line_count(Read, Line). 452 453 454 /******************************* 455 * JSON OUTPUT * 456 *******************************/
463% foreign json_write_string/2.
line_position(Stream, Pos)
is not 0. Then it writes Indent //
TabDistance tab characters and Indent mode TabDistance spaces.
471% 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.
562:- record json_write_state(indent:nonneg = 0, 563 step:positive_integer = 2, 564 tab:positive_integer = 8, 565 width:nonneg = 72, 566 serialize_unknown:boolean = false 567 ). 568 569json_write(Stream, Term) :- 570 json_write(Stream, Term, []). 571json_write(Stream, Term, Options) :- 572 make_json_write_state(Options, State, Options1), 573 make_json_options(Options1, OptionTerm, _RestOptions), 574 json_write_term(Term, Stream, State, OptionTerm). 575 576json_write_term(Var, _, _, _) :- 577 var(Var), 578 !, 579 instantiation_error(Var). 580json_write_term(json(Pairs), Stream, State, Options) :- 581 !, 582 json_write_object(Pairs, Stream, State, Options). 583json_write_term(Dict, Stream, State, Options) :- 584 is_dict(Dict, Tag), 585 !, 586 json_pairs(Dict, Pairs0), 587 ( nonvar(Tag), 588 json_options_tag(Options, Name), 589 Name \== '' 590 -> Pairs = [Name-Tag|Pairs0] 591 ; Pairs = Pairs0 592 ), 593 json_write_object(Pairs, Stream, State, Options). 594json_write_term(List, Stream, State, Options) :- 595 is_list(List), 596 !, 597 space_if_not_at_left_margin(Stream, State), 598 write(Stream, '['), 599 ( json_write_state_width(State, Width), 600 ( Width == 0 601 -> true 602 ; json_write_state_indent(State, Indent), 603 json_print_length(List, Options, Width, Indent, _) 604 ) 605 -> set_width_of_json_write_state(0, State, State2), 606 write_array_hor(List, Stream, State2, Options), 607 write(Stream, ']') 608 ; step_indent(State, State2), 609 write_array_ver(List, Stream, State2, Options), 610 indent(Stream, State), 611 write(Stream, ']') 612 ). 613 614json_write_term(Term, Stream, State, Options) :- 615 json_write_hook(Term, Stream, State, Options), 616 !. 617json_write_term(Number, Stream, _State, _Options) :- 618 number(Number), 619 !, 620 ( float(Number) 621 -> write(Stream, Number) 622 ; integer(Number) 623 -> write(Stream, Number) 624 ; Float is float(Number) % rational number 625 -> write(Stream, Float) 626 ). 627json_write_term(True, Stream, _State, Options) :- 628 json_options_true(Options, True), 629 !, 630 write(Stream, true). 631json_write_term(False, Stream, _State, Options) :- 632 json_options_false(Options, False), 633 !, 634 write(Stream, false). 635json_write_term(Null, Stream, _State, Options) :- 636 json_options_null(Options, Null), 637 !, 638 write(Stream, null). 639json_write_term(#(Text), Stream, _State, _Options) :- 640 !, 641 ( ( atom(Text) 642 ; string(Text) 643 ) 644 -> json_write_string(Stream, Text) 645 ; term_string(Text, String), 646 json_write_string(Stream, String) 647 ). 648json_write_term(String, Stream, _State, _Options) :- 649 atom(String), 650 !, 651 json_write_string(Stream, String). 652json_write_term(String, Stream, _State, _Options) :- 653 string(String), 654 !, 655 json_write_string(Stream, String). 656json_write_term(AnyTerm, Stream, State, _Options) :- 657 ( json_write_state_serialize_unknown(State, true) 658 -> term_string(AnyTerm, String), 659 json_write_string(Stream, String) 660 ; type_error(json_term, AnyTerm) 661 ). 662 663json_pairs(Dict, Pairs) :- 664 json_dict_pairs(Dict, Pairs), 665 !. 666json_pairs(Dict, Pairs) :- 667 dict_pairs(Dict, _, Pairs). 668 669json_write_object(Pairs, Stream, State, Options) :- 670 space_if_not_at_left_margin(Stream, State), 671 write(Stream, '{'), 672 ( json_write_state_width(State, Width), 673 ( Width == 0 674 -> true 675 ; json_write_state_indent(State, Indent), 676 json_print_length(json(Pairs), Options, Width, Indent, _) 677 ) 678 -> set_width_of_json_write_state(0, State, State2), 679 write_pairs_hor(Pairs, Stream, State2, Options), 680 write(Stream, '}') 681 ; step_indent(State, State2), 682 write_pairs_ver(Pairs, Stream, State2, Options), 683 indent(Stream, State), 684 write(Stream, '}') 685 ). 686 687 688write_pairs_hor([], _, _, _). 689write_pairs_hor([H|T], Stream, State, Options) :- 690 json_pair(H, Name, Value), 691 json_write_string(Stream, Name), 692 write(Stream, ':'), 693 json_write_term(Value, Stream, State, Options), 694 ( T == [] 695 -> true 696 ; write(Stream, ', '), 697 write_pairs_hor(T, Stream, State, Options) 698 ). 699 700write_pairs_ver([], _, _, _). 701write_pairs_ver([H|T], Stream, State, Options) :- 702 indent(Stream, State), 703 json_pair(H, Name, Value), 704 json_write_string(Stream, Name), 705 write(Stream, ':'), 706 json_write_term(Value, Stream, State, Options), 707 ( T == [] 708 -> true 709 ; write(Stream, ','), 710 write_pairs_ver(T, Stream, State, Options) 711 ). 712 713 714json_pair(Var, _, _) :- 715 var(Var), 716 !, 717 instantiation_error(Var). 718json_pair(Name=Value, Name, Value) :- !. 719json_pair(Name-Value, Name, Value) :- !. 720json_pair(NameValue, Name, Value) :- 721 compound(NameValue), 722 NameValue =.. [Name, Value], 723 !. 724json_pair(Pair, _, _) :- 725 type_error(json_pair, Pair). 726 727 728write_array_hor([], _, _, _). 729write_array_hor([H|T], Stream, State, Options) :- 730 json_write_term(H, Stream, State, Options), 731 ( T == [] 732 -> write(Stream, ' ') 733 ; write(Stream, ', '), 734 write_array_hor(T, Stream, State, Options) 735 ). 736 737write_array_ver([], _, _, _). 738write_array_ver([H|T], Stream, State, Options) :- 739 indent(Stream, State), 740 json_write_term(H, Stream, State, Options), 741 ( T == [] 742 -> true 743 ; write(Stream, ','), 744 write_array_ver(T, Stream, State, Options) 745 ). 746 747 748indent(Stream, State) :- 749 json_write_state_indent(State, Indent), 750 json_write_state_tab(State, Tab), 751 json_write_indent(Stream, Indent, Tab). 752 753step_indent(State0, State) :- 754 json_write_state_indent(State0, Indent), 755 json_write_state_step(State0, Step), 756 NewIndent is Indent+Step, 757 set_indent_of_json_write_state(NewIndent, State0, State). 758 759space_if_not_at_left_margin(Stream, State) :- 760 stream_pair(Stream, _, Write), 761 line_position(Write, LinePos), 762 ( LinePos == 0 763 ; json_write_state_indent(State, LinePos) 764 ), 765 !. 766space_if_not_at_left_margin(Stream, _) :- 767 put_char(Stream, ' ').
777json_print_length(Var, _, _, _, _) :- 778 var(Var), 779 !, 780 instantiation_error(Var). 781json_print_length(json(Pairs), Options, Max, Len0, Len) :- 782 !, 783 Len1 is Len0 + 2, 784 Len1 =< Max, 785 must_be(list, Pairs), 786 pairs_print_length(Pairs, Options, Max, Len1, Len). 787json_print_length(Dict, Options, Max, Len0, Len) :- 788 is_dict(Dict), 789 !, 790 dict_pairs(Dict, _Tag, Pairs), 791 Len1 is Len0 + 2, 792 Len1 =< Max, 793 pairs_print_length(Pairs, Options, Max, Len1, Len). 794json_print_length(Array, Options, Max, Len0, Len) :- 795 is_list(Array), 796 !, 797 Len1 is Len0 + 2, 798 Len1 =< Max, 799 array_print_length(Array, Options, Max, Len1, Len). 800json_print_length(Null, Options, Max, Len0, Len) :- 801 json_options_null(Options, Null), 802 !, 803 Len is Len0 + 4, 804 Len =< Max. 805json_print_length(False, Options, Max, Len0, Len) :- 806 json_options_false(Options, False), 807 !, 808 Len is Len0 + 5, 809 Len =< Max. 810json_print_length(True, Options, Max, Len0, Len) :- 811 json_options_true(Options, True), 812 !, 813 Len is Len0 + 4, 814 Len =< Max. 815json_print_length(Number, _Options, Max, Len0, Len) :- 816 number(Number), 817 !, 818 write_length(Number, AL, []), 819 Len is Len0 + AL, 820 Len =< Max. 821json_print_length(@(Id), _Options, Max, Len0, Len) :- 822 atom(Id), 823 !, 824 atom_length(Id, IdLen), 825 Len is Len0+IdLen, 826 Len =< Max. 827json_print_length(String, _Options, Max, Len0, Len) :- 828 string_len(String, Len0, Len), 829 !, 830 Len =< Max. 831json_print_length(AnyTerm, _Options, Max, Len0, Len) :- 832 write_length(AnyTerm, AL, []), % will be serialized 833 Len is Len0 + AL+2, 834 Len =< Max. 835 836pairs_print_length([], _, _, Len, Len). 837pairs_print_length([H|T], Options, Max, Len0, Len) :- 838 pair_len(H, Options, Max, Len0, Len1), 839 ( T == [] 840 -> Len = Len1 841 ; Len2 is Len1 + 2, 842 Len2 =< Max, 843 pairs_print_length(T, Options, Max, Len2, Len) 844 ). 845 846pair_len(Pair, Options, Max, Len0, Len) :- 847 compound(Pair), 848 pair_nv(Pair, Name, Value), 849 !, 850 string_len(Name, Len0, Len1), 851 Len2 is Len1+2, 852 Len2 =< Max, 853 json_print_length(Value, Options, Max, Len2, Len). 854pair_len(Pair, _Options, _Max, _Len0, _Len) :- 855 type_error(pair, Pair). 856 857pair_nv(Name=Value, Name, Value) :- !. 858pair_nv(Name-Value, Name, Value) :- !. 859pair_nv(Term, Name, Value) :- 860 compound_name_arguments(Term, Name, [Value]). 861 862array_print_length([], _, _, Len, Len). 863array_print_length([H|T], Options, Max, Len0, Len) :- 864 json_print_length(H, Options, Max, Len0, Len1), 865 ( T == [] 866 -> Len = Len1 867 ; Len2 is Len1+2, 868 Len2 =< Max, 869 array_print_length(T, Options, Max, Len2, Len) 870 ). 871 872string_len(String, Len0, Len) :- 873 atom(String), 874 !, 875 atom_length(String, AL), 876 Len is Len0 + AL + 2. 877string_len(String, Len0, Len) :- 878 string(String), 879 !, 880 string_length(String, AL), 881 Len is Len0 + AL + 2. 882 883 884 /******************************* 885 * TEST * 886 *******************************/
true
, false
and null
constants.895is_json_term(Term) :- 896 default_json_options(Options), 897 is_json_term2(Options, Term). 898 899is_json_term(Term, Options) :- 900 make_json_options(Options, OptionTerm, _RestOptions), 901 is_json_term2(OptionTerm, Term). 902 903is_json_term2(_, Var) :- 904 var(Var), !, fail. 905is_json_term2(Options, json(Pairs)) :- 906 !, 907 is_list(Pairs), 908 maplist(is_json_pair(Options), Pairs). 909is_json_term2(Options, List) :- 910 is_list(List), 911 !, 912 maplist(is_json_term2(Options), List). 913is_json_term2(_, Primitive) :- 914 atomic(Primitive), 915 !. % atom, string or number 916is_json_term2(Options, True) :- 917 json_options_true(Options, True). 918is_json_term2(Options, False) :- 919 json_options_false(Options, False). 920is_json_term2(Options, Null) :- 921 json_options_null(Options, Null). 922 923is_json_pair(_, Var) :- 924 var(Var), !, fail. 925is_json_pair(Options, Name=Value) :- 926 atom(Name), 927 is_json_term2(Options, Value). 928 929 /******************************* 930 * DICT SUPPORT * 931 *******************************/
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.972json_read_dict(Stream, Dict) :- 973 json_read_dict(Stream, Dict, []). 974 975json_read_dict(Stream, Dict, Options) :- 976 make_json_dict_options(Options, OptionTerm, _RestOptions), 977 ( json_value_top(Stream, Term, OptionTerm) 978 -> true 979 ; syntax_error(illegal_json, Stream) 980 ), 981 term_to_dict(Term, Dict, OptionTerm). 982 983term_to_dict(json(Pairs), Dict, Options) :- 984 !, 985 ( json_options_tag(Options, TagName), 986 Tag \== '', 987 select(TagName = Tag0, Pairs, NVPairs), 988 to_atom(Tag0, Tag) 989 -> json_dict_pairs(NVPairs, DictPairs, Options) 990 ; json_options_default_tag(Options, DefTag), 991 ( var(DefTag) 992 -> true 993 ; Tag = DefTag 994 ), 995 json_dict_pairs(Pairs, DictPairs, Options) 996 ), 997 dict_create(Dict, Tag, DictPairs). 998term_to_dict(Value0, Value, _Options) :- 999 atomic(Value0), Value0 \== [], 1000 !, 1001 Value = Value0. 1002term_to_dict(List0, List, Options) :- 1003 is_list(List0), 1004 !, 1005 terms_to_dicts(List0, List, Options). 1006term_to_dict(Special, Special, Options) :- 1007 ( json_options_true(Options, Special) 1008 ; json_options_false(Options, Special) 1009 ; json_options_null(Options, Special) 1010 ; json_options_end_of_file(Options, Special) 1011 ), 1012 !. 1013 1014json_dict_pairs([], [], _). 1015json_dict_pairs([Name=Value0|T0], [Name=Value|T], Options) :- 1016 term_to_dict(Value0, Value, Options), 1017 json_dict_pairs(T0, T, Options). 1018 1019terms_to_dicts([], [], _). 1020terms_to_dicts([Value0|T0], [Value|T], Options) :- 1021 term_to_dict(Value0, Value, Options), 1022 terms_to_dicts(T0, T, Options). 1023 1024to_atom(Tag, Atom) :- 1025 string(Tag), 1026 !, 1027 atom_string(Atom, Tag). 1028to_atom(Atom, Atom) :- 1029 atom(Atom).
1038json_write_dict(Stream, Dict) :- 1039 json_write_dict(Stream, Dict, []). 1040 1041json_write_dict(Stream, Dict, Options) :- 1042 make_json_write_state(Options, State, Options1), 1043 make_json_dict_options(Options1, OptionTerm, _RestOptions), 1044 json_write_term(Dict, Stream, State, OptionTerm). 1045 1046 1047make_json_dict_options(Options, Record, RestOptions) :- 1048 default_json_dict_options(Record0), 1049 set_json_options_fields(Options, Record0, Record, RestOptions).
atom
,
string
or codes
.1062atom_json_dict(Atom, Term, Options) :- 1063 ground(Atom), 1064 !, 1065 setup_call_cleanup( 1066 open_string(Atom, In), 1067 json_read_dict(In, Term, Options), 1068 close(In)). 1069atom_json_dict(Result, Term, Options) :- 1070 select_option(as(Type), Options, Options1, atom), 1071 ( type_term(Type, Result, Out) 1072 -> true 1073 ; must_be(oneof([atom,string,codes]), Type) 1074 ), 1075 with_output_to(Out, 1076 json_write_dict(current_output, Term, Options1)). 1077 1078 1079 /******************************* 1080 * MESSAGES * 1081 *******************************/ 1082 1083:- multifile 1084 prolog:error_message/3. 1085 1086prologerror_message(syntax_error(json(Id))) --> 1087 [ 'JSON syntax error: ' ], 1088 json_syntax_error(Id). 1089 1090json_syntax_error(illegal_comment) --> 1091 [ 'Illegal comment' ]. 1092json_syntax_error(illegal_string_escape) --> 1093 [ 'Illegal escape sequence 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. */