summaryrefslogtreecommitdiffstats
path: root/src/raptor_serialize_turtle.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/raptor_serialize_turtle.c')
-rw-r--r--src/raptor_serialize_turtle.c1819
1 files changed, 1819 insertions, 0 deletions
diff --git a/src/raptor_serialize_turtle.c b/src/raptor_serialize_turtle.c
new file mode 100644
index 0000000..79fdbbd
--- /dev/null
+++ b/src/raptor_serialize_turtle.c
@@ -0,0 +1,1819 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * raptor_serialize_turtle.c - Turtle serializer
+ *
+ * Copyright (C) 2006,2008 Dave Robillard
+ * Copyright (C) 2004-2013 David Beckett http://www.dajobe.org/
+ * Copyright (C) 2004-2005 University of Bristol, UK http://www.bristol.ac.uk/
+ * Copyright (C) 2005 Steve Shepard steveshep@gmail.com
+ *
+ * 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 <raptor_config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdarg.h>
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+/* Raptor includes */
+#include "raptor2.h"
+#include "raptor_internal.h"
+
+
+#define MAX_ASCII_INT_SIZE 13
+
+
+/*
+ * Raptor turtle serializer object
+ */
+typedef struct {
+ raptor_namespace_stack *nstack; /* Namespace stack */
+ raptor_namespace *rdf_nspace; /* the rdf: namespace */
+ raptor_turtle_writer *turtle_writer; /* where the xml is being written */
+ raptor_sequence *namespaces; /* User declared namespaces */
+ raptor_avltree *subjects; /* subject items */
+ raptor_avltree *blanks; /* blank subject items */
+ raptor_avltree *nodes; /* nodes */
+ raptor_abbrev_node *rdf_type; /* rdf:type uri */
+
+ /* URI of rdf:XMLLiteral */
+ raptor_uri* rdf_xml_literal_uri;
+
+ /* URI of rdf:first */
+ raptor_uri* rdf_first_uri;
+
+ /* URI of rdf:rest */
+ raptor_uri* rdf_rest_uri;
+
+ /* URI of rdf:nil */
+ raptor_uri* rdf_nil_uri;
+
+ /* URI of rs:ResultSet */
+ raptor_uri* rs_ResultSet_uri;
+
+ /* URI of rs:resultVariable */
+ raptor_uri* rs_resultVariable_uri;
+
+ /* Non 0 for rs:ResultSet */
+ int resultset;
+
+ /* Non 0 for mKR serializer */
+ int emit_mkr;
+ /* Flags for turtle writer */
+ int turtle_writer_flags;
+
+ /* Non 0 if "begin relation result ;" has been written */
+ int written_begin;
+
+ /* non zero if header is finished being written
+ * (and thus no new namespaces can be declared).
+ */
+ int written_header;
+
+ /* for labeling namespaces */
+ int namespace_count;
+
+ /* state for raptor_mkr_emit_subject_resultset() */
+ int mkr_rs_size;
+ int mkr_rs_arity;
+ int mkr_rs_ntuple;
+ int mkr_rs_nvalue;
+ int mkr_rs_processing_value;
+} raptor_turtle_context;
+
+
+/* prototypes for functions */
+
+static int raptor_turtle_emit_resource(raptor_serializer *serializer,
+ raptor_abbrev_node* node,
+ int depth);
+
+static int raptor_turtle_emit_literal(raptor_serializer *serializer,
+ raptor_abbrev_node* node,
+ int depth);
+static int raptor_turtle_emit_blank(raptor_serializer *serializer,
+ raptor_abbrev_node* node,
+ int depth);
+static int raptor_turtle_emit_subject_list_items(raptor_serializer* serializer,
+ raptor_abbrev_subject* subject,
+ int depth);
+static int raptor_turtle_emit_subject_collection_items(raptor_serializer* serializer,
+ raptor_abbrev_subject* subject,
+ int depth);
+static int raptor_turtle_emit_subject_properties(raptor_serializer *serializer,
+ raptor_abbrev_subject* subject,
+ int depth);
+static int raptor_mkr_emit_subject_resultset(raptor_serializer* serializer,
+ raptor_abbrev_subject* subject,
+ int depth);
+static int raptor_turtle_emit_subject(raptor_serializer *serializer,
+ raptor_abbrev_subject* subject,
+ int depth);
+static int raptor_turtle_emit(raptor_serializer *serializer);
+
+static int raptor_turtle_serialize_init(raptor_serializer* serializer,
+ const char *name);
+static void raptor_turtle_serialize_terminate(raptor_serializer* serializer);
+static int raptor_turtle_serialize_declare_namespace(raptor_serializer* serializer,
+ raptor_uri *uri,
+ const unsigned char *prefix);
+static int raptor_turtle_serialize_start(raptor_serializer* serializer);
+static int raptor_turtle_serialize_statement(raptor_serializer* serializer,
+ raptor_statement *statement);
+
+static int raptor_turtle_serialize_end(raptor_serializer* serializer);
+static int raptor_turtle_serialize_flush(raptor_serializer* serializer);
+static void raptor_turtle_serialize_finish_factory(raptor_serializer_factory* factory);
+
+
+int
+raptor_turtle_is_legal_turtle_qname(raptor_qname* qname)
+{
+ const char* prefix_name;
+ const char* local_name;
+
+ if(!qname)
+ return 0;
+
+ prefix_name = qname->nspace ? (const char*)qname->nspace->prefix : NULL;
+ if(prefix_name) {
+ /* prefixName: must have leading [A-Z][a-z][0-9] (nameStartChar - '_') */
+ /* prefixName: no . anywhere */
+ if(!(isalpha((int)*prefix_name) || isdigit((int)*prefix_name)) ||
+ strchr(prefix_name, '.'))
+ return 0;
+ }
+
+ local_name = (const char*)qname->local_name;
+ if(local_name) {
+ /* nameStartChar: must have leading [A-Z][a-z][0-9]_ */
+ /* nameChar: no . anywhere */
+ if(!(isalpha((int)*local_name) || isdigit((int)*local_name) || *local_name == '_') ||
+ strchr(local_name, '.'))
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * raptor_turtle_emit_resource:
+ * @serializer: #raptor_serializer object
+ * @node: resource node
+ * @depth: depth into tree
+ *
+ * Emit a description of a resource using an XML Element
+ *
+ * Return value: non-0 on failure
+ **/
+static int
+raptor_turtle_emit_resource(raptor_serializer *serializer,
+ raptor_abbrev_node* node,
+ int depth)
+{
+ raptor_turtle_context* context = (raptor_turtle_context*)serializer->context;
+ int emit_mkr = context->emit_mkr;
+ raptor_turtle_writer *turtle_writer = context->turtle_writer;
+
+ raptor_qname* qname = NULL;
+
+ RAPTOR_DEBUG_ABBREV_NODE("Emitting resource node", node);
+
+ if(node->term->type != RAPTOR_TERM_TYPE_URI)
+ return 1;
+
+ if(raptor_uri_equals(node->term->value.uri, context->rdf_nil_uri)) {
+ if(emit_mkr)
+ raptor_turtle_writer_raw_counted(turtle_writer, (const unsigned char*)" ", 1);
+ else
+ raptor_turtle_writer_raw_counted(turtle_writer, (const unsigned char*)"( )", 3);
+ return 0;
+ }
+
+ qname = raptor_new_qname_from_namespace_uri(context->nstack,
+ node->term->value.uri, 10);
+
+ /* XML Names allow leading '_' and '.' anywhere but Turtle does not */
+ if(qname && !raptor_turtle_is_legal_turtle_qname(qname)) {
+ raptor_free_qname(qname);
+ qname = NULL;
+ }
+
+ if(raptor_uri_equals(node->term->value.uri, context->rdf_nil_uri)) {
+ if(emit_mkr)
+ raptor_turtle_writer_raw_counted(turtle_writer, (const unsigned char*)" ", 1);
+ else
+ raptor_turtle_writer_raw_counted(turtle_writer ,(const unsigned char*)"( )", 3);
+ return 0;
+ }
+
+ if(qname) {
+ raptor_turtle_writer_qname(turtle_writer, qname);
+ raptor_free_qname(qname);
+ } else {
+ raptor_turtle_writer_reference(turtle_writer, node->term->value.uri);
+ }
+
+ RAPTOR_DEBUG_ABBREV_NODE("Emitted", node);
+
+ return 0;
+}
+
+
+/*
+ * raptor_turtle_emit_literal:
+ * @serializer: #raptor_serializer object
+ * @node: literal node
+ * @depth: depth into tree
+ *
+ * Emit a description of a literal (object).
+ *
+ * Return value: non-0 on failure
+ **/
+static int
+raptor_turtle_emit_literal(raptor_serializer *serializer,
+ raptor_abbrev_node* node,
+ int depth)
+{
+ raptor_turtle_context* context = (raptor_turtle_context*)serializer->context;
+ raptor_turtle_writer *turtle_writer = context->turtle_writer;
+ int rc = 0;
+
+ RAPTOR_DEBUG_ABBREV_NODE("Emitting literal node", node);
+
+ if(node->term->type != RAPTOR_TERM_TYPE_LITERAL)
+ return 1;
+
+ rc = raptor_turtle_writer_literal(turtle_writer, context->nstack,
+ node->term->value.literal.string,
+ node->term->value.literal.language,
+ node->term->value.literal.datatype);
+
+ RAPTOR_DEBUG_ABBREV_NODE("Emitted literal node", node);
+
+ return rc;
+}
+
+
+/*
+ * raptor_turtle_emit_blank:
+ * @serializer: #raptor_serializer object
+ * @node: blank node
+ * @depth: depth into tree
+ *
+ * Emit a description of a blank node
+ *
+ * Return value: non-0 on failure
+ **/
+static int
+raptor_turtle_emit_blank(raptor_serializer *serializer,
+ raptor_abbrev_node* node,
+ int depth)
+{
+ raptor_turtle_context* context = (raptor_turtle_context*)serializer->context;
+ raptor_turtle_writer* turtle_writer = context->turtle_writer;
+ int emit_mkr = context->emit_mkr;
+ int rc = 0;
+
+ RAPTOR_DEBUG_ABBREV_NODE("Emitting blank node", node);
+
+ if(node->term->type != RAPTOR_TERM_TYPE_BLANK)
+ return 1;
+
+ if((node->count_as_subject == 1 && node->count_as_object == 1)) {
+ /* If this is only used as a 1 subject and object or never
+ * used as a subject or never used as an object, it never need
+ * be referenced with an explicit name */
+ raptor_abbrev_subject* blank;
+
+ blank = raptor_abbrev_subject_find(context->blanks, node->term);
+ if(blank) {
+ rc = raptor_turtle_emit_subject(serializer, blank, depth+1);
+ raptor_abbrev_subject_invalidate(blank);
+ }
+
+ } else {
+ /* Blank node that needs an explicit name */
+ raptor_turtle_writer_bnodeid(context->turtle_writer,
+ node->term->value.blank.string,
+ node->term->value.blank.string_len);
+ if(emit_mkr && !context->resultset)
+ raptor_turtle_writer_raw_counted(turtle_writer, (const unsigned char*)" has", 4);
+ }
+
+ RAPTOR_DEBUG_ABBREV_NODE("Emitted blank node", node);
+
+ return rc;
+}
+
+
+/*
+ * raptor_turtle_emit_subject_list_items:
+ * @serializer: #raptor_serializer object
+ * @subject: subject node
+ * @depth: depth into tree
+ *
+ * Emit an rdf list of items (rdf:li) about a subject node.
+ *
+ * Return value: non-0 on failure
+ **/
+static int
+raptor_turtle_emit_subject_list_items(raptor_serializer* serializer,
+ raptor_abbrev_subject* subject,
+ int depth)
+{
+ int rv = 0;
+ int i = 0;
+
+ RAPTOR_DEBUG_ABBREV_NODE("Emitting subject list items", subject->node);
+
+ while(!rv && i < raptor_sequence_size(subject->list_items)) {
+ raptor_abbrev_node* object;
+
+ object = (raptor_abbrev_node*)raptor_sequence_get_at(subject->list_items,
+ i++);
+ if(!object)
+ continue;
+
+ switch(object->term->type) {
+ case RAPTOR_TERM_TYPE_URI:
+ rv = raptor_turtle_emit_resource(serializer, object, depth+1);
+ break;
+
+ case RAPTOR_TERM_TYPE_LITERAL:
+ rv = raptor_turtle_emit_literal(serializer, object, depth+1);
+ break;
+
+ case RAPTOR_TERM_TYPE_BLANK:
+ rv = raptor_turtle_emit_blank(serializer, object, depth+1);
+ break;
+
+ case RAPTOR_TERM_TYPE_UNKNOWN:
+ default:
+ raptor_log_error_formatted(serializer->world, RAPTOR_LOG_LEVEL_ERROR,
+ NULL, "Triple has unsupported term type %u",
+ object->term->type);
+ break;
+
+ }
+
+ }
+
+ return rv;
+}
+
+
+/*
+ * raptor_turtle_emit_subject_collection_items:
+ * @serializer: #raptor_serializer object
+ * @subject: subject node
+ * @depth: depth into tree
+ *
+ * Emit an abbreviated rdf collection of items (rdf:first, rdf:rest) about a subject node.
+ *
+ * Return value: non-0 on failure
+ **/
+static int
+raptor_turtle_emit_subject_collection_items(raptor_serializer* serializer,
+ raptor_abbrev_subject* subject,
+ int depth)
+{
+ raptor_turtle_context* context = (raptor_turtle_context*)serializer->context;
+ int emit_mkr = context->emit_mkr;
+ int rv = 0;
+ raptor_avltree_iterator* iter = NULL;
+ int i;
+ int is_new_subject = 0;
+
+ RAPTOR_DEBUG_ABBREV_NODE("Emitting subject collection items", subject->node);
+
+ /* if just saw a new subject (is_new_subject is true) then there is no need
+ * to advance the iterator - it was just reset
+ */
+ for(i = 0, (iter = raptor_new_avltree_iterator(subject->properties, NULL, NULL, 1));
+ iter && !rv;
+ i++, (rv = is_new_subject ? 0 : raptor_avltree_iterator_next(iter))) {
+ raptor_abbrev_node** nodes;
+ raptor_abbrev_node* predicate;
+ raptor_abbrev_node* object;
+
+ is_new_subject = 0;
+
+ nodes = (raptor_abbrev_node**)raptor_avltree_iterator_get(iter);
+ if(!nodes)
+ break;
+ predicate = nodes[0];
+ object = nodes[1];
+
+ if(!raptor_uri_equals(predicate->term->value.uri,
+ context->rdf_first_uri)) {
+ raptor_log_error(serializer->world, RAPTOR_LOG_LEVEL_ERROR, NULL,
+ "Malformed collection - first predicate is not rdf:first");
+ raptor_free_avltree_iterator(iter);
+ return 1;
+ }
+
+ if(!object)
+ continue;
+
+ if(i > 0) {
+ if(emit_mkr)
+ raptor_turtle_writer_raw_counted(context->turtle_writer,
+ (const unsigned char*)", ", 1);
+ else
+ raptor_turtle_writer_newline(context->turtle_writer);
+ }
+
+ switch(object->term->type) {
+ case RAPTOR_TERM_TYPE_URI:
+ rv = raptor_turtle_emit_resource(serializer, object, depth+1);
+ break;
+
+ case RAPTOR_TERM_TYPE_LITERAL:
+ rv = raptor_turtle_emit_literal(serializer, object, depth+1);
+ break;
+
+ case RAPTOR_TERM_TYPE_BLANK:
+ rv = raptor_turtle_emit_blank(serializer, object, depth+1);
+ break;
+
+ case RAPTOR_TERM_TYPE_UNKNOWN:
+ default:
+ raptor_log_error_formatted(serializer->world, RAPTOR_LOG_LEVEL_ERROR,
+ NULL, "Triple has unsupported term type %u",
+ object->term->type);
+ break;
+ }
+
+ /* Return error if emitting something failed above */
+ if(rv) {
+ raptor_free_avltree_iterator(iter);
+ return rv;
+ }
+
+ /* last item */
+ rv = raptor_avltree_iterator_next(iter);
+ if(rv)
+ break;
+
+ nodes = (raptor_abbrev_node**)raptor_avltree_iterator_get(iter);
+ predicate = nodes[0];
+ object = nodes[1];
+
+ if(!raptor_uri_equals(predicate->term->value.uri, context->rdf_rest_uri)) {
+ raptor_log_error(serializer->world, RAPTOR_LOG_LEVEL_ERROR, NULL,
+ "Malformed collection - second predicate is not rdf:rest");
+ raptor_free_avltree_iterator(iter);
+ return 1;
+ }
+
+ if(object->term->type == RAPTOR_TERM_TYPE_BLANK) {
+ subject = raptor_abbrev_subject_find(context->blanks, object->term);
+
+ if(!subject) {
+ raptor_log_error(serializer->world, RAPTOR_LOG_LEVEL_ERROR, NULL,
+ "Malformed collection - could not find subject for rdf:rest");
+ raptor_free_avltree_iterator(iter);
+ return 1;
+ }
+
+ /* got a <(old)subject> rdf:rest <(new)subject> triple so know
+ * subject has changed and should reset the properties iterator
+ */
+ if(iter)
+ raptor_free_avltree_iterator(iter);
+ iter = raptor_new_avltree_iterator(subject->properties, NULL, NULL, 1);
+ is_new_subject = 1;
+
+ } else {
+ if(object->term->type != RAPTOR_TERM_TYPE_URI ||
+ !raptor_uri_equals(object->term->value.uri, context->rdf_nil_uri)) {
+ raptor_log_error(serializer->world, RAPTOR_LOG_LEVEL_ERROR, NULL,
+ "Malformed collection - last rdf:rest resource is not rdf:nil");
+ raptor_free_avltree_iterator(iter);
+ return 1;
+ }
+ break;
+ }
+ }
+ if(iter)
+ raptor_free_avltree_iterator(iter);
+
+ return rv;
+}
+
+
+
+/*
+ * raptor_turtle_emit_subject_properties:
+ * @serializer: #raptor_serializer object
+ * @subject: subject node
+ * @depth: depth into tree
+ *
+ * Emit the properties about a subject node.
+ *
+ * Return value: non-0 on failure
+ **/
+static int
+raptor_turtle_emit_subject_properties(raptor_serializer* serializer,
+ raptor_abbrev_subject* subject,
+ int depth)
+{
+ raptor_turtle_context* context = (raptor_turtle_context*)serializer->context;
+ raptor_turtle_writer *turtle_writer = context->turtle_writer;
+ int emit_mkr = context->emit_mkr;
+ int numobj = 2; /* "[" "]" around all object lists (any size) */
+ raptor_abbrev_node* last_predicate = NULL;
+ int rv = 0;
+ raptor_avltree_iterator* iter = NULL;
+
+ RAPTOR_DEBUG_ABBREV_NODE("Emitting subject properties", subject->node);
+
+ /* Emit any rdf:_n properties collected */
+ if(raptor_sequence_size(subject->list_items) > 0)
+ rv = raptor_turtle_emit_subject_list_items(serializer, subject, depth+1);
+
+ for((iter = raptor_new_avltree_iterator(subject->properties, NULL, NULL, 1));
+ iter && !rv;
+ (rv = raptor_avltree_iterator_next(iter))) {
+ raptor_abbrev_node** nodes;
+ raptor_abbrev_node* predicate;
+ raptor_abbrev_node* object;
+ raptor_qname *qname;
+
+ nodes = (raptor_abbrev_node**)raptor_avltree_iterator_get(iter);
+ if(!nodes)
+ break;
+ predicate = nodes[0];
+ object = nodes[1];
+ numobj = 2; /* = raptor_sequence_size(xxx) if available */
+
+ if(!last_predicate ||
+ !raptor_abbrev_node_equals(predicate, last_predicate)) {
+ /* no object list abbreviation possible, terminate last object */
+ if(last_predicate) {
+ if(emit_mkr && !context->resultset) {
+ if(numobj > 1)
+ raptor_turtle_writer_raw_counted(turtle_writer, (const unsigned char*)"]", 1);
+ raptor_turtle_writer_raw_counted(turtle_writer, (const unsigned char*)", ", 2);
+ } else {
+ raptor_turtle_writer_raw_counted(turtle_writer, (const unsigned char*)" ;", 2);
+ }
+ raptor_turtle_writer_newline(turtle_writer);
+ }
+
+ qname = raptor_new_qname_from_namespace_uri(context->nstack,
+ predicate->term->value.uri,
+ 10);
+
+ if(raptor_abbrev_node_equals(predicate, context->rdf_type)) {
+ if(emit_mkr)
+ raptor_turtle_writer_raw_counted(turtle_writer, (const unsigned char*)"rdf:type", 8);
+ else
+ raptor_turtle_writer_raw_counted(turtle_writer, (const unsigned char*)"a", 1);
+ } else if(qname) {
+ raptor_turtle_writer_qname(turtle_writer, qname);
+ } else {
+ raptor_turtle_writer_reference(turtle_writer, predicate->term->value.uri);
+ }
+ if(emit_mkr) {
+ raptor_turtle_writer_raw_counted(turtle_writer, (const unsigned char*)" = ", 3);
+ if(numobj > 1)
+ raptor_turtle_writer_raw_counted(turtle_writer, (const unsigned char*)"[", 1);
+ } else {
+ raptor_turtle_writer_raw_counted(turtle_writer, (const unsigned char*)" ", 1);
+ }
+
+
+ if(qname)
+ raptor_free_qname(qname);
+ } else { /* not last object for this predicate */
+ raptor_turtle_writer_raw_counted(turtle_writer, (const unsigned char*)", ", 2);
+ }
+
+
+ switch(object->term->type) {
+ case RAPTOR_TERM_TYPE_URI:
+ rv = raptor_turtle_emit_resource(serializer, object, depth+1);
+ break;
+
+ case RAPTOR_TERM_TYPE_LITERAL:
+ rv = raptor_turtle_emit_literal(serializer, object, depth+1);
+ break;
+
+ case RAPTOR_TERM_TYPE_BLANK:
+ rv = raptor_turtle_emit_blank(serializer, object, depth+1);
+ break;
+
+ case RAPTOR_TERM_TYPE_UNKNOWN:
+ default:
+ raptor_log_error_formatted(serializer->world, RAPTOR_LOG_LEVEL_ERROR,
+ NULL, "Triple has unsupported term type %u",
+ object->term->type);
+ break;
+ }
+
+ /* Return error if emitting something failed above */
+ if(rv)
+ return rv;
+
+ last_predicate = predicate;
+ }
+
+ if(iter)
+ raptor_free_avltree_iterator(iter);
+
+ return rv;
+}
+
+
+
+/*
+ * raptor_mkr_emit_subject_resultset:
+ * @serializer: #raptor_serializer object
+ * @subject: subject node
+ * @depth: depth into tree
+ *
+ * Emit rs:ResultSet as CSV relation.
+ *
+ * Return value: non-0 on failure
+ **/
+static int
+raptor_mkr_emit_subject_resultset(raptor_serializer* serializer,
+ raptor_abbrev_subject* subject,
+ int depth)
+{
+ raptor_turtle_context* context = (raptor_turtle_context*)serializer->context;
+ raptor_turtle_writer *turtle_writer = context->turtle_writer;
+ raptor_abbrev_node* last_predicate = NULL;
+ int rv = 0;
+ raptor_avltree_iterator* iter = NULL;
+ int skip_object;
+
+
+ RAPTOR_DEBUG_ABBREV_NODE("Emitting subject resultset", subject->node);
+
+ /* Emit any rdf:_n properties collected */
+ if(raptor_sequence_size(subject->list_items) > 0)
+ rv = raptor_turtle_emit_subject_list_items(serializer, subject, depth+1);
+
+
+ for((iter = raptor_new_avltree_iterator(subject->properties, NULL, NULL, 1));
+ iter && !rv;
+ (rv = raptor_avltree_iterator_next(iter))) {
+ raptor_abbrev_node** nodes;
+ raptor_abbrev_node* predicate;
+ raptor_abbrev_node* object;
+ raptor_qname *qname;
+
+ nodes = (raptor_abbrev_node**)raptor_avltree_iterator_get(iter);
+ if(!nodes)
+ break;
+
+ predicate = nodes[0];
+ object = nodes[1];
+
+ if(!last_predicate ||
+ !raptor_abbrev_node_equals(predicate, last_predicate)) {
+ /* first predicate or same predicate as last time */
+
+ /* no object list abbreviation possible, terminate last object */
+ if(last_predicate) {
+ if(!context->mkr_rs_arity) {
+ /* last variable in first row */
+ raptor_turtle_writer_raw_counted(turtle_writer, (const unsigned char*)" ;", 2);
+ raptor_turtle_writer_newline(turtle_writer);
+ context->mkr_rs_ntuple++; /* start count after variables */
+ } else if(!context->mkr_rs_nvalue) {
+ /* size not emitted */
+ } else if(context->mkr_rs_processing_value &&
+ (context->mkr_rs_nvalue == context->mkr_rs_arity)) {
+ /* previous value was last value of row */
+ context->mkr_rs_processing_value = 0;
+ raptor_turtle_writer_raw_counted(turtle_writer, (const unsigned char*)" ;", 2);
+ raptor_turtle_writer_newline(turtle_writer);
+ context->mkr_rs_nvalue = 0;
+ context->mkr_rs_ntuple++;
+ if(context->mkr_rs_ntuple > context->mkr_rs_size) {
+ /* previous row was last row of table */
+ raptor_turtle_writer_raw_counted(turtle_writer, (const unsigned char*)"end relation result ;", 21);
+ raptor_turtle_writer_newline(turtle_writer);
+ break;
+ }
+ }
+ }
+
+ qname = raptor_new_qname_from_namespace_uri(context->nstack,
+ predicate->term->value.uri,
+ 10);
+ if(raptor_abbrev_node_equals(predicate, context->rdf_type)) {
+ skip_object = 1; /* all values have been written */
+ } else if(qname) {
+ /* check predicate name */
+ if(!strcmp((const char*)qname->local_name, (const char*)"resultVariable")) {
+ /* emit mKR relation header */
+ raptor_turtle_writer_raw_counted(turtle_writer, (const unsigned char*)"result is relation with format = csv ;", 38);
+ raptor_turtle_writer_newline(turtle_writer);
+ raptor_turtle_writer_raw_counted(turtle_writer, (const unsigned char*)"begin relation result ;", 23);
+ raptor_turtle_writer_decrease_indent(turtle_writer);
+ raptor_turtle_writer_newline(turtle_writer);
+ skip_object = 0;
+
+ } else if(!strcmp((const char*)qname->local_name, (const char*)"size")) {
+ context->mkr_rs_arity = context->mkr_rs_nvalue;
+ context->mkr_rs_nvalue = 0;
+ skip_object = 0;
+ } else if(!strcmp((const char*)qname->local_name, (const char*)"solution")) {
+ skip_object = 0; /* get values */
+ } else if(!strcmp((const char*)qname->local_name, (const char*)"binding")) {
+ skip_object = 0; /* get values */
+ } else if(!strcmp((const char*)qname->local_name, (const char*)"variable")) {
+ skip_object = 1;
+ } else if(!strcmp((const char*)qname->local_name, (const char*)"value")) {
+ context->mkr_rs_processing_value = 1;
+ context->mkr_rs_nvalue++;
+ skip_object = 0;
+ } else {
+ skip_object = 1;
+ }
+
+ } else {
+ /* not qname */
+ raptor_turtle_writer_reference(turtle_writer, predicate->term->value.uri);
+ skip_object = 0;
+ } /* end predicate */
+
+ if(qname)
+ raptor_free_qname(qname);
+ } else { /* predicate was skipped */
+ if(!context->mkr_rs_arity)
+ /* not last variable */
+ raptor_turtle_writer_raw_counted(turtle_writer, (const unsigned char*)", ", 2);
+ }
+
+ if(!skip_object) {
+ /* do not skip object */
+ switch(object->term->type) {
+ case RAPTOR_TERM_TYPE_URI:
+ rv = raptor_turtle_emit_resource(serializer, object, depth+1);
+ break;
+
+ case RAPTOR_TERM_TYPE_LITERAL:
+ if(!context->mkr_rs_arity) {
+ /* variables */
+ context->mkr_rs_nvalue++;
+ raptor_turtle_writer_csv_string(turtle_writer, object->term->value.literal.string);
+ } else if(!context->mkr_rs_nvalue) {
+ /* size */
+ context->mkr_rs_size = atoi((const char*)object->term->value.literal.string);
+ } else {
+ /* values */
+ raptor_turtle_writer_csv_string(turtle_writer, object->term->value.literal.string);
+ if(context->mkr_rs_nvalue < context->mkr_rs_arity)
+ /* not last value */
+ raptor_turtle_writer_raw_counted(turtle_writer, (const unsigned char*)", ", 2);
+ }
+ break;
+
+ case RAPTOR_TERM_TYPE_BLANK:
+ rv = raptor_turtle_emit_blank(serializer, object, depth+1);
+ break;
+
+ case RAPTOR_TERM_TYPE_UNKNOWN:
+ default:
+ raptor_log_error_formatted(serializer->world, RAPTOR_LOG_LEVEL_ERROR,
+ NULL, "Triple has unsupported term type %u",
+ object->term->type);
+ break;
+ }
+ } /* end object */
+
+ /* Return error if emitting something failed above */
+ if(rv)
+ return rv;
+
+ last_predicate = predicate;
+ } /* end iteration i */
+
+ if(iter)
+ raptor_free_avltree_iterator(iter);
+
+ return rv;
+}
+
+/*
+ * raptor_turtle_emit_subject:
+ * @serializer: #raptor_serializer object
+ * @subject: subject node
+ * @depth: depth into tree
+ *
+ * Emit a subject node
+ *
+ * Return value: non-0 on failure
+ **/
+static int
+raptor_turtle_emit_subject(raptor_serializer *serializer,
+ raptor_abbrev_subject* subject,
+ int depth)
+{
+ raptor_turtle_context* context = (raptor_turtle_context*)serializer->context;
+ raptor_turtle_writer* turtle_writer = context->turtle_writer;
+ int emit_mkr = context->emit_mkr;
+ int numobj = 2;
+ int blank = 1;
+ int collection = 0;
+ int rc = 0;
+
+ if(!raptor_abbrev_subject_valid(subject)) return 0;
+
+ RAPTOR_DEBUG_ABBREV_NODE("Emitting subject node", subject->node);
+
+ if(!depth &&
+ subject->node->term->type == RAPTOR_TERM_TYPE_BLANK &&
+ subject->node->count_as_subject == 1 &&
+ subject->node->count_as_object == 1) {
+ RAPTOR_DEBUG_ABBREV_NODE("Skipping subject node - subj & obj count 1", subject->node);
+ return 0;
+ }
+
+ if(raptor_avltree_size(subject->properties) == 0) {
+ RAPTOR_DEBUG_ABBREV_NODE("Skipping subject node - no props", subject->node);
+ return 0;
+ }
+
+ /* check if we can do collection abbreviation */
+ if(raptor_avltree_size(subject->properties) >= 2) {
+ raptor_avltree_iterator* iter = NULL;
+ raptor_abbrev_node* pred1;
+ raptor_abbrev_node* pred2;
+
+ iter = raptor_new_avltree_iterator(subject->properties, NULL, NULL, 1);
+ if(!iter)
+ return 1;
+ pred1 = ((raptor_abbrev_node**)raptor_avltree_iterator_get(iter))[0];
+ if(raptor_avltree_iterator_next(iter)) {
+ raptor_free_avltree_iterator(iter);
+ return 1;
+ }
+ pred2 = ((raptor_abbrev_node**)raptor_avltree_iterator_get(iter))[0];
+ raptor_free_avltree_iterator(iter);
+
+ if(pred1->term->type == RAPTOR_TERM_TYPE_URI &&
+ pred2->term->type == RAPTOR_TERM_TYPE_URI &&
+ (
+ (raptor_uri_equals(pred1->term->value.uri, context->rdf_first_uri) &&
+ raptor_uri_equals(pred2->term->value.uri, context->rdf_rest_uri))
+ ||
+ (raptor_uri_equals(pred2->term->value.uri, context->rdf_first_uri) &&
+ raptor_uri_equals(pred1->term->value.uri, context->rdf_rest_uri))
+ )
+ ) {
+ collection = 1;
+ /* check for rs:ResultSet */
+ } else if(pred1->term->type == RAPTOR_TERM_TYPE_URI &&
+ raptor_uri_equals(pred1->term->value.uri, context->rs_resultVariable_uri)) {
+ context->resultset = 1;
+ }
+ }
+
+ /* emit the subject node */
+ if(subject->node->term->type == RAPTOR_TERM_TYPE_URI) {
+ if(emit_mkr) {
+ if(context->resultset && !context->written_begin) {
+ raptor_turtle_writer_raw_counted(turtle_writer, (const unsigned char*)"result is ", 10);
+ rc = raptor_turtle_emit_resource(serializer, subject->node, depth+1);
+ raptor_turtle_writer_raw_counted(turtle_writer, (const unsigned char*)" ;", 2);
+ raptor_turtle_writer_decrease_indent(turtle_writer);
+ raptor_turtle_writer_newline(turtle_writer);
+ } else {
+ rc = raptor_turtle_emit_resource(serializer, subject->node, depth+1);
+ raptor_turtle_writer_raw_counted(turtle_writer, (const unsigned char*)" has", 4);
+ }
+ } else {
+ rc = raptor_turtle_emit_resource(serializer, subject->node, depth+1);
+ }
+ if(rc)
+ return rc;
+ blank = 0;
+ collection = 0;
+
+ } else if(subject->node->term->type == RAPTOR_TERM_TYPE_BLANK) {
+ if((subject->node->count_as_subject == 1 &&
+ subject->node->count_as_object == 0) && depth > 1) {
+ blank = 1;
+ } else if(subject->node->count_as_object == 0) {
+ if(emit_mkr)
+ raptor_turtle_writer_raw_counted(turtle_writer, (const unsigned char*)"{}", 2);
+ else
+ raptor_turtle_writer_raw_counted(turtle_writer, (const unsigned char*)"[]", 2);
+ blank = 0;
+ } else if(!collection && subject->node->count_as_object > 1) {
+ /* Referred to (used as an object), so needs a nodeID */
+ if(emit_mkr) {
+ if(!context->resultset) {
+ raptor_turtle_writer_bnodeid(turtle_writer,
+ subject->node->term->value.blank.string,
+ subject->node->term->value.blank.string_len);
+ raptor_turtle_writer_raw_counted(turtle_writer, (const unsigned char*)" has", 4);
+ }
+ } else {
+ raptor_turtle_writer_bnodeid(turtle_writer,
+ subject->node->term->value.blank.string,
+ subject->node->term->value.blank.string_len);
+ }
+ }
+ }
+
+ if(collection) {
+ if(!emit_mkr)
+ raptor_turtle_writer_raw_counted(turtle_writer, (const unsigned char*)"(", 1);
+ raptor_turtle_writer_increase_indent(turtle_writer);
+
+ rc = raptor_turtle_emit_subject_collection_items(serializer, subject, depth+1);
+
+ raptor_turtle_writer_decrease_indent(turtle_writer);
+
+ if(!emit_mkr) {
+ raptor_turtle_writer_newline(turtle_writer);
+ raptor_turtle_writer_raw_counted(turtle_writer, (const unsigned char*)")", 1);
+ }
+
+ } else {
+ if(emit_mkr) {
+ if(context->resultset) {
+ /* mKR relation with format = csv */
+ if(blank && depth > 1) {
+ /* skip */
+ }
+
+ raptor_mkr_emit_subject_resultset(serializer, subject, depth+1);
+
+ raptor_turtle_writer_decrease_indent(turtle_writer);
+
+ if(blank && depth > 1) {
+ /* skip */
+ }
+ } else {
+ /* mKR not relation */
+ if(blank && depth > 1) {
+ raptor_turtle_writer_raw_counted(turtle_writer, (const unsigned char*)"{ ", 2);
+ raptor_turtle_writer_newline(turtle_writer);
+ raptor_turtle_writer_bnodeid(turtle_writer,
+ subject->node->term->value.blank.string,
+ subject->node->term->value.blank.string_len);
+ raptor_turtle_writer_raw_counted(turtle_writer, (const unsigned char*)" has", 4);
+ }
+ raptor_turtle_writer_increase_indent(turtle_writer);
+ raptor_turtle_writer_newline(turtle_writer);
+
+ raptor_turtle_emit_subject_properties(serializer, subject, depth+1);
+
+ raptor_turtle_writer_decrease_indent(turtle_writer);
+
+ if(blank && depth > 1) {
+ if(numobj > 1)
+ raptor_turtle_writer_raw_counted(turtle_writer, (const unsigned char*)"]", 1);
+ raptor_turtle_writer_newline(turtle_writer);
+ raptor_turtle_writer_raw_counted(turtle_writer, (const unsigned char*)";}", 2);
+ }
+ }
+ } else {
+ /* Turtle */
+ if(blank && depth > 1)
+ raptor_turtle_writer_raw_counted(turtle_writer, (const unsigned char*)"[", 1);
+
+ raptor_turtle_writer_increase_indent(turtle_writer);
+ raptor_turtle_writer_newline(turtle_writer);
+
+ raptor_turtle_emit_subject_properties(serializer, subject, depth+1);
+
+ raptor_turtle_writer_decrease_indent(turtle_writer);
+
+ if(blank && depth > 1) {
+ raptor_turtle_writer_newline(turtle_writer);
+ raptor_turtle_writer_raw_counted(turtle_writer, (const unsigned char*)"]", 1);
+ }
+ }
+ }
+
+ if(depth == 0) {
+ /* NOTE: the space before the . here MUST be there or statements
+ * that end in a numeric literal will be interpreted incorrectly
+ * (the "." will be parsed as part of the literal and statement
+ * left unterminated)
+ */
+ if(emit_mkr) {
+ if(!context->resultset) {
+ if(numobj > 1)
+ raptor_turtle_writer_raw_counted(turtle_writer, (const unsigned char*)"]", 1);
+ raptor_turtle_writer_raw_counted(turtle_writer, (const unsigned char*)" ;", 2);
+ raptor_turtle_writer_newline(turtle_writer);
+ raptor_turtle_writer_newline(turtle_writer);
+ }
+ context->resultset = 0;
+ context->written_begin = 0;
+ } else {
+ raptor_turtle_writer_raw_counted(turtle_writer, (const unsigned char*)" .", 2);
+ raptor_turtle_writer_newline(turtle_writer);
+ raptor_turtle_writer_newline(turtle_writer);
+ }
+ }
+
+ return rc;
+}
+
+
+/*
+ * raptor_turtle_emit:
+ * @serializer: #raptor_serializer object
+ *
+ * Emit Turtle for all stored triples.
+ *
+ * Return value: non-0 on failure
+ **/
+static int
+raptor_turtle_emit(raptor_serializer *serializer)
+{
+ raptor_turtle_context* context = (raptor_turtle_context*)serializer->context;
+ raptor_abbrev_subject* subject;
+ raptor_abbrev_subject* blank;
+ int rc;
+ raptor_avltree_iterator* iter = NULL;
+
+ iter = raptor_new_avltree_iterator(context->subjects, NULL, NULL, 1);
+ while(iter) {
+ subject = (raptor_abbrev_subject *)raptor_avltree_iterator_get(iter);
+ if(subject) {
+ rc = raptor_turtle_emit_subject(serializer, subject, 0);
+ if(rc) {
+ raptor_free_avltree_iterator(iter);
+ return rc;
+ }
+ }
+ if(raptor_avltree_iterator_next(iter)) break;
+ }
+ if(iter) raptor_free_avltree_iterator(iter);
+
+ /* Emit any remaining blank nodes. */
+ iter = raptor_new_avltree_iterator(context->blanks, NULL, NULL, 1);
+ while(iter) {
+ blank = (raptor_abbrev_subject *)raptor_avltree_iterator_get(iter);
+ if(blank) {
+ rc = raptor_turtle_emit_subject(serializer, blank, 0);
+ if(rc) {
+ raptor_free_avltree_iterator(iter);
+ return rc;
+ }
+ }
+ if(raptor_avltree_iterator_next(iter)) break;
+ }
+ if(iter) raptor_free_avltree_iterator(iter);
+
+ return 0;
+}
+
+
+/*
+ * raptor serializer Turtle implementation
+ */
+
+
+/* create a new serializer */
+static int
+raptor_turtle_serialize_init(raptor_serializer* serializer, const char *name)
+{
+ raptor_turtle_context* context = (raptor_turtle_context*)serializer->context;
+ raptor_uri *rdf_type_uri;
+
+ context->turtle_writer_flags = 0;
+ if(!strcmp(name,(const char*)"mkr")) {
+ context->emit_mkr = 1;
+ context->turtle_writer_flags |= TURTLE_WRITER_FLAG_MKR;
+ } else
+ context->emit_mkr = 0;
+ context->resultset = 0;
+ context->written_begin = 0;
+
+ context->nstack = raptor_new_namespaces(serializer->world, 1);
+ if(!context->nstack)
+ return 1;
+ context->rdf_nspace = raptor_new_namespace(context->nstack,
+ (const unsigned char*)"rdf",
+ (const unsigned char*)raptor_rdf_namespace_uri,
+ 0);
+
+ context->namespaces = raptor_new_sequence(NULL, NULL);
+
+ context->subjects =
+ raptor_new_avltree((raptor_data_compare_handler)raptor_abbrev_subject_compare,
+ (raptor_data_free_handler)raptor_free_abbrev_subject, 0);
+
+ context->blanks =
+ raptor_new_avltree((raptor_data_compare_handler)raptor_abbrev_subject_compare,
+ (raptor_data_free_handler)raptor_free_abbrev_subject, 0);
+
+ context->nodes =
+ raptor_new_avltree((raptor_data_compare_handler)raptor_abbrev_node_compare,
+ (raptor_data_free_handler)raptor_free_abbrev_node, 0);
+
+ rdf_type_uri = raptor_new_uri_for_rdf_concept(serializer->world,
+ (const unsigned char*)"type");
+ if(rdf_type_uri) {
+ raptor_term* uri_term;
+ uri_term = raptor_new_term_from_uri(serializer->world,
+ rdf_type_uri);
+ raptor_free_uri(rdf_type_uri);
+ context->rdf_type = raptor_new_abbrev_node(serializer->world, uri_term);
+ raptor_free_term(uri_term);
+ } else
+ context->rdf_type = NULL;
+
+ context->rdf_xml_literal_uri = raptor_new_uri(serializer->world, raptor_xml_literal_datatype_uri_string);
+ context->rdf_first_uri = raptor_new_uri(serializer->world, (const unsigned char*)"http://www.w3.org/1999/02/22-rdf-syntax-ns#first");
+ context->rdf_rest_uri = raptor_new_uri(serializer->world, (const unsigned char*)"http://www.w3.org/1999/02/22-rdf-syntax-ns#rest");
+ context->rdf_nil_uri = raptor_new_uri(serializer->world, (const unsigned char*)"http://www.w3.org/1999/02/22-rdf-syntax-ns#nil");
+
+ context->rs_ResultSet_uri = raptor_new_uri(serializer->world, (const unsigned char*)"http://jena.hpl.hp.com/2003/03/result-set#ResultSet");
+ context->rs_resultVariable_uri = raptor_new_uri(serializer->world, (const unsigned char*)"http://jena.hpl.hp.com/2003/03/result-set#resultVariable");
+
+ if(!context->rdf_nspace || !context->namespaces ||
+ !context->subjects || !context->blanks || !context->nodes ||
+ !context->rdf_xml_literal_uri || !context->rdf_first_uri ||
+ !context->rdf_rest_uri || !context->rdf_nil_uri || !context->rdf_type ||
+ !context->rs_ResultSet_uri || !context->rs_resultVariable_uri)
+ {
+ raptor_turtle_serialize_terminate(serializer);
+ return 1;
+ }
+
+ /* Note: item 0 in the list is rdf:RDF's namespace */
+ if(raptor_sequence_push(context->namespaces, context->rdf_nspace)) {
+ raptor_turtle_serialize_terminate(serializer);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/* destroy a serializer */
+static void
+raptor_turtle_serialize_terminate(raptor_serializer* serializer)
+{
+ raptor_turtle_context* context = (raptor_turtle_context*)serializer->context;
+
+ if(context->turtle_writer) {
+ raptor_free_turtle_writer(context->turtle_writer);
+ context->turtle_writer = NULL;
+ }
+
+ if(context->rdf_nspace) {
+ raptor_free_namespace(context->rdf_nspace);
+ context->rdf_nspace = NULL;
+ }
+
+ if(context->namespaces) {
+ int i;
+
+ /* Note: item 0 in the list is rdf:RDF's namespace and freed above */
+ for(i = 1; i< raptor_sequence_size(context->namespaces); i++) {
+ raptor_namespace* ns;
+ ns =(raptor_namespace*)raptor_sequence_get_at(context->namespaces, i);
+ if(ns)
+ raptor_free_namespace(ns);
+ }
+ raptor_free_sequence(context->namespaces);
+ context->namespaces = NULL;
+ }
+
+ if(context->subjects) {
+ raptor_free_avltree(context->subjects);
+ context->subjects = NULL;
+ }
+
+ if(context->blanks) {
+ raptor_free_avltree(context->blanks);
+ context->blanks = NULL;
+ }
+
+ if(context->nodes) {
+ raptor_free_avltree(context->nodes);
+ context->nodes = NULL;
+ }
+
+ if(context->nstack) {
+ raptor_free_namespaces(context->nstack);
+ context->nstack = NULL;
+ }
+
+ if(context->rdf_type) {
+ raptor_free_abbrev_node(context->rdf_type);
+ context->rdf_type = NULL;
+ }
+
+ if(context->rdf_xml_literal_uri) {
+ raptor_free_uri(context->rdf_xml_literal_uri);
+ context->rdf_xml_literal_uri = NULL;
+ }
+
+ if(context->rdf_first_uri) {
+ raptor_free_uri(context->rdf_first_uri);
+ context->rdf_first_uri = NULL;
+ }
+
+ if(context->rdf_rest_uri) {
+ raptor_free_uri(context->rdf_rest_uri);
+ context->rdf_rest_uri = NULL;
+ }
+
+ if(context->rdf_nil_uri) {
+ raptor_free_uri(context->rdf_nil_uri);
+ context->rdf_nil_uri = NULL;
+ }
+
+ if(context->rs_ResultSet_uri) {
+ raptor_free_uri(context->rs_ResultSet_uri);
+ context->rs_ResultSet_uri = NULL;
+ }
+
+ if(context->rs_resultVariable_uri) {
+ raptor_free_uri(context->rs_resultVariable_uri);
+ context->rs_resultVariable_uri = NULL;
+ }
+}
+
+
+#define TURTLE_NAMESPACE_DEPTH 0
+
+/* add a namespace */
+static int
+raptor_turtle_serialize_declare_namespace_from_namespace(raptor_serializer* serializer,
+ raptor_namespace *nspace)
+{
+ raptor_turtle_context* context = (raptor_turtle_context*)serializer->context;
+ int i;
+
+ if(context->written_header)
+ return 1;
+
+ for(i = 0; i< raptor_sequence_size(context->namespaces); i++) {
+ raptor_namespace* ns;
+ ns = (raptor_namespace*)raptor_sequence_get_at(context->namespaces, i);
+
+ /* If prefix is already declared, ignore it */
+ if(!ns->prefix && !nspace->prefix)
+ return 1;
+
+ if(ns->prefix && nspace->prefix &&
+ !strcmp((const char*)ns->prefix, (const char*)nspace->prefix))
+ return 1;
+
+ if(ns->uri && nspace->uri &&
+ raptor_uri_equals(ns->uri, nspace->uri))
+ return 1;
+ }
+
+ nspace = raptor_new_namespace_from_uri(context->nstack,
+ nspace->prefix, nspace->uri,
+ TURTLE_NAMESPACE_DEPTH);
+ if(!nspace)
+ return 1;
+
+ raptor_sequence_push(context->namespaces, nspace);
+ return 0;
+}
+
+
+/* add a namespace */
+static int
+raptor_turtle_serialize_declare_namespace(raptor_serializer* serializer,
+ raptor_uri *uri,
+ const unsigned char *prefix)
+{
+ raptor_turtle_context* context = (raptor_turtle_context*)serializer->context;
+ raptor_namespace *ns;
+ int rc;
+
+ ns = raptor_new_namespace_from_uri(context->nstack, prefix, uri,
+ TURTLE_NAMESPACE_DEPTH);
+
+ rc = raptor_turtle_serialize_declare_namespace_from_namespace(serializer, ns);
+ raptor_free_namespace(ns);
+
+ return rc;
+}
+
+
+/* start a serialize */
+static int
+raptor_turtle_serialize_start(raptor_serializer* serializer)
+{
+ raptor_turtle_context* context = (raptor_turtle_context*)serializer->context;
+ raptor_turtle_writer* turtle_writer;
+ int flag;
+
+ if(context->turtle_writer)
+ raptor_free_turtle_writer(context->turtle_writer);
+
+ flag = RAPTOR_OPTIONS_GET_NUMERIC(serializer, RAPTOR_OPTION_WRITE_BASE_URI);
+ turtle_writer = raptor_new_turtle_writer(serializer->world,
+ serializer->base_uri,
+ flag,
+ context->nstack,
+ serializer->iostream,
+ context->turtle_writer_flags);
+ if(!turtle_writer)
+ return 1;
+
+ raptor_turtle_writer_set_option(turtle_writer,
+ RAPTOR_OPTION_WRITER_AUTO_INDENT, 1);
+ raptor_turtle_writer_set_option(turtle_writer,
+ RAPTOR_OPTION_WRITER_INDENT_WIDTH, 2);
+
+ context->turtle_writer = turtle_writer;
+
+ return 0;
+}
+
+static void
+raptor_turtle_ensure_writen_header(raptor_serializer* serializer,
+ raptor_turtle_context* context)
+{
+ int i;
+ raptor_turtle_writer* turtle_writer = context->turtle_writer;
+
+ if(context->written_header)
+ return;
+
+ if(!context->turtle_writer)
+ return;
+
+ for(i = 0; i< raptor_sequence_size(context->namespaces); i++) {
+ raptor_namespace* ns;
+ ns = (raptor_namespace*)raptor_sequence_get_at(context->namespaces, i);
+ raptor_turtle_writer_namespace_prefix(turtle_writer, ns);
+ raptor_namespace_stack_start_namespace(context->nstack, ns, 0);
+ }
+
+ raptor_turtle_writer_newline(context->turtle_writer);
+
+ context->written_header = 1;
+}
+
+/* serialize a statement */
+static int
+raptor_turtle_serialize_statement(raptor_serializer* serializer,
+ raptor_statement *statement)
+{
+ raptor_turtle_context* context = (raptor_turtle_context*)serializer->context;
+ raptor_abbrev_subject* subject = NULL;
+ raptor_abbrev_node* predicate = NULL;
+ raptor_abbrev_node* object = NULL;
+ int rv;
+ raptor_term_type object_type;
+
+ if(!(statement->subject->type == RAPTOR_TERM_TYPE_URI ||
+ statement->subject->type == RAPTOR_TERM_TYPE_BLANK)) {
+ raptor_log_error_formatted(serializer->world, RAPTOR_LOG_LEVEL_ERROR, NULL,
+ "Do not know how to serialize node type %u",
+ statement->subject->type);
+ return 1;
+ }
+
+ subject = raptor_abbrev_subject_lookup(context->nodes, context->subjects,
+ context->blanks,
+ statement->subject);
+ if(!subject) {
+ return 1;
+ }
+
+ object_type = statement->object->type;
+
+ if(!(object_type == RAPTOR_TERM_TYPE_URI ||
+ object_type == RAPTOR_TERM_TYPE_BLANK ||
+ object_type == RAPTOR_TERM_TYPE_LITERAL)) {
+ raptor_log_error_formatted(serializer->world, RAPTOR_LOG_LEVEL_ERROR, NULL,
+ "Cannot serialize a triple with object node type %u",
+ object_type);
+ return 1;
+ }
+
+ object = raptor_abbrev_node_lookup(context->nodes, statement->object);
+ if(!object)
+ return 1;
+
+
+ if(statement->predicate->type == RAPTOR_TERM_TYPE_URI) {
+ predicate = raptor_abbrev_node_lookup(context->nodes, statement->predicate);
+ if(!predicate)
+ return 1;
+
+ rv = raptor_abbrev_subject_add_property(subject, predicate, object);
+ if(rv < 0) {
+ raptor_log_error_formatted(serializer->world, RAPTOR_LOG_LEVEL_ERROR, NULL,
+ "Unable to add properties to subject %p",
+ RAPTOR_VOIDP(subject));
+ return rv;
+ }
+
+ } else {
+ raptor_log_error_formatted(serializer->world, RAPTOR_LOG_LEVEL_ERROR, NULL,
+ "Do not know how to serialize node type %u",
+ statement->predicate->type);
+ return 1;
+ }
+
+ if(object_type == RAPTOR_TERM_TYPE_URI ||
+ object_type == RAPTOR_TERM_TYPE_BLANK)
+ object->count_as_object++;
+
+ return 0;
+}
+
+
+/* end a serialize */
+static int
+raptor_turtle_serialize_end(raptor_serializer* serializer)
+{
+ raptor_turtle_context* context = (raptor_turtle_context*)serializer->context;
+
+ raptor_turtle_ensure_writen_header(serializer, context);
+
+ raptor_turtle_emit(serializer);
+
+ /* reset serializer for reuse */
+ context->written_header = 0;
+
+ return 0;
+}
+
+/* flush turtle */
+static int
+raptor_turtle_serialize_flush(raptor_serializer* serializer)
+{
+ raptor_turtle_context* context = (raptor_turtle_context*)serializer->context;
+
+ raptor_turtle_ensure_writen_header(serializer, context);
+
+ raptor_turtle_emit(serializer);
+
+ if(context->subjects) {
+ raptor_avltree_trim(context->subjects);
+ }
+
+ if(context->blanks) {
+ raptor_avltree_trim(context->blanks);
+ }
+
+ if(context->nodes) {
+ raptor_avltree_trim(context->nodes);
+ }
+
+ return 0;
+}
+
+
+/* finish the serializer factory */
+static void
+raptor_turtle_serialize_finish_factory(raptor_serializer_factory* factory)
+{
+ /* NOP */
+}
+
+
+static const char* const turtle_names[2] = { "turtle", NULL};
+static const char* const mkr_names[2] = { "mkr", NULL};
+
+static const char* const turtle_uri_strings[3] = {
+ "http://www.w3.org/ns/formats/Turtle",
+ "http://www.dajobe.org/2004/01/turtle/",
+ NULL
+};
+
+#define TURTLE_TYPES_COUNT 6
+static const raptor_type_q turtle_types[TURTLE_TYPES_COUNT + 1] = {
+ { "text/turtle", 11, 10},
+ { "application/turtle", 18, 10},
+ { "application/x-turtle", 20, 8},
+ { "text/n3", 7, 3},
+ { "text/rdf+n3", 11, 3},
+ { "application/rdf+n3", 18, 3},
+ { NULL, 0, 0}
+};
+#define MKR_TYPES_COUNT 6
+static const raptor_type_q mkr_types[TURTLE_TYPES_COUNT + 1] = {
+ { "text/mkr", 8, 10},
+ { "application/mkr", 15, 10},
+ { "application/x-mkr", 17, 8},
+ { "text/n3", 7, 3},
+ { "text/rdf+n3", 11, 3},
+ { "application/rdf+n3", 18, 3},
+ { NULL, 0, 0}
+};
+
+static int
+raptor_turtle_serializer_register_factory(raptor_serializer_factory *factory)
+{
+ factory->desc.names = turtle_names;
+ factory->desc.mime_types = turtle_types;
+
+ factory->desc.label = "Turtle Terse RDF Triple Language";
+ factory->desc.uri_strings = turtle_uri_strings;
+
+ factory->context_length = sizeof(raptor_turtle_context);
+
+ factory->init = raptor_turtle_serialize_init;
+ factory->terminate = raptor_turtle_serialize_terminate;
+ factory->declare_namespace = raptor_turtle_serialize_declare_namespace;
+ factory->declare_namespace_from_namespace = raptor_turtle_serialize_declare_namespace_from_namespace;
+ factory->serialize_start = raptor_turtle_serialize_start;
+ factory->serialize_statement = raptor_turtle_serialize_statement;
+ factory->serialize_end = raptor_turtle_serialize_end;
+ factory->serialize_flush = raptor_turtle_serialize_flush;
+ factory->finish_factory = raptor_turtle_serialize_finish_factory;
+
+ return 0;
+}
+
+static int
+raptor_mkr_serializer_register_factory(raptor_serializer_factory *factory)
+{
+ factory->desc.names = mkr_names;
+ factory->desc.mime_types = mkr_types;
+
+ factory->desc.label = "mKR my Knowledge Representation Language";
+ factory->desc.uri_strings = turtle_uri_strings;
+
+ factory->context_length = sizeof(raptor_turtle_context);
+
+ factory->init = raptor_turtle_serialize_init;
+ factory->terminate = raptor_turtle_serialize_terminate;
+ factory->declare_namespace = raptor_turtle_serialize_declare_namespace;
+ factory->declare_namespace_from_namespace = raptor_turtle_serialize_declare_namespace_from_namespace;
+ factory->serialize_start = raptor_turtle_serialize_start;
+ factory->serialize_statement = raptor_turtle_serialize_statement;
+ factory->serialize_end = raptor_turtle_serialize_end;
+ factory->finish_factory = raptor_turtle_serialize_finish_factory;
+
+ return 0;
+}
+
+int
+raptor_init_serializer_turtle(raptor_world* world)
+{
+ return !raptor_serializer_register_factory(world,
+ &raptor_turtle_serializer_register_factory);
+}
+
+int
+raptor_init_serializer_mkr(raptor_world* world)
+{
+ return !raptor_serializer_register_factory(world,
+ &raptor_mkr_serializer_register_factory);
+}
+
+
+
+/**
+ * raptor_uri_turtle_write:
+ * @world: world
+ * @iostr: iostream for writing
+ * @uri: uri
+ * @nstack: namespace stack
+ * @base_uri: base URI
+ *
+ * Write #raptor_uri to a stream in turtle syntax (using QNames).
+ *
+ * Note: This creates and destroys several internal objects for each
+ * call so for more efficient writing, create a turtle serializer.
+ *
+ * Return value: non-0 on failure
+ */
+int
+raptor_uri_turtle_write(raptor_world *world,
+ raptor_iostream* iostr,
+ raptor_uri* uri,
+ raptor_namespace_stack *nstack,
+ raptor_uri *base_uri)
+{
+ int rc;
+ raptor_turtle_writer* turtle_writer;
+
+ turtle_writer = raptor_new_turtle_writer(world, base_uri, 0, nstack, iostr, 0);
+ if(!turtle_writer)
+ return 1;
+
+ rc = raptor_turtle_writer_uri(turtle_writer, uri);
+
+ raptor_free_turtle_writer(turtle_writer);
+
+ return rc;
+}
+
+
+
+/**
+ * raptor_term_turtle_write:
+ * @iostr: iostream for writing
+ * @term: term
+ * @nstack: namespace stack
+ * @base_uri: base URI
+ *
+ * Write #raptor_term to a stream in turtle syntax (using QNames).
+ *
+ * Note: This creates and destroys several internal objects for each
+ * call so for more efficient writing, create a turtle serializer.
+ *
+ * Return value: non-0 on failure
+ */
+int
+raptor_term_turtle_write(raptor_iostream* iostr,
+ raptor_term* term,
+ raptor_namespace_stack *nstack,
+ raptor_uri *base_uri)
+{
+ int rc;
+ raptor_turtle_writer* turtle_writer;
+
+ turtle_writer = raptor_new_turtle_writer(term->world, base_uri, 0, nstack,
+ iostr, 0);
+ if(!turtle_writer)
+ return 1;
+
+ rc = raptor_turtle_writer_term(turtle_writer, term);
+
+ raptor_free_turtle_writer(turtle_writer);
+
+ return rc;
+}
+
+
+
+/**
+ * raptor_uri_to_turtle_counted_string:
+ * @world: world
+ * @uri: uri
+ * @nstack: namespace stack
+ * @base_uri: base URI
+ * @len_p: Pointer to location to store length of new string (if not NULL)
+ *
+ * Convert #raptor_uri to a string.
+ * Caller has responsibility to free the string.
+ *
+ * Note: This creates and destroys several internal objects for each
+ * call so for more efficient writing, create a turtle serializer.
+ *
+ * Return value: the new string or NULL on failure. The length of
+ * the new string is returned in *@len_p if len_p is not NULL.
+ */
+unsigned char*
+raptor_uri_to_turtle_counted_string(raptor_world *world,
+ raptor_uri* uri,
+ raptor_namespace_stack *nstack,
+ raptor_uri *base_uri,
+ size_t *len_p)
+{
+ int rc = 1;
+ raptor_iostream* iostr;
+ unsigned char *s = NULL;
+ raptor_turtle_writer* turtle_writer;
+
+ iostr = raptor_new_iostream_to_string(world,
+ (void**)&s, len_p, malloc);
+ if(!iostr)
+ return NULL;
+
+ turtle_writer = raptor_new_turtle_writer(world, base_uri, 0, nstack, iostr, 0);
+ if(!turtle_writer)
+ goto tidy;
+
+ rc = raptor_turtle_writer_uri(turtle_writer, uri);
+
+ raptor_free_turtle_writer(turtle_writer);
+
+ tidy:
+ raptor_free_iostream(iostr);
+
+ if(rc) {
+ free(s);
+ s = NULL;
+ }
+
+ return s;
+}
+
+/**
+ * raptor_uri_to_turtle_string:
+ * @world: world
+ * @uri: uri
+ * @nstack: namespace stack
+ * @base_uri: base URI
+ *
+ * Convert #raptor_uri to a string.
+ * Caller has responsibility to free the string.
+ *
+ * Note: This creates and destroys several internal objects for each
+ * call so for more efficient writing, create a turtle serializer.
+ *
+ * Return value: the new string or NULL on failure.
+ */
+unsigned char*
+raptor_uri_to_turtle_string(raptor_world *world,
+ raptor_uri* uri,
+ raptor_namespace_stack *nstack,
+ raptor_uri *base_uri)
+{
+ return raptor_uri_to_turtle_counted_string(world, uri, nstack, base_uri, NULL);
+}
+
+
+
+/**
+ * raptor_term_to_turtle_counted_string:
+ * @term: term
+ * @nstack: namespace stack
+ * @base_uri: base URI
+ * @len_p: Pointer to location to store length of new string (if not NULL)
+ *
+ * Convert #raptor_term to a string.
+ * Caller has responsibility to free the string.
+ *
+ * Note: This creates and destroys several internal objects for each
+ * call so for more efficient writing, create a turtle serializer.
+ *
+ * See also raptor_term_to_counted_string() which writes in simpler
+ * N-Triples with no Turtle abbreviated forms, and is quicker.
+ *
+ * Return value: the new string or NULL on failure. The length of
+ * the new string is returned in *@len_p if len_p is not NULL.
+ */
+unsigned char*
+raptor_term_to_turtle_counted_string(raptor_term* term,
+ raptor_namespace_stack *nstack,
+ raptor_uri *base_uri,
+ size_t *len_p)
+{
+ int rc;
+ raptor_iostream* iostr;
+ unsigned char *s;
+ iostr = raptor_new_iostream_to_string(term->world,
+ (void**)&s, len_p, malloc);
+ if(!iostr)
+ return NULL;
+
+ rc = raptor_term_turtle_write(iostr, term, nstack, base_uri);
+
+ raptor_free_iostream(iostr);
+ if(rc) {
+ free(s);
+ s = NULL;
+ }
+
+ return s;
+}
+
+/**
+ * raptor_term_to_turtle_string:
+ * @term: term
+ * @nstack: namespace stack
+ * @base_uri: base URI
+ *
+ * Convert #raptor_term to a string.
+ * Caller has responsibility to free the string.
+ *
+ * See also raptor_term_to_counted_string() which writes in simpler
+ * N-Triples with no Turtle abbreviated forms, and is quicker.
+ *
+ * Return value: the new string or NULL on failure.
+ */
+unsigned char*
+raptor_term_to_turtle_string(raptor_term* term,
+ raptor_namespace_stack *nstack,
+ raptor_uri *base_uri)
+{
+ return raptor_term_to_turtle_counted_string(term, nstack, base_uri, NULL);
+}
+