SERD_API SerdStatus serd_writer_end_anon(SerdWriter* writer, const SerdNode* node) { if (writer->syntax == SERD_NTRIPLES) { return SERD_SUCCESS; } if (serd_stack_is_empty(&writer->anon_stack) || writer->indent == 0) { w_err(writer, SERD_ERR_UNKNOWN, "unexpected end of anonymous node\n"); return SERD_ERR_UNKNOWN; } --writer->indent; write_sep(writer, SEP_ANON_END); reset_context(writer, true); writer->context = *anon_stack_top(writer); serd_stack_pop(&writer->anon_stack, sizeof(WriteContext)); const bool is_subject = serd_node_equals(node, &writer->context.subject); if (is_subject) { copy_node(&writer->context.subject, node); writer->context.predicate.type = SERD_NOTHING; } return SERD_SUCCESS; }
SERD_API SerdStatus serd_writer_end_anon(SerdWriter* writer, const SerdNode* node) { if (writer->syntax == SERD_NTRIPLES) { return SERD_SUCCESS; } if (serd_stack_is_empty(&writer->anon_stack)) { fprintf(stderr, "Unexpected end of anonymous node\n"); return SERD_ERR_UNKNOWN; } assert(writer->indent > 0); --writer->indent; serd_writer_write_delim(writer, '\n'); writer->sink("]", 1, writer->stream); reset_context(writer); writer->context = *anon_stack_top(writer); serd_stack_pop(&writer->anon_stack, sizeof(WriteContext)); const bool is_subject = serd_node_equals(node, &writer->context.subject); if (is_subject) { serd_node_free(&writer->context.predicate); writer->context.subject = serd_node_copy(node); writer->context.predicate = SERD_NODE_NULL; } return SERD_SUCCESS; }
static inline WriteContext* anon_stack_top(SerdWriter* writer) { assert(!serd_stack_is_empty(&writer->anon_stack)); return (WriteContext*)(writer->anon_stack.buf + writer->anon_stack.size - sizeof(WriteContext)); }
SERD_API SerdStatus serd_writer_write_statement(SerdWriter* writer, SerdStatementFlags flags, const SerdNode* graph, const SerdNode* subject, const SerdNode* predicate, const SerdNode* object, const SerdNode* datatype, const SerdNode* lang) { if (!subject || !predicate || !object || !subject->buf || !predicate->buf || !object->buf || !is_resource(subject) || !is_resource(predicate)) { return SERD_ERR_BAD_ARG; } #define TRY(write_result) \ if (!write_result) { \ return SERD_ERR_UNKNOWN; \ } switch (writer->syntax) { case SERD_NTRIPLES: TRY(write_node(writer, subject, NULL, NULL, FIELD_SUBJECT, flags)); sink(" ", 1, writer); TRY(write_node(writer, predicate, NULL, NULL, FIELD_PREDICATE, flags)); sink(" ", 1, writer); TRY(write_node(writer, object, datatype, lang, FIELD_OBJECT, flags)); sink(" .\n", 3, writer); return SERD_SUCCESS; default: break; } if ((flags & SERD_LIST_CONT)) { if (write_list_obj(writer, flags, predicate, object, datatype, lang)) { // Reached end of list if (--writer->list_depth == 0 && writer->list_subj.type) { reset_context(writer, true); writer->context.subject = writer->list_subj; writer->list_subj = SERD_NODE_NULL; } return SERD_SUCCESS; } } else if (serd_node_equals(subject, &writer->context.subject)) { if (serd_node_equals(predicate, &writer->context.predicate)) { // Abbreviate S P if (!(flags & SERD_ANON_O_BEGIN)) { ++writer->indent; } write_sep(writer, SEP_END_O); write_node(writer, object, datatype, lang, FIELD_OBJECT, flags); if (!(flags & SERD_ANON_O_BEGIN)) { --writer->indent; } } else { // Abbreviate S Sep sep = writer->context.predicate.type ? SEP_END_P : SEP_S_P; write_sep(writer, sep); write_pred(writer, flags, predicate); write_node(writer, object, datatype, lang, FIELD_OBJECT, flags); } } else { // No abbreviation if (writer->context.subject.type) { assert(writer->indent > 0); --writer->indent; if (serd_stack_is_empty(&writer->anon_stack)) { write_sep(writer, SEP_END_S); } } else if (!writer->empty) { write_sep(writer, SEP_S_P); } if (!(flags & SERD_ANON_CONT)) { write_node(writer, subject, NULL, NULL, FIELD_SUBJECT, flags); ++writer->indent; write_sep(writer, SEP_S_P); } else { ++writer->indent; } reset_context(writer, true); copy_node(&writer->context.subject, subject); if (!(flags & SERD_LIST_S_BEGIN)) { write_pred(writer, flags, predicate); } write_node(writer, object, datatype, lang, FIELD_OBJECT, flags); } if (flags & (SERD_ANON_S_BEGIN|SERD_ANON_O_BEGIN)) { WriteContext* ctx = (WriteContext*)serd_stack_push( &writer->anon_stack, sizeof(WriteContext)); *ctx = writer->context; WriteContext new_context = { serd_node_copy(graph), serd_node_copy(subject), SERD_NODE_NULL }; if ((flags & SERD_ANON_S_BEGIN)) { new_context.predicate = serd_node_copy(predicate); } writer->context = new_context; } else { copy_node(&writer->context.graph, graph); copy_node(&writer->context.subject, subject); copy_node(&writer->context.predicate, predicate); } return SERD_SUCCESS; }
SERD_API SerdStatus serd_writer_write_statement(SerdWriter* writer, SerdStatementFlags flags, const SerdNode* graph, const SerdNode* subject, const SerdNode* predicate, const SerdNode* object, const SerdNode* object_datatype, const SerdNode* object_lang) { assert(subject && predicate && object); switch (writer->syntax) { case SERD_NTRIPLES: write_node(writer, subject, NULL, NULL, FIELD_SUBJECT, flags); writer->sink(" ", 1, writer->stream); write_node(writer, predicate, NULL, NULL, FIELD_PREDICATE, flags); writer->sink(" ", 1, writer->stream); if (!write_node(writer, object, object_datatype, object_lang, FIELD_OBJECT, flags)) { return SERD_ERR_UNKNOWN; } writer->sink(" .\n", 3, writer->stream); return SERD_SUCCESS; case SERD_TURTLE: break; } if (serd_node_equals(subject, &writer->context.subject)) { if (serd_node_equals(predicate, &writer->context.predicate)) { // Abbreviate S P if ((flags & SERD_ANON_O_BEGIN)) { writer->sink(" , ", 3, writer->stream); // ] , [ } else { ++writer->indent; serd_writer_write_delim(writer, ','); } write_node(writer, object, object_datatype, object_lang, FIELD_OBJECT, flags); if (!(flags & SERD_ANON_O_BEGIN)) { --writer->indent; } } else { // Abbreviate S if (writer->context.predicate.buf) { serd_writer_write_delim(writer, ';'); } else { serd_writer_write_delim(writer, '\n'); } write_node(writer, predicate, NULL, NULL, FIELD_PREDICATE, flags); if (writer->context.predicate.buf) serd_node_free(&writer->context.predicate); writer->context.predicate = serd_node_copy(predicate); writer->sink(" ", 1, writer->stream); write_node(writer, object, object_datatype, object_lang, FIELD_OBJECT, flags); } } else { if (writer->context.subject.buf) { if (writer->indent > 0) { --writer->indent; } if (serd_stack_is_empty(&writer->anon_stack)) { serd_writer_write_delim(writer, '.'); serd_writer_write_delim(writer, '\n'); } } else if (!writer->empty) { serd_writer_write_delim(writer, '\n'); } if (!(flags & SERD_ANON_CONT)) { write_node(writer, subject, NULL, NULL, FIELD_SUBJECT, flags); ++writer->indent; if (!(flags & SERD_ANON_S_BEGIN)) { serd_writer_write_delim(writer, '\n'); } } else { ++writer->indent; } reset_context(writer); writer->context.subject = serd_node_copy(subject); writer->context.predicate = SERD_NODE_NULL; write_node(writer, predicate, NULL, NULL, FIELD_PREDICATE, flags); writer->context.predicate = serd_node_copy(predicate); writer->sink(" ", 1, writer->stream); write_node(writer, object, object_datatype, object_lang, FIELD_OBJECT, flags); } if (writer->syntax != SERD_NTRIPLES && ((flags & SERD_ANON_S_BEGIN) || (flags & SERD_ANON_O_BEGIN))) { WriteContext* ctx = (WriteContext*)serd_stack_push( &writer->anon_stack, sizeof(WriteContext)); *ctx = writer->context; writer->context = WRITE_CONTEXT_NULL; // Prevent deletion... } const WriteContext new_context = { serd_node_copy(graph), serd_node_copy(subject), serd_node_copy(predicate) }; reset_context(writer); // ... here writer->context = new_context; return SERD_SUCCESS; }