/* -*- Mode: c; c-basic-offset: 2 -*- * * raptor_json_writer.c - Raptor JSON Writer * * Copyright (C) 2008, David Beckett http://www.dajobe.org/ * * This package is Free Software and part of Redland http://librdf.org/ * * It is licensed under the following three licenses as alternatives: * 1. GNU Lesser General Public License (LGPL) V2.1 or any newer version * 2. GNU General Public License (GPL) V2 or any newer version * 3. Apache License, V2.0 or any newer version * * You may not use this file except in compliance with at least one of * the above three licenses. * * See LICENSE.html or LICENSE.txt at the top of this package for the * complete terms and further detail along with the license texts for * the licenses in COPYING.LIB, COPYING and LICENSE-2.0.txt respectively. * * */ #ifdef HAVE_CONFIG_H #include #endif #ifdef WIN32 #include #endif #include #include #include #include #ifdef HAVE_ERRNO_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_LIMITS_H #include #endif /* Raptor includes */ #include "raptor.h" #include "raptor_internal.h" #ifndef STANDALONE #ifndef RAPTOR_JSON_WRITER_DATATYPES #define RAPTOR_JSON_WRITER_DATATYPES 0 #endif struct raptor_json_writer_s { raptor_world* world; raptor_uri* base_uri; raptor_simple_message_handler error_handler; void *error_data; /* outputting to this iostream */ raptor_iostream *iostr; #if RAPTOR_JSON_WRITER_DATATYPES == 1 raptor_uri* xsd_boolean_uri; raptor_uri* xsd_decimal_uri; raptor_uri* xsd_double_uri; raptor_uri* xsd_integer_uri; #endif /* current indent */ int indent; /* indent step */ int indent_step; }; /** * raptor_new_json_writer: * @world: raptor_world object * @base_uri: Base URI for the writer * @iostr: I/O stream to write to * @error_handler: error handler function * @error_data: error handler data * * INTERNAL - Constructor - Create a new JSON writer writing to a raptor_iostream * * Return value: a new #raptor_json_writer object or NULL on failure **/ raptor_json_writer* raptor_new_json_writer(raptor_world* world, raptor_uri* base_uri, raptor_iostream* iostr, raptor_simple_message_handler error_handler, void *error_data) { raptor_json_writer* json_writer; json_writer=(raptor_json_writer*)RAPTOR_CALLOC(raptor_json_writer, 1, sizeof(raptor_json_writer)+1); if(!json_writer) return NULL; json_writer->world=world; json_writer->error_handler=error_handler; json_writer->error_data=error_data; json_writer->iostr=iostr; json_writer->base_uri=base_uri; #if RAPTOR_JSON_WRITER_DATATYPES == 1 json_writer->xsd_boolean_uri=raptor_new_uri_v2(world, (const unsigned char*)"http://www.w3.org/2001/XMLSchema#boolean"); json_writer->xsd_decimal_uri=raptor_new_uri_v2(world, (const unsigned char*)"http://www.w3.org/2001/XMLSchema#decimal"); json_writer->xsd_double_uri=raptor_new_uri_v2(world, (const unsigned char*)"http://www.w3.org/2001/XMLSchema#double"); json_writer->xsd_integer_uri=raptor_new_uri_v2(world, (const unsigned char*)"http://www.w3.org/2001/XMLSchema#integer"); #endif json_writer->indent_step=2; return json_writer; } /** * raptor_free_json_writer: * @json_writer: JSON writer object * * INTERNAL - Destructor - Free JSON Writer * **/ void raptor_free_json_writer(raptor_json_writer* json_writer) { RAPTOR_ASSERT_OBJECT_POINTER_RETURN(json_writer, raptor_json_writer); #if RAPTOR_JSON_WRITER_DATATYPES == 1 if(json_writer->xsd_boolean_uri) raptor_free_uri_v2(json_writer->world, json_writer->xsd_boolean_uri); if(json_writer->xsd_decimal_uri) raptor_free_uri_v2(json_writer->world, json_writer->xsd_decimal_uri); if(json_writer->xsd_double_uri) raptor_free_uri_v2(json_writer->world, json_writer->xsd_double_uri); if(json_writer->xsd_integer_uri) raptor_free_uri_v2(json_writer->world, json_writer->xsd_integer_uri); #endif RAPTOR_FREE(raptor_json_writer, json_writer); } static int raptor_json_writer_quoted(raptor_json_writer* json_writer, const char *value, size_t value_len) { if(!value) { raptor_iostream_write_counted_string(json_writer->iostr, "\"\"", 2); return 0; } if(!value_len) value_len=strlen((const char*)value); raptor_iostream_write_byte(json_writer->iostr, '\"'); raptor_iostream_write_string_python(json_writer->iostr, (const unsigned char*)value, value_len, '"', 3); raptor_iostream_write_byte(json_writer->iostr, '\"'); return 0; } static int raptor_json_writer_spaces(raptor_json_writer* json_writer, int depth) { int i; for(i=0; iiostr, ' '); return 0; } int raptor_json_writer_newline(raptor_json_writer* json_writer) { raptor_iostream_write_byte(json_writer->iostr, '\n'); if(json_writer->indent) raptor_json_writer_spaces(json_writer, json_writer->indent); return 0; } int raptor_json_writer_key_value(raptor_json_writer* json_writer, const char* key, size_t key_len, const char* value, size_t value_len) { if(!key_len && key) key_len=strlen(key); if(!value_len && value) value_len=strlen(value); raptor_json_writer_quoted(json_writer, key, key_len); raptor_iostream_write_counted_string(json_writer->iostr, " : ", 3); raptor_json_writer_quoted(json_writer, value, value_len); return 0; } int raptor_json_writer_key_uri_value(raptor_json_writer* json_writer, const char* key, size_t key_len, raptor_uri* uri) { const char* value; size_t value_len; int rc=0; value=(const char*)raptor_uri_to_relative_counted_uri_string_v2(json_writer->world, json_writer->base_uri, uri, &value_len); if(!value) return 1; if(key) rc=raptor_json_writer_key_value(json_writer, key, key_len, value, value_len); else rc=raptor_json_writer_quoted(json_writer, value, value_len); RAPTOR_FREE(cstring, value); return 0; } int raptor_json_writer_start_block(raptor_json_writer* json_writer, char c) { json_writer->indent += json_writer->indent_step; raptor_iostream_write_byte(json_writer->iostr, c); return 0; } int raptor_json_writer_end_block(raptor_json_writer* json_writer, char c) { raptor_iostream_write_byte(json_writer->iostr, c); json_writer->indent -= json_writer->indent_step; return 0; } int raptor_json_writer_literal_object(raptor_json_writer* json_writer, unsigned char* s, unsigned char* lang, raptor_uri* datatype, const char* key, const char* type_key) { if(key) { raptor_json_writer_start_block(json_writer, '{'); raptor_json_writer_newline(json_writer); raptor_json_writer_quoted(json_writer, key, 0); raptor_iostream_write_counted_string(json_writer->iostr, " : ", 3); } raptor_json_writer_quoted(json_writer, (const char*)s, 0); if(datatype || lang) { raptor_iostream_write_byte(json_writer->iostr, ','); raptor_json_writer_newline(json_writer); if(datatype) raptor_json_writer_key_uri_value(json_writer, "datatype", 8, datatype); if(lang) { if(datatype) { raptor_iostream_write_byte(json_writer->iostr, ','); raptor_json_writer_newline(json_writer); } raptor_json_writer_key_value(json_writer, "lang", 4, (const char*)lang, 0); } } if(type_key) { raptor_iostream_write_byte(json_writer->iostr, ','); raptor_json_writer_newline(json_writer); raptor_json_writer_key_value(json_writer, type_key, 0, "literal", 0); } raptor_json_writer_newline(json_writer); if(key) { raptor_json_writer_end_block(json_writer, '}'); raptor_json_writer_newline(json_writer); } return 0; } /* not used here */ #if RAPTOR_JSON_WRITER_DATATYPES == 1 int raptor_json_writer_literal_datatype(raptor_json_writer* json_writer, raptor_namespace_stack *nstack, unsigned char* s, unsigned char* lang, raptor_uri* datatype); int raptor_json_writer_literal_datatype(raptor_json_writer* json_writer, raptor_namespace_stack *nstack, unsigned char* s, unsigned char* lang, raptor_uri* datatype) { /* DBL_MAX = 309 decimal digits */ #define INT_MAX_LEN 309 /* DBL_EPSILON = 52 digits */ #define FRAC_MAX_LEN 52 const size_t buflen = INT_MAX_LEN + FRAC_MAX_LEN + 3; /* sign, decimal, \0 */ char buf[buflen]; size_t len = 0; char* endptr = (char *)s; int written = 0; /* typed literal special cases */ if(datatype) { /* integer */ if(raptor_uri_equals_v2(json_writer->world, datatype, json_writer->xsd_integer_uri)) { long inum = strtol((const char*)s, NULL, 10); if(inum != LONG_MIN && inum != LONG_MAX) { raptor_iostream_write_decimal(json_writer->iostr, inum); written = 1; } /* double */ } else if(raptor_uri_equals_v2(json_writer->world, datatype, json_writer->xsd_double_uri)) { double dnum = strtod((const char*)s, &endptr); if(endptr != (char*)s) { const char* decimal = strchr((const char*)s, '.'); const size_t max_digits = (decimal ? (endptr - decimal - 2) : 1); char* num_str; num_str=raptor_format_float(buf, &len, buflen, dnum, 1, max_digits, 0); raptor_iostream_write_counted_string(json_writer->iostr, num_str, len); written = 1; } /* decimal */ } else if(raptor_uri_equals_v2(json_writer->world, datatype, json_writer->xsd_decimal_uri)) { double dnum = strtod((const char*)s, &endptr); if(endptr != (char*)s) { snprintf(buf, 20, "%.1lf", dnum); raptor_iostream_write_string(json_writer->iostr, buf); written = 1; } /* boolean */ } else if(raptor_uri_equals_v2(json_writer->world, datatype, json_writer->xsd_boolean_uri)) { if(!strcmp((const char*)s, "0") || !strcmp((const char*)s, "false")) { raptor_iostream_write_string(json_writer->iostr, "false"); written = 1; } else if(!strcmp((const char*)s, "1") || !strcmp((const char*)s, "true")) { raptor_iostream_write_string(json_writer->iostr, "true"); written = 1; } else { json_writer->error_handler(json_writer->error_data, "Illegal value for xsd:boolean literal."); return 1; } } } if(written) return 0; return raptor_json_writer_literal_object(json_writer, s, lang, datatype, "value", NULL); } #endif int raptor_json_writer_blank_object(raptor_json_writer* json_writer, const char* blank) { raptor_json_writer_start_block(json_writer, '{'); raptor_json_writer_newline(json_writer); raptor_iostream_write_counted_string(json_writer->iostr, "\"value\" : \"_:", 13); raptor_iostream_write_string(json_writer->iostr, blank); raptor_iostream_write_counted_string(json_writer->iostr, "\",", 2); raptor_json_writer_newline(json_writer); raptor_iostream_write_counted_string(json_writer->iostr, "\"type\" : \"bnode\"", 16); raptor_json_writer_newline(json_writer); raptor_json_writer_end_block(json_writer, '}'); return 0; } int raptor_json_writer_uri_object(raptor_json_writer* json_writer, raptor_uri* uri) { raptor_json_writer_start_block(json_writer, '{'); raptor_json_writer_newline(json_writer); raptor_json_writer_key_uri_value(json_writer, "value", 5, uri); raptor_iostream_write_byte(json_writer->iostr, ','); raptor_json_writer_newline(json_writer); raptor_iostream_write_counted_string(json_writer->iostr, "\"type\" : \"uri\"", 14); raptor_json_writer_newline(json_writer); raptor_json_writer_end_block(json_writer, '}'); return 0; } #endif