1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-08-08 08:01:19 +02:00
audacity/lib-src/redland/raptor/src/raptor_serialize_turtle.c
2010-01-24 09:19:39 +00:00

1241 lines
40 KiB
C

/* -*- Mode: c; c-basic-offset: 2 -*-
*
* raptor_serialize_turtle.c - Turtle serializer
*
* Copyright (C) 2006,2008 Dave Robillard
* Copyright (C) 2004-2008 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
#ifdef WIN32
#include <win32_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 "raptor.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_sequence *subjects; /* subject items */
raptor_sequence *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;
/* 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;
} 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_xml_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_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,
const raptor_statement *statement);
static int raptor_turtle_serialize_end(raptor_serializer* serializer);
static void raptor_turtle_serialize_finish_factory(raptor_serializer_factory* factory);
/*
* 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;
raptor_turtle_writer *turtle_writer = context->turtle_writer;
raptor_qname* qname = NULL;
RAPTOR_DEBUG5("Emitting resource node %p refcount %d subject %d object %d\n",
node,
node->ref_count, node->count_as_subject, node->count_as_object);
if(node->type != RAPTOR_IDENTIFIER_TYPE_RESOURCE)
return 1;
qname = raptor_namespaces_qname_from_uri(context->nstack,
node->value.resource.uri, 10);
if(qname) {
raptor_turtle_writer_qname(turtle_writer, qname);
raptor_free_qname(qname);
} else {
raptor_turtle_writer_reference(turtle_writer, node->value.resource.uri);
}
RAPTOR_DEBUG2("Emitted %p\n", 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_DEBUG5("Emitting literal node %p refcount %d subject %d object %d\n",
node,
node->ref_count, node->count_as_subject, node->count_as_object);
if(node->type != RAPTOR_IDENTIFIER_TYPE_LITERAL)
return 1;
rc=raptor_turtle_writer_literal(turtle_writer, context->nstack,
node->value.literal.string,
node->value.literal.language,
node->value.literal.datatype);
RAPTOR_DEBUG2("Emitted %p\n", node);
return rc;
}
/*
* raptor_turtle_emit_xml_literal:
* @serializer: #raptor_serializer object
* @node: XML literal node
* @depth: depth into tree
*
* Emit a description of a literal using an XML Element
*
* Return value: non-0 on failure
**/
static int
raptor_turtle_emit_xml_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;
raptor_uri* type_uri;
int rc=0;
RAPTOR_DEBUG5("Emitting XML literal node %p refcount %d subject %d object %d\n",
node,
node->ref_count, node->count_as_subject, node->count_as_object);
if(node->type != RAPTOR_IDENTIFIER_TYPE_XML_LITERAL)
return 1;
type_uri = raptor_new_uri((const unsigned char*)
"http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral");
rc=raptor_turtle_writer_literal(turtle_writer, context->nstack,
node->value.literal.string, NULL, type_uri);
raptor_free_uri(type_uri);
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;
int rc=0;
RAPTOR_DEBUG5("Emitting blank node %p refcount %d subject %d object %d\n",
node,
node->ref_count, node->count_as_subject, node->count_as_object);
if(node->type != RAPTOR_IDENTIFIER_TYPE_ANONYMOUS)
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 */
int idx;
raptor_abbrev_subject* blank;
blank = raptor_abbrev_subject_find(context->blanks,
node->type,
node->value.blank.string, &idx);
if(blank) {
rc = raptor_turtle_emit_subject(serializer, blank, depth+1);
raptor_sequence_set_at(context->blanks, idx, NULL);
}
} else {
/* Blank node that needs an explicit name */
const unsigned char *node_id = node->value.blank.string;
raptor_turtle_writer_raw(context->turtle_writer, (const unsigned char*)"_:");
raptor_turtle_writer_raw(context->turtle_writer, node_id);
}
RAPTOR_DEBUG2("Emitted %p\n", 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_DEBUG5("Emitting subject list items for node %p refcount %d subject %d object %d\n",
subject->node,
subject->node->ref_count, subject->node->count_as_subject,
subject->node->count_as_object);
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->type) {
case RAPTOR_IDENTIFIER_TYPE_RESOURCE:
rv = raptor_turtle_emit_resource(serializer, object, depth+1);
break;
case RAPTOR_IDENTIFIER_TYPE_LITERAL:
rv = raptor_turtle_emit_literal(serializer, object, depth+1);
break;
case RAPTOR_IDENTIFIER_TYPE_XML_LITERAL:
rv = raptor_turtle_emit_xml_literal(serializer, object, depth+1);
break;
case RAPTOR_IDENTIFIER_TYPE_ANONYMOUS:
rv = raptor_turtle_emit_blank(serializer, object, depth+1);
break;
case RAPTOR_IDENTIFIER_TYPE_ORDINAL:
/* ordinals should never appear as an object with current parsers */
case RAPTOR_IDENTIFIER_TYPE_PREDICATE:
/* predicates should never appear as an object */
case RAPTOR_IDENTIFIER_TYPE_UNKNOWN:
default:
RAPTOR_FATAL1("Unsupported identifier type\n");
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 rv = 0;
int idx;
raptor_avltree_iterator* iter=NULL;
int i;
RAPTOR_DEBUG5("Emitting subject collection items for node %p refcount %d subject %d object %d\n",
subject->node,
subject->node->ref_count, subject->node->count_as_subject,
subject->node->count_as_object);
for(i=0, (iter=raptor_new_avltree_iterator(subject->properties, NULL, NULL, 1));
iter && !rv;
i++, (rv=raptor_avltree_iterator_next(iter))) {
raptor_abbrev_node** nodes;
raptor_abbrev_node* predicate;
raptor_abbrev_node* object;
nodes=(raptor_abbrev_node**)raptor_avltree_iterator_get(iter);
if(!nodes)
break;
predicate= nodes[0];
object= nodes[1];
if(!raptor_uri_equals(predicate->value.resource.uri,
context->rdf_first_uri)) {
raptor_serializer_error(serializer,
"Malformed collection - first predicate is not rdf:first");
return 1;
}
if(!object)
continue;
if(i > 0)
raptor_turtle_writer_newline(context->turtle_writer);
switch(object->type) {
case RAPTOR_IDENTIFIER_TYPE_RESOURCE:
rv = raptor_turtle_emit_resource(serializer, object, depth+1);
break;
case RAPTOR_IDENTIFIER_TYPE_LITERAL:
rv = raptor_turtle_emit_literal(serializer, object, depth+1);
break;
case RAPTOR_IDENTIFIER_TYPE_XML_LITERAL:
rv = raptor_turtle_emit_xml_literal(serializer, object, depth+1);
break;
case RAPTOR_IDENTIFIER_TYPE_ANONYMOUS:
rv = raptor_turtle_emit_blank(serializer, object, depth+1);
break;
case RAPTOR_IDENTIFIER_TYPE_ORDINAL:
/* ordinals should never appear as an object with current parsers */
case RAPTOR_IDENTIFIER_TYPE_PREDICATE:
/* predicates should never appear as an object */
case RAPTOR_IDENTIFIER_TYPE_UNKNOWN:
default:
RAPTOR_FATAL1("Unsupported identifier type\n");
break;
}
/* 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->value.resource.uri, context->rdf_rest_uri)) {
raptor_serializer_error(serializer,
"Malformed collection - second predicate is not rdf:rest");
return 1;
}
if(object->type == RAPTOR_IDENTIFIER_TYPE_ANONYMOUS) {
subject = raptor_abbrev_subject_find(context->blanks, object->type,
object->value.blank.string, &idx);
if(!subject) {
raptor_serializer_error(serializer,
"Malformed collection - could not find subject for rdf:rest");
return 1;
}
} else {
if(object->type != RAPTOR_IDENTIFIER_TYPE_RESOURCE ||
!raptor_uri_equals(object->value.resource.uri, context->rdf_nil_uri)) {
raptor_serializer_error(serializer,
"Malformed collection - last rdf:rest resource is not rdf:nil");
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;
raptor_abbrev_node* last_predicate=NULL;
int rv = 0;
raptor_avltree_iterator* iter=NULL;
int i;
RAPTOR_DEBUG5("Emitting subject properties for node %p refcount %d subject %d object %d\n",
subject->node, subject->node->ref_count,
subject->node->count_as_subject,
subject->node->count_as_object);
/* 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(i=0, (iter=raptor_new_avltree_iterator(subject->properties, NULL, NULL, 1));
iter && !rv;
i++, (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))) {
/* no object list abbreviation possible, terminate last object */
if(last_predicate) {
raptor_turtle_writer_raw(turtle_writer, (const unsigned char*)" ;");
raptor_turtle_writer_newline(turtle_writer);
}
if(predicate->type == RAPTOR_IDENTIFIER_TYPE_ORDINAL) {
/* we should only get here in rare cases -- usually when there
* are multiple ordinals with the same value. */
unsigned char uri_string[MAX_ASCII_INT_SIZE + 2];
sprintf((char*)uri_string, "_%d", predicate->value.ordinal.ordinal);
qname = raptor_new_qname_from_namespace_local_name(context->rdf_nspace,
uri_string, NULL);
} else {
qname = raptor_namespaces_qname_from_uri(context->nstack,
predicate->value.resource.uri, 10);
}
if(raptor_abbrev_node_equals(predicate, context->rdf_type))
raptor_turtle_writer_raw(turtle_writer, (const unsigned char*)"a");
else if(qname)
raptor_turtle_writer_qname(turtle_writer, qname);
else
raptor_turtle_writer_reference(turtle_writer, predicate->value.resource.uri);
raptor_turtle_writer_raw(turtle_writer, (const unsigned char*)" ");
if(qname)
raptor_free_qname(qname);
} else
raptor_turtle_writer_raw(turtle_writer, (const unsigned char*)", ");
switch(object->type) {
case RAPTOR_IDENTIFIER_TYPE_RESOURCE:
rv = raptor_turtle_emit_resource(serializer, object, depth+1);
break;
case RAPTOR_IDENTIFIER_TYPE_LITERAL:
rv = raptor_turtle_emit_literal(serializer, object, depth+1);
break;
case RAPTOR_IDENTIFIER_TYPE_ANONYMOUS:
rv = raptor_turtle_emit_blank(serializer, object, depth+1);
break;
case RAPTOR_IDENTIFIER_TYPE_XML_LITERAL:
rv = raptor_turtle_emit_xml_literal(serializer, object, depth+1);
break;
case RAPTOR_IDENTIFIER_TYPE_ORDINAL:
/* ordinals should never appear as an object with current parsers */
case RAPTOR_IDENTIFIER_TYPE_PREDICATE:
/* predicates should never appear as an object */
case RAPTOR_IDENTIFIER_TYPE_UNKNOWN:
default:
RAPTOR_FATAL1("Unsupported identifier type\n");
break;
}
last_predicate = predicate;
}
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 blank = 1;
int collection = 0;
int rc = 0;
RAPTOR_DEBUG5("Emitting subject node %p refcount %d subject %d object %d\n",
subject->node,
subject->node->ref_count,
subject->node->count_as_subject,
subject->node->count_as_object);
if(!depth &&
subject->node->type == RAPTOR_IDENTIFIER_TYPE_ANONYMOUS &&
subject->node->count_as_subject == 1 &&
subject->node->count_as_object == 1) {
RAPTOR_DEBUG2("Skipping subject node %p\n", subject->node);
return 0;
}
if(raptor_avltree_size(subject->properties) == 0) {
RAPTOR_DEBUG2("Skipping subject node %p\n", subject->node);
return 0;
}
/* check if we can do collection abbreviation */
if(raptor_avltree_size(subject->properties) >= 4) {
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];
raptor_avltree_iterator_next(iter);
pred2=((raptor_abbrev_node**)raptor_avltree_iterator_get(iter))[0];
raptor_free_avltree_iterator(iter);
if(pred1->type == RAPTOR_IDENTIFIER_TYPE_RESOURCE &&
pred2->type == RAPTOR_IDENTIFIER_TYPE_RESOURCE &&
(
(raptor_uri_equals(pred1->value.resource.uri, context->rdf_first_uri) &&
raptor_uri_equals(pred2->value.resource.uri, context->rdf_rest_uri))
||
(raptor_uri_equals(pred2->value.resource.uri, context->rdf_first_uri) &&
raptor_uri_equals(pred1->value.resource.uri, context->rdf_rest_uri))
)
) {
collection = 1;
}
}
/* emit the subject node */
if(subject->node->type == RAPTOR_IDENTIFIER_TYPE_RESOURCE) {
rc= raptor_turtle_emit_resource(serializer, subject->node, depth+1);
if(rc)
return rc;
blank = 0;
} else if(subject->node->type == RAPTOR_IDENTIFIER_TYPE_ANONYMOUS) {
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) {
raptor_turtle_writer_raw(turtle_writer, (const unsigned char*)"[]");
blank = 0;
} else if(!collection && subject->node->count_as_object > 1) {
/* Referred to (used as an object), so needs a nodeID */
const unsigned char* genid = subject->node->value.blank.string;
size_t len = strlen((const char*)genid);
unsigned char* subject_str;
subject_str= (unsigned char *)RAPTOR_MALLOC(cstring, len+3);
if(!subject_str)
return 1;
subject_str[0]='_';
subject_str[1]=':';
strncpy((char*)&subject_str[2], (const char*)genid, len+1);
raptor_turtle_writer_raw(turtle_writer, subject_str);
RAPTOR_FREE(cstring, subject_str);
}
} else if(subject->node->type == RAPTOR_IDENTIFIER_TYPE_ORDINAL) {
unsigned char* subject_str;
subject_str = (unsigned char *)RAPTOR_MALLOC(string,
raptor_rdf_namespace_uri_len + MAX_ASCII_INT_SIZE + 2);
if(!subject_str)
return 1;
sprintf((char*)subject, "%s_%d", raptor_rdf_namespace_uri,
subject->node->value.ordinal.ordinal);
raptor_turtle_writer_raw(turtle_writer, subject_str);
RAPTOR_FREE(cstring, subject_str);
return blank = 0;
}
if(collection) {
raptor_turtle_writer_raw(turtle_writer, (const unsigned char*)"(");
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);
raptor_turtle_writer_newline(turtle_writer);
raptor_turtle_writer_raw(turtle_writer, (const unsigned char*)")");
} else {
if(blank && depth > 1)
raptor_turtle_writer_raw(turtle_writer, (const unsigned char*)"[");
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(turtle_writer, (const unsigned char*)"]");
}
}
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)
*/
raptor_turtle_writer_raw(turtle_writer, (const unsigned char*)" .");
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 i;
int rc;
for(i=0; i < raptor_sequence_size(context->subjects); i++) {
subject = (raptor_abbrev_subject* )raptor_sequence_get_at(context->subjects, i);
if(subject) {
rc= raptor_turtle_emit_subject(serializer, subject, 0);
if(rc)
return rc;
}
}
/* Emit any remaining blank nodes */
for(i=0; i < raptor_sequence_size(context->blanks); i++) {
blank = (raptor_abbrev_subject* )raptor_sequence_get_at(context->blanks, i);
if(blank) {
rc= raptor_turtle_emit_subject(serializer, blank, 0);
if(rc)
return rc;
}
}
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;
const raptor_uri_handler *uri_handler;
raptor_uri *rdf_type_uri;
void *uri_context;
raptor_uri_get_handler(&uri_handler, &uri_context);
context->nstack=raptor_new_namespaces(uri_handler, uri_context,
(raptor_simple_message_handler)raptor_serializer_simple_error,
serializer,
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_sequence((raptor_sequence_free_handler *)raptor_free_abbrev_subject,NULL);
context->blanks =
raptor_new_sequence((raptor_sequence_free_handler *)raptor_free_abbrev_subject,NULL);
context->nodes =
raptor_new_avltree((raptor_data_compare_function)raptor_abbrev_node_cmp,
(raptor_data_free_function)raptor_free_abbrev_node, 0);
rdf_type_uri = raptor_new_uri_for_rdf_concept("type");
if(rdf_type_uri) {
context->rdf_type = raptor_new_abbrev_node(RAPTOR_IDENTIFIER_TYPE_RESOURCE,
rdf_type_uri, NULL, NULL);
raptor_free_uri(rdf_type_uri);
} else
context->rdf_type = NULL;
context->rdf_xml_literal_uri=raptor_new_uri(raptor_xml_literal_datatype_uri_string);
context->rdf_first_uri=raptor_new_uri((const unsigned char*)"http://www.w3.org/1999/02/22-rdf-syntax-ns#first");
context->rdf_rest_uri=raptor_new_uri((const unsigned char*)"http://www.w3.org/1999/02/22-rdf-syntax-ns#rest");
context->rdf_nil_uri=raptor_new_uri((const unsigned char*)"http://www.w3.org/1999/02/22-rdf-syntax-ns#nil");
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)
{
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_sequence(context->subjects);
context->subjects=NULL;
}
if(context->blanks) {
raptor_free_sequence(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;
}
}
#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;
const raptor_uri_handler *uri_handler;
void *uri_context;
raptor_uri_get_handler(&uri_handler, &uri_context);
if(context->turtle_writer)
raptor_free_turtle_writer(context->turtle_writer);
turtle_writer=raptor_new_turtle_writer(serializer->base_uri,
serializer->feature_write_base_uri,
context->nstack,
uri_handler, uri_context,
serializer->iostream,
(raptor_simple_message_handler)raptor_serializer_simple_error,
serializer);
if(!turtle_writer)
return 1;
raptor_turtle_writer_set_feature(turtle_writer,
RAPTOR_FEATURE_WRITER_AUTO_INDENT,1);
raptor_turtle_writer_set_feature(turtle_writer,
RAPTOR_FEATURE_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;
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(context->turtle_writer, ns);
raptor_namespace_copy(context->nstack, ns, 0);
}
raptor_turtle_writer_raw(context->turtle_writer, (const unsigned char*)"\n");
context->written_header=1;
}
/* serialize a statement */
static int
raptor_turtle_serialize_statement(raptor_serializer* serializer,
const 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_identifier_type object_type;
int subject_created = 0;
int predicate_created = 0;
int object_created = 0;
if(!(statement->subject_type == RAPTOR_IDENTIFIER_TYPE_RESOURCE ||
statement->subject_type == RAPTOR_IDENTIFIER_TYPE_ANONYMOUS ||
statement->subject_type == RAPTOR_IDENTIFIER_TYPE_ORDINAL)) {
raptor_serializer_error(serializer,
"Do not know how to serialize node type %d\n",
statement->subject_type);
return 1;
}
subject = raptor_abbrev_subject_lookup(context->nodes, context->subjects,
context->blanks,
statement->subject_type,
statement->subject,
&subject_created);
if(!subject)
return 1;
object_type=statement->object_type;
if(object_type == RAPTOR_IDENTIFIER_TYPE_LITERAL) {
if(statement->object_literal_datatype &&
raptor_uri_equals(statement->object_literal_datatype,
context->rdf_xml_literal_uri))
object_type = RAPTOR_IDENTIFIER_TYPE_XML_LITERAL;
}
if(!(object_type == RAPTOR_IDENTIFIER_TYPE_RESOURCE ||
object_type == RAPTOR_IDENTIFIER_TYPE_ANONYMOUS ||
object_type == RAPTOR_IDENTIFIER_TYPE_LITERAL ||
object_type == RAPTOR_IDENTIFIER_TYPE_XML_LITERAL ||
object_type == RAPTOR_IDENTIFIER_TYPE_ORDINAL)) {
raptor_serializer_error(serializer,
"Cannot serialize a triple with object node type %d\n",
object_type);
return 1;
}
object = raptor_abbrev_node_lookup(context->nodes, object_type,
statement->object,
statement->object_literal_datatype,
statement->object_literal_language,
&object_created);
if(!object)
return 1;
if((statement->predicate_type == RAPTOR_IDENTIFIER_TYPE_PREDICATE) ||
(statement->predicate_type == RAPTOR_IDENTIFIER_TYPE_RESOURCE)) {
predicate = raptor_abbrev_node_lookup(context->nodes,
statement->predicate_type,
statement->predicate, NULL, NULL,
&predicate_created);
if(!predicate)
return 1;
rv = raptor_abbrev_subject_add_property(subject, predicate, object);
if(rv < 0) {
raptor_serializer_error(serializer,
"Unable to add properties to subject %p\n",
subject);
return rv;
}
} else if(statement->predicate_type == RAPTOR_IDENTIFIER_TYPE_ORDINAL) {
int idx = *(int*)statement->predicate;
rv = raptor_abbrev_subject_add_list_element(subject, idx, object);
if(rv) {
/* An ordinal might already exist at that location, the fallback
* is to just put in the properties list */
predicate = raptor_abbrev_node_lookup(context->nodes,
statement->predicate_type,
statement->predicate, NULL, NULL,
&predicate_created);
if(!predicate)
return 1;
rv = raptor_abbrev_subject_add_property(subject, predicate, object);
if(rv < 0) {
raptor_serializer_error(serializer,
"Unable to add properties to subject %p\n",
subject);
return rv;
}
}
} else {
raptor_serializer_error(serializer,
"Do not know how to serialize node type %d\n",
statement->predicate_type);
return 1;
}
if(object_type == RAPTOR_IDENTIFIER_TYPE_RESOURCE ||
object_type == RAPTOR_IDENTIFIER_TYPE_ANONYMOUS)
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;
}
/* finish the serializer factory */
static void
raptor_turtle_serialize_finish_factory(raptor_serializer_factory* factory)
{
/* NOP */
}
static int
raptor_turtle_serializer_register_factory(raptor_serializer_factory *factory)
{
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(void)
{
return raptor_serializer_register_factory("turtle", "Turtle",
"application/x-turtle",
NULL,
(const unsigned char*)"http://www.dajobe.org/2004/01/turtle",
&raptor_turtle_serializer_register_factory);
}