1 /* -*- Mode: c; c-basic-offset: 2 -*-
2 *
3 * raptor_serialize_json.c - JSON serializers
4 *
5 * Copyright (C) 2008-2009, David Beckett http://www.dajobe.org/
6 *
7 * This package is Free Software and part of Redland http://librdf.org/
8 *
9 * It is licensed under the following three licenses as alternatives:
10 * 1. GNU Lesser General Public License (LGPL) V2.1 or any newer version
11 * 2. GNU General Public License (GPL) V2 or any newer version
12 * 3. Apache License, V2.0 or any newer version
13 *
14 * You may not use this file except in compliance with at least one of
15 * the above three licenses.
16 *
17 * See LICENSE.html or LICENSE.txt at the top of this package for the
18 * complete terms and further detail along with the license texts for
19 * the licenses in COPYING.LIB, COPYING and LICENSE-2.0.txt respectively.
20 *
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <raptor_config.h>
25 #endif
26
27 #ifdef WIN32
28 #include <win32_raptor_config.h>
29 #endif
30
31
32 #include <stdio.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include <stdarg.h>
36 #ifdef HAVE_STDLIB_H
37 #include <stdlib.h>
38 #endif
39
40 /* Raptor includes */
41 #include "raptor.h"
42 #include "raptor_internal.h"
43
44
45 /*
46 * Raptor JSON serializer object
47 */
48 typedef struct {
49 /* non-0 if json-r otherwise json-t */
50 int is_resource;
51
52 int need_subject_comma;
53
54 /* JSON writer object */
55 raptor_json_writer* json_writer;
56
57 /* Ordered sequence of triples if is_resource */
58 raptor_avltree* avltree;
59
60 /* Last statement generated if is_resource (shared pointer) */
61 raptor_statement_v2* last_statement;
62
63 int need_object_comma;
64
65 } raptor_json_context;
66
67
68 static int raptor_json_serialize_init(raptor_serializer* serializer,
69 const char *name);
70 static void raptor_json_serialize_terminate(raptor_serializer* serializer);
71 static int raptor_json_serialize_start(raptor_serializer* serializer);
72 static int raptor_json_serialize_statement(raptor_serializer* serializer,
73 const raptor_statement *statement);
74 static int raptor_json_serialize_end(raptor_serializer* serializer);
75 static void raptor_json_serialize_finish_factory(raptor_serializer_factory* factory);
76
77
78 /*
79 * raptor serializer JSON implementation
80 */
81
82
83 /* create a new serializer */
84 static int
raptor_json_serialize_init(raptor_serializer * serializer,const char * name)85 raptor_json_serialize_init(raptor_serializer* serializer, const char *name)
86 {
87 raptor_json_context* context=(raptor_json_context*)serializer->context;
88
89 context->is_resource=!strcmp(name,"json");
90
91 /* Default for JSON serializer is absolute URIs */
92 serializer->feature_relative_uris=0;
93
94 return 0;
95 }
96
97
98 /* destroy a serializer */
99 static void
raptor_json_serialize_terminate(raptor_serializer * serializer)100 raptor_json_serialize_terminate(raptor_serializer* serializer)
101 {
102 raptor_json_context* context=(raptor_json_context*)serializer->context;
103
104 if(context->json_writer) {
105 raptor_free_json_writer(context->json_writer);
106 context->json_writer=NULL;
107 }
108
109 if(context->avltree) {
110 raptor_free_avltree(context->avltree);
111 context->avltree=NULL;
112 }
113 }
114
115
116 static int
raptor_json_serialize_start(raptor_serializer * serializer)117 raptor_json_serialize_start(raptor_serializer* serializer)
118 {
119 raptor_json_context* context=(raptor_json_context*)serializer->context;
120 raptor_uri* base_uri;
121
122 base_uri=(serializer->feature_relative_uris) ? serializer->base_uri : NULL;
123
124 context->json_writer=raptor_new_json_writer(serializer->world,
125 base_uri,
126 serializer->iostream,
127 (raptor_simple_message_handler)raptor_serializer_simple_error,
128 serializer);
129 if(!context->json_writer)
130 return 1;
131
132 if(context->is_resource) {
133 context->avltree=raptor_new_avltree(serializer->world,
134 (raptor_data_compare_function)raptor_statement_compare_v2,
135 (raptor_data_free_function)raptor_free_statement_v2,
136 0);
137 if(!context->avltree) {
138 raptor_free_json_writer(context->json_writer);
139 context->json_writer=NULL;
140 return 1;
141 }
142 }
143
144 /* start callback */
145 if(serializer->feature_json_callback) {
146 raptor_iostream_write_string(serializer->iostream,
147 serializer->feature_json_callback);
148 raptor_iostream_write_byte(serializer->iostream, '(');
149 }
150
151 if(!context->is_resource) {
152 /* start outer object */
153 raptor_json_writer_start_block(context->json_writer, '{');
154 raptor_json_writer_newline(context->json_writer);
155
156 /* start triples array */
157 raptor_iostream_write_counted_string(serializer->iostream,
158 (const unsigned char*)"\"triples\" : ", 12);
159 raptor_json_writer_start_block(context->json_writer, '[');
160 raptor_json_writer_newline(context->json_writer);
161 }
162
163 return 0;
164 }
165
166
167 static int
raptor_json_serialize_statement(raptor_serializer * serializer,const raptor_statement * statement)168 raptor_json_serialize_statement(raptor_serializer* serializer,
169 const raptor_statement *statement)
170 {
171 raptor_json_context* context=(raptor_json_context*)serializer->context;
172
173 if(context->is_resource) {
174 raptor_statement_v2* s=raptor_statement_copy_v2_from_v1(serializer->world, statement);
175 if(!s)
176 return 1;
177 return raptor_avltree_add(context->avltree, s);
178 }
179
180 if(context->need_subject_comma) {
181 raptor_iostream_write_byte(serializer->iostream, ',');
182 raptor_json_writer_newline(context->json_writer);
183 }
184
185 /* start triple */
186 raptor_json_writer_start_block(context->json_writer, '{');
187 raptor_json_writer_newline(context->json_writer);
188
189 /* subject */
190 raptor_iostream_write_string(serializer->iostream,
191 (const unsigned char*)"\"subject\" : ");
192 switch(statement->subject_type) {
193 case RAPTOR_IDENTIFIER_TYPE_RESOURCE:
194 case RAPTOR_IDENTIFIER_TYPE_PREDICATE:
195 raptor_json_writer_uri_object(context->json_writer,
196 (raptor_uri*)statement->subject);
197 break;
198
199 case RAPTOR_IDENTIFIER_TYPE_ANONYMOUS:
200 raptor_json_writer_blank_object(context->json_writer,
201 (const char*)statement->subject);
202 break;
203
204 case RAPTOR_IDENTIFIER_TYPE_LITERAL:
205 case RAPTOR_IDENTIFIER_TYPE_XML_LITERAL:
206 case RAPTOR_IDENTIFIER_TYPE_ORDINAL:
207 case RAPTOR_IDENTIFIER_TYPE_UNKNOWN:
208 default:
209 RAPTOR_FATAL1("Unsupported identifier type\n");
210 break;
211 }
212 raptor_iostream_write_byte(serializer->iostream, ',');
213 raptor_json_writer_newline(context->json_writer);
214
215 /* predicate */
216 raptor_iostream_write_string(serializer->iostream,
217 (const unsigned char*)"\"predicate\" : ");
218 raptor_json_writer_uri_object(context->json_writer,
219 (raptor_uri*)statement->predicate);
220 raptor_iostream_write_byte(serializer->iostream, ',');
221 raptor_json_writer_newline(context->json_writer);
222
223 /* object */
224 raptor_iostream_write_string(serializer->iostream,
225 (const unsigned char*)"\"object\" : ");
226 switch(statement->object_type) {
227 case RAPTOR_IDENTIFIER_TYPE_RESOURCE:
228 case RAPTOR_IDENTIFIER_TYPE_PREDICATE:
229 raptor_json_writer_uri_object(context->json_writer,
230 (raptor_uri*)statement->object);
231 break;
232
233 case RAPTOR_IDENTIFIER_TYPE_LITERAL:
234 case RAPTOR_IDENTIFIER_TYPE_XML_LITERAL:
235 raptor_json_writer_literal_object(context->json_writer,
236 (unsigned char*)statement->object,
237 (unsigned char*)statement->object_literal_language,
238 statement->object_literal_datatype,
239 "value", "type");
240 break;
241
242 case RAPTOR_IDENTIFIER_TYPE_ANONYMOUS:
243 raptor_json_writer_blank_object(context->json_writer,
244 (const char*)statement->object);
245 break;
246
247 case RAPTOR_IDENTIFIER_TYPE_ORDINAL:
248 case RAPTOR_IDENTIFIER_TYPE_UNKNOWN:
249 default:
250 RAPTOR_FATAL1("Unsupported identifier type\n");
251 break;
252 }
253 raptor_json_writer_newline(context->json_writer);
254
255 /* end triple */
256 raptor_json_writer_end_block(context->json_writer, '}');
257
258 context->need_subject_comma=1;
259 return 0;
260 }
261
262
263 /* return 0 to abort visit */
264 static int
raptor_json_serialize_avltree_visit(int depth,void * data,void * user_data)265 raptor_json_serialize_avltree_visit(int depth, void* data, void *user_data)
266 {
267 raptor_serializer* serializer=(raptor_serializer*)user_data;
268 raptor_json_context* context=(raptor_json_context*)serializer->context;
269
270 raptor_statement_v2* statement=(raptor_statement_v2*)data;
271 raptor_statement* s1 = statement->s;
272 raptor_statement* s2 = context->last_statement ? (context->last_statement->s) : NULL;
273 int new_subject=0;
274 int new_predicate=0;
275
276 if(s2) {
277 if(s1->subject_type != s2->subject_type) {
278 new_subject=1;
279 } else {
280 /* subjects are URIs or blank nodes */
281 if(s1->subject_type == RAPTOR_IDENTIFIER_TYPE_ANONYMOUS)
282 new_subject=strcmp((char*)s1->subject, (char*)s2->subject);
283 else
284 new_subject=!raptor_uri_equals_v2(serializer->world,
285 (raptor_uri*)s1->subject,
286 (raptor_uri*)s2->subject);
287 }
288
289 if(new_subject) {
290 /* end last predicate */
291 raptor_json_writer_newline(context->json_writer);
292
293 raptor_json_writer_end_block(context->json_writer, ']');
294 raptor_json_writer_newline(context->json_writer);
295
296 /* end last statement */
297 raptor_json_writer_end_block(context->json_writer, '}');
298 raptor_json_writer_newline(context->json_writer);
299
300 context->need_subject_comma=1;
301 context->need_object_comma=0;
302 }
303 } else
304 new_subject=1;
305
306 if(new_subject) {
307 if(context->need_subject_comma) {
308 raptor_iostream_write_byte(serializer->iostream, ',');
309 raptor_json_writer_newline(context->json_writer);
310 }
311
312 /* start triple */
313
314 /* subject */
315 switch(s1->subject_type) {
316 case RAPTOR_IDENTIFIER_TYPE_RESOURCE:
317 case RAPTOR_IDENTIFIER_TYPE_PREDICATE:
318 raptor_json_writer_key_uri_value(context->json_writer,
319 NULL, 0,
320 (raptor_uri*)s1->subject);
321 break;
322
323 case RAPTOR_IDENTIFIER_TYPE_ANONYMOUS:
324 raptor_iostream_write_counted_string(serializer->iostream, "\"_:", 3);
325 raptor_iostream_write_string_python(serializer->iostream,
326 (const unsigned char*)s1->subject, 0,
327 '"', 2);
328 raptor_iostream_write_byte(serializer->iostream, '"');
329 break;
330
331 case RAPTOR_IDENTIFIER_TYPE_LITERAL:
332 case RAPTOR_IDENTIFIER_TYPE_XML_LITERAL:
333 case RAPTOR_IDENTIFIER_TYPE_ORDINAL:
334 case RAPTOR_IDENTIFIER_TYPE_UNKNOWN:
335 default:
336 RAPTOR_FATAL2("Unsupported statement subject identifier type %d\n",
337 s1->subject_type);
338 break;
339 }
340
341 raptor_iostream_write_counted_string(serializer->iostream, " : ", 3);
342 raptor_json_writer_start_block(context->json_writer, '{');
343
344 raptor_json_writer_newline(context->json_writer);
345 }
346
347
348 /* predicate */
349 if(context->last_statement) {
350 if(new_subject)
351 new_predicate=1;
352 else {
353 new_predicate=!raptor_uri_equals_v2(serializer->world,
354 (raptor_uri*)s1->predicate,
355 (raptor_uri*)s2->predicate);
356 if(new_predicate) {
357 raptor_json_writer_newline(context->json_writer);
358 raptor_json_writer_end_block(context->json_writer, ']');
359 raptor_iostream_write_byte(serializer->iostream, ',');
360 raptor_json_writer_newline(context->json_writer);
361 }
362 }
363 } else
364 new_predicate=1;
365
366 if(new_predicate) {
367 /* start predicate */
368
369 raptor_json_writer_key_uri_value(context->json_writer,
370 NULL, 0,
371 (raptor_uri*)s1->predicate);
372 raptor_iostream_write_counted_string(serializer->iostream, " : ", 3);
373 raptor_json_writer_start_block(context->json_writer, '[');
374 raptor_iostream_write_byte(serializer->iostream, ' ');
375
376 context->need_object_comma=0;
377 }
378
379 if(context->need_object_comma) {
380 raptor_iostream_write_byte(serializer->iostream, ',');
381 raptor_json_writer_newline(context->json_writer);
382 }
383
384 /* object */
385 switch(s1->object_type) {
386 case RAPTOR_IDENTIFIER_TYPE_RESOURCE:
387 case RAPTOR_IDENTIFIER_TYPE_PREDICATE:
388 raptor_json_writer_uri_object(context->json_writer,
389 (raptor_uri*)s1->object);
390 raptor_json_writer_newline(context->json_writer);
391 break;
392
393 case RAPTOR_IDENTIFIER_TYPE_LITERAL:
394 case RAPTOR_IDENTIFIER_TYPE_XML_LITERAL:
395 raptor_json_writer_literal_object(context->json_writer,
396 (unsigned char*)s1->object,
397 (unsigned char*)s1->object_literal_language,
398 s1->object_literal_datatype,
399 "value", "type");
400 break;
401
402 case RAPTOR_IDENTIFIER_TYPE_ANONYMOUS:
403 raptor_json_writer_blank_object(context->json_writer,
404 (const char*)s1->object);
405 raptor_json_writer_newline(context->json_writer);
406 break;
407
408 case RAPTOR_IDENTIFIER_TYPE_ORDINAL:
409 case RAPTOR_IDENTIFIER_TYPE_UNKNOWN:
410 default:
411 RAPTOR_FATAL2("Unsupported statement object identifier type %d\n",
412 s1->object_type);
413 break;
414 }
415
416 /* end triple */
417
418 context->need_object_comma = 1;
419 context->last_statement = statement;
420
421 return 1;
422 }
423
424
425 static int
raptor_json_serialize_end(raptor_serializer * serializer)426 raptor_json_serialize_end(raptor_serializer* serializer)
427 {
428 raptor_json_context* context=(raptor_json_context*)serializer->context;
429
430 raptor_json_writer_newline(context->json_writer);
431
432 if(context->is_resource) {
433 /* start outer object */
434 raptor_json_writer_start_block(context->json_writer, '{');
435 raptor_json_writer_newline(context->json_writer);
436
437 raptor_avltree_visit(context->avltree,
438 raptor_json_serialize_avltree_visit,
439 serializer);
440
441 /* end last triples block */
442 if(context->last_statement) {
443 raptor_json_writer_newline(context->json_writer);
444 raptor_json_writer_end_block(context->json_writer, ']');
445 raptor_json_writer_newline(context->json_writer);
446
447 raptor_json_writer_end_block(context->json_writer, '}');
448 raptor_json_writer_newline(context->json_writer);
449 }
450 } else {
451 /* end triples array */
452 raptor_json_writer_end_block(context->json_writer, ']');
453 raptor_json_writer_newline(context->json_writer);
454 }
455
456
457 if(serializer->feature_json_extra_data) {
458 raptor_iostream_write_byte(serializer->iostream, ',');
459 raptor_json_writer_newline(context->json_writer);
460 raptor_iostream_write_string(serializer->iostream,
461 serializer->feature_json_extra_data);
462 raptor_json_writer_newline(context->json_writer);
463 }
464
465
466 /* end outer object */
467 raptor_json_writer_end_block(context->json_writer, '}');
468 raptor_json_writer_newline(context->json_writer);
469
470 /* end callback */
471 if(serializer->feature_json_callback)
472 raptor_iostream_write_counted_string(serializer->iostream,
473 (const unsigned char*)");", 2);
474
475 return 0;
476 }
477
478
479 static void
raptor_json_serialize_finish_factory(raptor_serializer_factory * factory)480 raptor_json_serialize_finish_factory(raptor_serializer_factory* factory)
481 {
482 /* NOP */
483 }
484
485
486
487 static int
raptor_json_triples_serializer_register_factory(raptor_serializer_factory * factory)488 raptor_json_triples_serializer_register_factory(raptor_serializer_factory *factory)
489 {
490 factory->context_length = sizeof(raptor_json_context);
491
492 factory->init = raptor_json_serialize_init;
493 factory->terminate = raptor_json_serialize_terminate;
494 factory->declare_namespace = NULL;
495 factory->declare_namespace_from_namespace = NULL;
496 factory->serialize_start = raptor_json_serialize_start;
497 factory->serialize_statement = raptor_json_serialize_statement;
498 factory->serialize_end = raptor_json_serialize_end;
499 factory->finish_factory = raptor_json_serialize_finish_factory;
500
501 return 0;
502 }
503
504
505 static int
raptor_json_resource_serializer_register_factory(raptor_serializer_factory * factory)506 raptor_json_resource_serializer_register_factory(raptor_serializer_factory *factory)
507 {
508 factory->context_length = sizeof(raptor_json_context);
509
510 factory->init = raptor_json_serialize_init;
511 factory->terminate = raptor_json_serialize_terminate;
512 factory->declare_namespace = NULL;
513 factory->declare_namespace_from_namespace = NULL;
514 factory->serialize_start = raptor_json_serialize_start;
515 factory->serialize_statement = raptor_json_serialize_statement;
516 factory->serialize_end = raptor_json_serialize_end;
517 factory->finish_factory = raptor_json_serialize_finish_factory;
518
519 return 0;
520 }
521
522
523 int
raptor_init_serializer_json(raptor_world * world)524 raptor_init_serializer_json(raptor_world* world)
525 {
526 int rc;
527
528 rc=raptor_serializer_register_factory(world,
529 "json-triples",
530 "RDF/JSON Triples",
531 "application/json",
532 NULL,
533 NULL,
534 &raptor_json_triples_serializer_register_factory);
535 if(rc)
536 return rc;
537
538 return raptor_serializer_register_factory(world,
539 "json",
540 "RDF/JSON Resource-Centric",
541 "application/json",
542 NULL,
543 (const unsigned char *)"http://n2.talis.com/wiki/RDF_JSON_Specification",
544 &raptor_json_resource_serializer_register_factory);
545 }
546