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-2016, University of Amsterdam 7 VU University Amsterdam 8 All rights reserved. 9 10 Redistribution and use in source and binary forms, with or without 11 modification, are permitted provided that the following conditions 12 are met: 13 14 1. Redistributions of source code must retain the above copyright 15 notice, this list of conditions and the following disclaimer. 16 17 2. Redistributions in binary form must reproduce the above copyright 18 notice, this list of conditions and the following disclaimer in 19 the documentation and/or other materials provided with the 20 distribution. 21 22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 POSSIBILITY OF SUCH DAMAGE. 34*/ 35 36:- if(current_predicate(is_dict/1)). 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 54:- else. 55 56:- module(json, 57 [ json_read/2, % +Stream, -JSONTerm 58 json_read/3, % +Stream, -JSONTerm, +Options 59 atom_json_term/3, % ?Atom, ?JSONTerm, +Options 60 json_write/2, % +Stream, +Term 61 json_write/3, % +Stream, +Term, +Options 62 is_json_term/1, % @Term 63 is_json_term/2 64 ]). 65 66:- endif. 67 68:- use_module(library(record)). 69:- use_module(library(memfile)). 70:- use_module(library(error)). 71:- use_module(library(option)). 72 73:- use_foreign_library(foreign(json)). 74 75:- predicate_options(json_read/3, 3, 76 [ null(ground), 77 true(ground), 78 false(ground), 79 value_string_as(oneof([atom,string])) 80 ]). 81:- predicate_options(json_write/3, 3, 82 [ indent(nonneg), 83 step(positive_integer), 84 tab(positive_integer), 85 width(nonneg), 86 null(ground), 87 true(ground), 88 false(ground), 89 serialize_unknown(boolean) 90 ]). 91:- predicate_options(json_read_dict/3, 3, 92 [ tag(atom), 93 pass_to(json_read/3, 3) 94 ]). 95:- predicate_options(json_write_dict/3, 3, 96 [ tag(atom), 97 pass_to(json_write/3, 3) 98 ]). 99:- predicate_options(is_json_term/2, 2, 100 [ null(ground), 101 true(ground), 102 false(ground) 103 ]). 104:- predicate_options(atom_json_term/3, 3, 105 [ as(oneof([atom,string,codes])), 106 pass_to(json_read/3, 3), 107 pass_to(json_write/3, 3) 108 ]).
132:- record json_options(null:ground = @(null), 133 true:ground = @(true), 134 false:ground = @(false), 135 value_string_as:oneof([atom,string]) = atom, 136 tag:atom = ''). 137 138default_json_dict_options( 139 json_options(null, true, false, string, '')). 140 141 142 /******************************* 143 * MAP TO/FROM TEXT * 144 *******************************/
atom
(default),
string
, codes
or chars
.155atom_json_term(Atom, Term, Options) :- 156 ground(Atom), 157 !, 158 setup_call_cleanup( 159 ( atom_to_memory_file(Atom, MF), 160 open_memory_file(MF, read, In, [free_on_close(true)]) 161 ), 162 json_read(In, Term, Options), 163 close(In)). 164atom_json_term(Result, Term, Options) :- 165 select_option(as(Type), Options, Options1, atom), 166 ( type_term(Type, Result, Out) 167 -> true 168 ; must_be(oneof([atom,string,codes,chars]), Type) 169 ), 170 with_output_to(Out, 171 json_write(current_output, Term, Options1)). 172 173type_term(atom, Result, atom(Result)). 174type_term(string, Result, string(Result)). 175type_term(codes, Result, codes(Result)). 176type_term(chars, Result, chars(Result)). 177 178 179 /******************************* 180 * READING * 181 *******************************/
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)atom
. The alternative is string
, producing a
packed string object. Please note that codes
or
chars
would produce ambiguous output and is therefore
not supported.246json_read(Stream, Term) :- 247 default_json_options(Options), 248 ( json_value(Stream, Term, _, Options) 249 -> true 250 ; syntax_error(illegal_json, Stream) 251 ). 252json_read(Stream, Term, Options) :- 253 make_json_options(Options, OptionTerm, _RestOptions), 254 ( json_value(Stream, Term, _, OptionTerm) 255 -> true 256 ; syntax_error(illegal_json, Stream) 257 ). 258 259json_value(Stream, Term, Next, Options) :- 260 get_code(Stream, C0), 261 ws(C0, Stream, C1), 262 ( C1 == -1 263 -> syntax_error(unexpected_end_of_file, Stream) 264 ; json_term(C1, Stream, Term, Next, Options) 265 ). 266 267json_term(0'{, Stream, json(Pairs), Next, Options) :- 268 !, 269 ws(Stream, C), 270 json_pairs(C, Stream, Pairs, Options), 271 get_code(Stream, Next). 272json_term(0'[, Stream, Array, Next, Options) :- 273 !, 274 ws(Stream, C), 275 json_array(C, Stream, Array, Options), 276 get_code(Stream, Next). 277json_term(0'", Stream, String, Next, Options) :- 278 !, 279 get_code(Stream, C1), 280 json_string_codes(C1, Stream, Codes), 281 json_options_value_string_as(Options, Type), 282 codes_to_type(Type, Codes, String), 283 get_code(Stream, Next). 284json_term(0'-, Stream, Number, Next, _Options) :- 285 !, 286 json_number_codes(Stream, Codes, Next), 287 number_codes(Number, [0'-|Codes]). 288json_term(D, Stream, Number, Next, _Options) :- 289 between(0'0, 0'9, D), 290 !, 291 json_number_codes(Stream, Codes, Next), 292 number_codes(Number, [D|Codes]). 293json_term(C, Stream, Constant, Next, Options) :- 294 get_code(Stream, C1), 295 json_identifier_codes(C1, Stream, Codes, Next), 296 atom_codes(ID, [C|Codes]), 297 json_constant(ID, Constant, Options). 298 299json_pairs(0'}, _, [], _) :- !. 300json_pairs(C0, Stream, [Pair|Tail], Options) :- 301 json_pair(C0, Stream, Pair, C, Options), 302 ws(C, Stream, Next), 303 ( Next == 0', 304 -> ws(Stream, C2), 305 json_pairs(C2, Stream, Tail, Options) 306 ; Next == 0'} 307 -> Tail = [] 308 ; syntax_error(illegal_object, Stream) 309 ). 310 311json_pair(C0, Stream, Name=Value, Next, Options) :- 312 json_string_as_atom(C0, Stream, Name), 313 ws(Stream, C), 314 C == 0':, 315 json_value(Stream, Value, Next, Options). 316 317 318json_array(0'], _, [], _) :- !. 319json_array(C0, Stream, [Value|Tail], Options) :- 320 json_term(C0, Stream, Value, C, Options), 321 ws(C, Stream, Next), 322 ( Next == 0', 323 -> ws(Stream, C1), 324 json_array(C1, Stream, Tail, Options) 325 ; Next == 0'] 326 -> Tail = [] 327 ; syntax_error(illegal_array, Stream) 328 ). 329 330codes_to_type(atom, Codes, Atom) :- 331 atom_codes(Atom, Codes). 332codes_to_type(string, Codes, Atom) :- 333 string_codes(Atom, Codes). 334codes_to_type(codes, Codes, Codes). 335 336json_string_as_atom(0'", Stream, Atom) :- 337 get_code(Stream, C1), 338 json_string_codes(C1, Stream, Codes), 339 atom_codes(Atom, Codes). 340 341json_string_codes(0'", _, []) :- !. 342json_string_codes(0'\\, Stream, [H|T]) :- 343 !, 344 get_code(Stream, C0), 345 ( escape(C0, Stream, H) 346 -> true 347 ; syntax_error(illegal_string_escape, Stream) 348 ), 349 get_code(Stream, C1), 350 json_string_codes(C1, Stream, T). 351json_string_codes(-1, Stream, _) :- 352 !, 353 syntax_error(eof_in_string, Stream). 354json_string_codes(C, Stream, [C|T]) :- 355 get_code(Stream, C1), 356 json_string_codes(C1, Stream, T). 357 358escape(0'", _, 0'") :- !. 359escape(0'\\, _, 0'\\) :- !. 360escape(0'/, _, 0'/) :- !. 361escape(0'b, _, 0'\b) :- !. 362escape(0'f, _, 0'\f) :- !. 363escape(0'n, _, 0'\n) :- !. 364escape(0'r, _, 0'\r) :- !. 365escape(0't, _, 0'\t) :- !. 366escape(0'u, Stream, C) :- 367 !, 368 get_code(Stream, C1), 369 get_code(Stream, C2), 370 get_code(Stream, C3), 371 get_code(Stream, C4), 372 code_type(C1, xdigit(D1)), 373 code_type(C2, xdigit(D2)), 374 code_type(C3, xdigit(D3)), 375 code_type(C4, xdigit(D4)), 376 C is D1<<12+D2<<8+D3<<4+D4. 377 378json_number_codes(Stream, Codes, Next) :- 379 get_code(Stream, C1), 380 json_number_codes(C1, Stream, Codes, Next). 381 382json_number_codes(C1, Stream, [C1|Codes], Next) :- 383 number_code(C1), 384 !, 385 get_code(Stream, C2), 386 json_number_codes(C2, Stream, Codes, Next). 387json_number_codes(C, _, [], C). 388 389number_code(C) :- 390 between(0'0, 0'9, C), 391 !. 392number_code(0'.). 393number_code(0'-). 394number_code(0'+). 395number_code(0'e). 396number_code(0'E). 397 398json_identifier_codes(C1, Stream, [C1|T], Next) :- 399 between(0'a, 0'z, C1), 400 !, 401 get_code(Stream, C2), 402 json_identifier_codes(C2, Stream, T, Next). 403json_identifier_codes(C, _, [], C). 404 405 406json_constant(true, Constant, Options) :- 407 !, 408 json_options_true(Options, Constant). 409json_constant(false, Constant, Options) :- 410 !, 411 json_options_false(Options, Constant). 412json_constant(null, Constant, Options) :- 413 !, 414 json_options_null(Options, Constant).
//
... comments.422ws(Stream, Next) :- 423 get_code(Stream, C0), 424 ws(C0, Stream, Next). 425 426ws(C0, Stream, C) :- 427 ws(C0), 428 !, 429 get_code(Stream, C1), 430 ws(C1, Stream, C). 431ws(0'/, Stream, C) :- 432 !, 433 get_code(Stream, Cmt1), 434 !, 435 expect(Cmt1, 0'/, Stream), 436 skip(Stream, 0'\n), 437 get_code(Stream, C0), 438 ws(C0, Stream, C). 439ws(C, _, C). 440 441ws(0' ). 442ws(0'\t). 443ws(0'\n). 444ws(0'\r). 445 446expect(C, C, _) :- !. 447expect(_, 0'/, Stream) :- 448 !, 449 syntax_error(illegal_comment, Stream). 450 451syntax_error(Message, Stream) :- 452 stream_error_context(Stream, Context), 453 throw(error(syntax_error(json(Message)), Context)). 454 455stream_error_context(Stream, stream(Stream, Line, LinePos, CharNo)) :- 456 stream_pair(Stream, Read, _), 457 character_count(Read, CharNo), 458 line_position(Read, LinePos), 459 line_count(Read, Line). 460 461 462 /******************************* 463 * JSON OUTPUT * 464 *******************************/
471% foreign json_write_string/2.
line_position(Stream, Pos)
is not 0. Then it writes Indent //
TabDistance tab characters and Indent mode TabDistance spaces.
479% 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.
The version 7 dict type is supported as well. If the dicts has
a tag, a property "type":"tag" is added to the object. This
behaviour can be changed using the tag
option (see below). For
example:
?- json_write(current_output, point{x:1,y:2}). { "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.
536:- record json_write_state(indent:nonneg = 0, 537 step:positive_integer = 2, 538 tab:positive_integer = 8, 539 width:nonneg = 72, 540 serialize_unknown:boolean = false 541 ). 542 543json_write(Stream, Term) :- 544 json_write(Stream, Term, []). 545json_write(Stream, Term, Options) :- 546 make_json_write_state(Options, State, Options1), 547 make_json_options(Options1, OptionTerm, _RestOptions), 548 json_write_term(Term, Stream, State, OptionTerm). 549 550json_write_term(Var, _, _, _) :- 551 var(Var), 552 !, 553 instantiation_error(Var). 554json_write_term(json(Pairs), Stream, State, Options) :- 555 !, 556 json_write_object(Pairs, Stream, State, Options). 557:- if(current_predicate(is_dict/1)). 558json_write_term(Dict, Stream, State, Options) :- 559 is_dict(Dict), 560 !, 561 dict_pairs(Dict, Tag, Pairs0), 562 ( nonvar(Tag), 563 json_options_tag(Options, Name), 564 Name \== '' 565 -> Pairs = [Name-Tag|Pairs0] 566 ; Pairs = Pairs0 567 ), 568 json_write_object(Pairs, Stream, State, Options). 569:- endif. 570json_write_term(List, Stream, State, Options) :- 571 is_list(List), 572 !, 573 space_if_not_at_left_margin(Stream, State), 574 write(Stream, '['), 575 ( json_write_state_width(State, Width), 576 ( Width == 0 577 -> true 578 ; json_write_state_indent(State, Indent), 579 json_print_length(List, Options, Width, Indent, _) 580 ) 581 -> set_width_of_json_write_state(0, State, State2), 582 write_array_hor(List, Stream, State2, Options), 583 write(Stream, ']') 584 ; step_indent(State, State2), 585 write_array_ver(List, Stream, State2, Options), 586 indent(Stream, State), 587 write(Stream, ']') 588 ). 589json_write_term(Number, Stream, _State, _Options) :- 590 number(Number), 591 !, 592 write(Stream, Number). 593json_write_term(True, Stream, _State, Options) :- 594 json_options_true(Options, True), 595 !, 596 write(Stream, true). 597json_write_term(False, Stream, _State, Options) :- 598 json_options_false(Options, False), 599 !, 600 write(Stream, false). 601json_write_term(Null, Stream, _State, Options) :- 602 json_options_null(Options, Null), 603 !, 604 write(Stream, null). 605json_write_term(#(Text), Stream, _State, _Options) :- 606 !, 607 ( ( atom(Text) 608 ; string(Text) 609 ) 610 -> json_write_string(Stream, Text) 611 ; term_string(Text, String), 612 json_write_string(Stream, String) 613 ). 614json_write_term(String, Stream, _State, _Options) :- 615 atom(String), 616 !, 617 json_write_string(Stream, String). 618json_write_term(String, Stream, _State, _Options) :- 619 string(String), 620 !, 621 json_write_string(Stream, String). 622json_write_term(AnyTerm, Stream, State, _Options) :- 623 ( json_write_state_serialize_unknown(State, true) 624 -> term_string(AnyTerm, String), 625 json_write_string(Stream, String) 626 ; type_error(json_term, AnyTerm) 627 ). 628 629json_write_object(Pairs, Stream, State, Options) :- 630 space_if_not_at_left_margin(Stream, State), 631 write(Stream, '{'), 632 ( json_write_state_width(State, Width), 633 ( Width == 0 634 -> true 635 ; json_write_state_indent(State, Indent), 636 json_print_length(json(Pairs), Options, Width, Indent, _) 637 ) 638 -> set_width_of_json_write_state(0, State, State2), 639 write_pairs_hor(Pairs, Stream, State2, Options), 640 write(Stream, '}') 641 ; step_indent(State, State2), 642 write_pairs_ver(Pairs, Stream, State2, Options), 643 indent(Stream, State), 644 write(Stream, '}') 645 ). 646 647 648write_pairs_hor([], _, _, _). 649write_pairs_hor([H|T], Stream, State, Options) :- 650 json_pair(H, Name, Value), 651 json_write_string(Stream, Name), 652 write(Stream, ':'), 653 json_write_term(Value, Stream, State, Options), 654 ( T == [] 655 -> true 656 ; write(Stream, ', '), 657 write_pairs_hor(T, Stream, State, Options) 658 ). 659 660write_pairs_ver([], _, _, _). 661write_pairs_ver([H|T], Stream, State, Options) :- 662 indent(Stream, State), 663 json_pair(H, Name, Value), 664 json_write_string(Stream, Name), 665 write(Stream, ':'), 666 json_write_term(Value, Stream, State, Options), 667 ( T == [] 668 -> true 669 ; write(Stream, ','), 670 write_pairs_ver(T, Stream, State, Options) 671 ). 672 673 674json_pair(Var, _, _) :- 675 var(Var), 676 !, 677 instantiation_error(Var). 678json_pair(Name=Value, Name, Value) :- !. 679json_pair(Name-Value, Name, Value) :- !. 680json_pair(NameValue, Name, Value) :- 681 compound(NameValue), 682 NameValue =.. [Name, Value], 683 !. 684json_pair(Pair, _, _) :- 685 type_error(json_pair, Pair). 686 687 688write_array_hor([], _, _, _). 689write_array_hor([H|T], Stream, State, Options) :- 690 json_write_term(H, Stream, State, Options), 691 ( T == [] 692 -> write(Stream, ' ') 693 ; write(Stream, ', '), 694 write_array_hor(T, Stream, State, Options) 695 ). 696 697write_array_ver([], _, _, _). 698write_array_ver([H|T], Stream, State, Options) :- 699 indent(Stream, State), 700 json_write_term(H, Stream, State, Options), 701 ( T == [] 702 -> true 703 ; write(Stream, ','), 704 write_array_ver(T, Stream, State, Options) 705 ). 706 707 708indent(Stream, State) :- 709 json_write_state_indent(State, Indent), 710 json_write_state_tab(State, Tab), 711 json_write_indent(Stream, Indent, Tab). 712 713step_indent(State0, State) :- 714 json_write_state_indent(State0, Indent), 715 json_write_state_step(State0, Step), 716 NewIndent is Indent+Step, 717 set_indent_of_json_write_state(NewIndent, State0, State). 718 719space_if_not_at_left_margin(Stream, State) :- 720 stream_pair(Stream, _, Write), 721 line_position(Write, LinePos), 722 ( LinePos == 0 723 ; json_write_state_indent(State, LinePos) 724 ), 725 !. 726space_if_not_at_left_margin(Stream, _) :- 727 put_char(Stream, ' ').
737json_print_length(Var, _, _, _, _) :- 738 var(Var), 739 !, 740 instantiation_error(Var). 741json_print_length(json(Pairs), Options, Max, Len0, Len) :- 742 !, 743 Len1 is Len0 + 2, 744 Len1 =< Max, 745 must_be(list, Pairs), 746 pairs_print_length(Pairs, Options, Max, Len1, Len). 747:- if(current_predicate(is_dict/1)). 748json_print_length(Dict, Options, Max, Len0, Len) :- 749 is_dict(Dict), 750 !, 751 dict_pairs(Dict, _Tag, Pairs), 752 Len1 is Len0 + 2, 753 Len1 =< Max, 754 pairs_print_length(Pairs, Options, Max, Len1, Len). 755:- endif. 756json_print_length(Array, Options, Max, Len0, Len) :- 757 is_list(Array), 758 !, 759 Len1 is Len0 + 2, 760 Len1 =< Max, 761 array_print_length(Array, Options, Max, Len1, Len). 762json_print_length(Null, Options, Max, Len0, Len) :- 763 json_options_null(Options, Null), 764 !, 765 Len is Len0 + 4, 766 Len =< Max. 767json_print_length(False, Options, Max, Len0, Len) :- 768 json_options_false(Options, False), 769 !, 770 Len is Len0 + 5, 771 Len =< Max. 772json_print_length(True, Options, Max, Len0, Len) :- 773 json_options_true(Options, True), 774 !, 775 Len is Len0 + 4, 776 Len =< Max. 777json_print_length(Number, _Options, Max, Len0, Len) :- 778 number(Number), 779 !, 780 write_length(Number, AL, []), 781 Len is Len0 + AL, 782 Len =< Max. 783json_print_length(@(Id), _Options, Max, Len0, Len) :- 784 atom(Id), 785 !, 786 atom_length(Id, IdLen), 787 Len is Len0+IdLen, 788 Len =< Max. 789json_print_length(String, _Options, Max, Len0, Len) :- 790 string_len(String, Len0, Len), 791 !, 792 Len =< Max. 793json_print_length(AnyTerm, _Options, Max, Len0, Len) :- 794 write_length(AnyTerm, AL, []), % will be serialized 795 Len is Len0 + AL+2, 796 Len =< Max. 797 798pairs_print_length([], _, _, Len, Len). 799pairs_print_length([H|T], Options, Max, Len0, Len) :- 800 pair_len(H, Options, Max, Len0, Len1), 801 ( T == [] 802 -> Len = Len1 803 ; Len2 is Len1 + 2, 804 Len2 =< Max, 805 pairs_print_length(T, Options, Max, Len2, Len) 806 ). 807 808pair_len(Pair, Options, Max, Len0, Len) :- 809 compound(Pair), 810 pair_nv(Pair, Name, Value), 811 !, 812 string_len(Name, Len0, Len1), 813 Len2 is Len1+2, 814 Len2 =< Max, 815 json_print_length(Value, Options, Max, Len2, Len). 816pair_len(Pair, _Options, _Max, _Len0, _Len) :- 817 type_error(pair, Pair). 818 819pair_nv(Name=Value, Name, Value) :- !. 820pair_nv(Name-Value, Name, Value) :- !. 821pair_nv(Term, Name, Value) :- 822 compound_name_arguments(Term, Name, [Value]). 823 824array_print_length([], _, _, Len, Len). 825array_print_length([H|T], Options, Max, Len0, Len) :- 826 json_print_length(H, Options, Max, Len0, Len1), 827 ( T == [] 828 -> Len = Len1 829 ; Len2 is Len1+2, 830 Len2 =< Max, 831 array_print_length(T, Options, Max, Len2, Len) 832 ). 833 834string_len(String, Len0, Len) :- 835 atom(String), 836 !, 837 atom_length(String, AL), 838 Len is Len0 + AL + 2. 839string_len(String, Len0, Len) :- 840 string(String), 841 !, 842 string_length(String, AL), 843 Len is Len0 + AL + 2. 844 845 846 /******************************* 847 * TEST * 848 *******************************/
true
, false
and null
constants.857is_json_term(Term) :- 858 default_json_options(Options), 859 is_json_term2(Options, Term). 860 861is_json_term(Term, Options) :- 862 make_json_options(Options, OptionTerm, _RestOptions), 863 is_json_term2(OptionTerm, Term). 864 865is_json_term2(_, Var) :- 866 var(Var), !, fail. 867is_json_term2(Options, json(Pairs)) :- 868 !, 869 is_list(Pairs), 870 maplist(is_json_pair(Options), Pairs). 871is_json_term2(Options, List) :- 872 is_list(List), 873 !, 874 maplist(is_json_term2(Options), List). 875is_json_term2(_, Primitive) :- 876 atomic(Primitive), 877 !. % atom, string or number 878is_json_term2(Options, True) :- 879 json_options_true(Options, True). 880is_json_term2(Options, False) :- 881 json_options_false(Options, False). 882is_json_term2(Options, Null) :- 883 json_options_null(Options, Null). 884 885is_json_pair(_, Var) :- 886 var(Var), !, fail. 887is_json_pair(Options, Name=Value) :- 888 atom(Name), 889 is_json_term2(Options, Value). 890 891:- if(current_predicate(is_dict/1)). 892 893 /******************************* 894 * DICT SUPPORT * 895 *******************************/
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.
null
.true
.false
string
. The alternative is atom
, producing a
packed string object.931json_read_dict(Stream, Dict) :- 932 json_read_dict(Stream, Dict, []). 933 934json_read_dict(Stream, Dict, Options) :- 935 make_json_dict_options(Options, OptionTerm, _RestOptions), 936 ( json_value(Stream, Term, _, OptionTerm) 937 -> true 938 ; syntax_error(illegal_json, Stream) 939 ), 940 term_to_dict(Term, Dict, OptionTerm). 941 942term_to_dict(json(Pairs), Dict, Options) :- 943 !, 944 ( json_options_tag(Options, TagName), 945 Tag \== '', 946 select(TagName = Tag0, Pairs, NVPairs), 947 to_atom(Tag0, Tag) 948 -> json_dict_pairs(NVPairs, DictPairs, Options) 949 ; json_dict_pairs(Pairs, DictPairs, Options) 950 ), 951 dict_create(Dict, Tag, DictPairs). 952term_to_dict(Value0, Value, _Options) :- 953 atomic(Value0), Value0 \== [], 954 !, 955 Value = Value0. 956term_to_dict(List0, List, Options) :- 957 assertion(is_list(List0)), 958 terms_to_dicts(List0, List, Options). 959 960json_dict_pairs([], [], _). 961json_dict_pairs([Name=Value0|T0], [Name=Value|T], Options) :- 962 term_to_dict(Value0, Value, Options), 963 json_dict_pairs(T0, T, Options). 964 965terms_to_dicts([], [], _). 966terms_to_dicts([Value0|T0], [Value|T], Options) :- 967 term_to_dict(Value0, Value, Options), 968 terms_to_dicts(T0, T, Options). 969 970to_atom(Tag, Atom) :- 971 string(Tag), 972 !, 973 atom_string(Atom, Tag). 974to_atom(Atom, Atom) :- 975 atom(Atom).
984json_write_dict(Stream, Dict) :- 985 json_write_dict(Stream, Dict, []). 986 987json_write_dict(Stream, Dict, Options) :- 988 make_json_write_state(Options, State, Options1), 989 make_json_dict_options(Options1, OptionTerm, _RestOptions), 990 json_write_term(Dict, Stream, State, OptionTerm). 991 992 993make_json_dict_options(Options, Record, RestOptions) :- 994 default_json_dict_options(Record0), 995 set_json_options_fields(Options, Record0, Record, RestOptions).
atom
,
string
or codes
.1008atom_json_dict(Atom, Term, Options) :- 1009 ground(Atom), 1010 !, 1011 setup_call_cleanup( 1012 ( text_memfile(Atom, MF), 1013 open_memory_file(MF, read, In, [free_on_close(true)]) 1014 ), 1015 json_read_dict(In, Term, Options), 1016 close(In)). 1017atom_json_dict(Result, Term, Options) :- 1018 select_option(as(Type), Options, Options1, atom), 1019 ( type_term(Type, Result, Out) 1020 -> true 1021 ; must_be(oneof([atom,string,codes]), Type) 1022 ), 1023 with_output_to(Out, 1024 json_write_dict(current_output, Term, Options1)). 1025 1026text_memfile(Atom, MF) :- 1027 atom(Atom), 1028 !, 1029 atom_to_memory_file(Atom, MF). 1030text_memfile(String, MF) :- 1031 string(String), 1032 !, 1033 new_memory_file(MF), 1034 insert_memory_file(MF, 0, String). 1035 1036:- endif. 1037 1038 /******************************* 1039 * MESSAGES * 1040 *******************************/ 1041 1042:- multifile 1043 prolog:error_message/3. 1044 1045prologerror_message(syntax_error(json(Id))) --> 1046 [ 'JSON syntax error: ' ], 1047 json_syntax_error(Id). 1048 1049json_syntax_error(illegal_comment) --> 1050 [ 'Illegal comment' ]. 1051json_syntax_error(illegal_string_escape) --> 1052 [ '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. */