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