aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/serd/serd.h14
-rw-r--r--src/cursor.c9
-rw-r--r--src/describe.c180
-rw-r--r--src/writer.c2
-rw-r--r--test/sort/GOPS.nq3
-rw-r--r--test/sort/GOSP.nq3
-rw-r--r--test/sort/GPSO.nq3
-rw-r--r--test/sort/GSOP.nq3
-rw-r--r--test/sort/GSPO.nq3
-rw-r--r--test/sort/OPS.nq3
-rw-r--r--test/sort/OSP.nq3
-rw-r--r--test/sort/POS.nq3
-rw-r--r--test/sort/PSO.nq3
-rw-r--r--test/sort/SOP.nq3
-rw-r--r--test/sort/SPO.nq3
-rw-r--r--test/sort/input.trig27
-rw-r--r--test/sort/pretty.nq3
-rw-r--r--test/sort/untyped.nq12
-rwxr-xr-xtest/test_sort.py16
-rw-r--r--tools/console.c1
-rw-r--r--tools/serd-sort.c8
21 files changed, 214 insertions, 91 deletions
diff --git a/include/serd/serd.h b/include/serd/serd.h
index 1f46e092..07f6b9f5 100644
--- a/include/serd/serd.h
+++ b/include/serd/serd.h
@@ -2523,7 +2523,14 @@ typedef enum {
particular invalid UTF-8 text. Note that this flag should be used
carefully, since it can result in data loss.
*/
- SERD_WRITE_LAX = 1u << 4u
+ SERD_WRITE_LAX = 1u << 4u,
+
+ /**
+ Write rdf:type as a normal predicate.
+
+ This disables the special "a" syntax in Turtle and TriG.
+ */
+ SERD_WRITE_RDF_TYPE = 1u << 5u
} SerdWriterFlag;
/// Bitwise OR of SerdWriterFlag values
@@ -2629,7 +2636,7 @@ serd_cursor_copy(const SerdCursor* SERD_NULLABLE cursor);
/// Return the statement pointed to by `cursor`
SERD_API
const SerdStatement* SERD_NULLABLE
-serd_cursor_get(const SerdCursor* SERD_NONNULL cursor);
+serd_cursor_get(const SerdCursor* SERD_NULLABLE cursor);
/**
Increment cursor to point to the next statement.
@@ -2671,7 +2678,8 @@ serd_cursor_free(SerdCursor* SERD_NULLABLE cursor);
/// Flags that control the style of a model serialisation
typedef enum {
- SERD_NO_INLINE_OBJECTS = 1u << 0u ///< Disable object inlining
+ SERD_NO_INLINE_OBJECTS = 1u << 0u, ///< Disable object inlining
+ SERD_NO_TYPE_FIRST = 1u << 1u ///< Disable writing rdf:type ("a") first
} SerdDescribeFlag;
/// Bitwise OR of SerdDescribeFlag values
diff --git a/src/cursor.c b/src/cursor.c
index 4213476e..650ac771 100644
--- a/src/cursor.c
+++ b/src/cursor.c
@@ -146,11 +146,10 @@ serd_cursor_copy(const SerdCursor* const cursor)
const SerdStatement*
serd_cursor_get(const SerdCursor* const cursor)
{
- assert(cursor);
-
- return ((!zix_btree_iter_is_end(cursor->iter) && check_version(cursor))
- ? (const SerdStatement*)zix_btree_get(cursor->iter)
- : NULL);
+ return (
+ (cursor && !zix_btree_iter_is_end(cursor->iter) && check_version(cursor))
+ ? (const SerdStatement*)zix_btree_get(cursor->iter)
+ : NULL);
}
SerdStatus
diff --git a/src/describe.c b/src/describe.c
index 718eaf1c..9328f261 100644
--- a/src/describe.c
+++ b/src/describe.c
@@ -29,17 +29,24 @@
#include <assert.h>
#include <stdbool.h>
-#include <stdlib.h>
+#include <stddef.h>
typedef enum { NAMED, ANON_S, ANON_O, LIST_S, LIST_O } NodeStyle;
+typedef struct {
+ const SerdModel* model; // Model to read from
+ const SerdSink* sink; // Sink to write description to
+ ZixHash* list_subjects; // Nodes written in the current list or null
+ SerdDescribeFlags flags; // Flags to control description
+} DescribeContext;
+
static SerdStatus
-write_range_statement(const SerdSink* sink,
- const SerdModel* model,
- ZixHash* list_subjects,
- unsigned depth,
- SerdStatementFlags flags,
- const SerdStatement* statement);
+write_range_statement(const DescribeContext* ctx,
+ unsigned depth,
+ SerdStatementFlags statement_flags,
+ const SerdStatement* statement,
+ const SerdNode* last_subject,
+ bool write_types);
static NodeStyle
get_node_style(const SerdModel* const model, const SerdNode* const node)
@@ -81,39 +88,41 @@ ptr_equals(const SerdNode* const a, const SerdNode* const b)
}
static SerdStatus
-write_pretty_range(const SerdSink* const sink,
- const unsigned depth,
- const SerdModel* const model,
- SerdCursor* const range)
+write_pretty_range(const DescribeContext* const ctx,
+ const unsigned depth,
+ SerdCursor* const range,
+ const SerdNode* last_subject,
+ bool write_types)
{
- ZixHash* const list_subjects = zix_hash_new(identity, ptr_hash, ptr_equals);
- SerdStatus st = SERD_SUCCESS;
-
- while (!st && !serd_cursor_is_end(range)) {
- const SerdStatement* const statement = serd_cursor_get(range);
- assert(statement);
+ SerdStatus st = SERD_SUCCESS;
+ const SerdStatement* statement = serd_cursor_get(range);
- if (!(st = write_range_statement(
- sink, model, list_subjects, depth, 0, statement))) {
- st = serd_cursor_advance(range);
+ while (statement) {
+ // Write this statement (and possibly more to describe anonymous nodes)
+ if ((st = write_range_statement(
+ ctx, depth, 0u, statement, last_subject, write_types))) {
+ break;
}
- }
- zix_hash_free(list_subjects);
+ // Update the last subject and advance the cursor
+ last_subject = serd_statement_subject(statement);
+ st = serd_cursor_advance(range);
+ statement = serd_cursor_get(range);
+ }
return st > SERD_FAILURE ? st : SERD_SUCCESS;
}
static SerdStatus
-write_list(const SerdSink* const sink,
- const SerdModel* const model,
- ZixHash* const list_subjects,
- const unsigned depth,
- SerdStatementFlags flags,
- const SerdNode* object,
- const SerdNode* const graph)
+write_list(const DescribeContext* const ctx,
+ const unsigned depth,
+ SerdStatementFlags flags,
+ const SerdNode* object,
+ const SerdNode* const graph)
{
+ const SerdModel* const model = ctx->model;
const SerdWorld* const world = model->world;
+ const SerdSink* const sink = ctx->sink;
const SerdNode* const rdf_first = world->rdf_first;
const SerdNode* const rdf_rest = world->rdf_rest;
const SerdNode* const rdf_nil = world->rdf_nil;
@@ -126,8 +135,7 @@ write_list(const SerdSink* const sink,
while (!st && !serd_node_equals(object, rdf_nil)) {
// Write rdf:first statement for this node
- if ((st = write_range_statement(
- sink, model, list_subjects, depth, flags, fs))) {
+ if ((st = write_range_statement(ctx, depth, flags, fs, NULL, false))) {
return st;
}
@@ -177,24 +185,47 @@ skip_range_statement(const SerdModel* const model,
}
static SerdStatus
-write_range_statement(const SerdSink* const sink,
- const SerdModel* const model,
- ZixHash* const list_subjects,
- const unsigned depth,
- SerdStatementFlags flags,
- const SerdStatement* SERD_NONNULL statement)
+write_subject_types(const DescribeContext* const ctx,
+ const unsigned depth,
+ const SerdNode* const subject,
+ const SerdNode* const graph)
{
- const SerdNode* const subject = serd_statement_subject(statement);
- const NodeStyle subject_style = get_node_style(model, subject);
- const SerdNode* const object = serd_statement_object(statement);
- const NodeStyle object_style = get_node_style(model, object);
- const SerdNode* const graph = serd_statement_graph(statement);
- SerdStatus st = SERD_SUCCESS;
+ SerdStatus st = SERD_SUCCESS;
+ SerdCursor* const t = serd_model_find(
+ ctx->model, subject, ctx->model->world->rdf_type, NULL, graph);
- if (subject_style == ANON_S) { // Write anonymous subject like "[] p o"
- flags |= SERD_EMPTY_S;
+ if (t) {
+ st = write_pretty_range(ctx, depth + 1, t, subject, true);
}
+ serd_cursor_free(t);
+ return st;
+}
+
+static bool
+types_first_for_subject(const DescribeContext* const ctx, const NodeStyle style)
+{
+ return style != LIST_S && !(ctx->flags & SERD_NO_TYPE_FIRST);
+}
+
+static SerdStatus
+write_range_statement(const DescribeContext* const ctx,
+ const unsigned depth,
+ SerdStatementFlags statement_flags,
+ const SerdStatement* SERD_NONNULL statement,
+ const SerdNode* SERD_NULLABLE last_subject,
+ const bool write_types)
+{
+ const SerdModel* const model = ctx->model;
+ const SerdSink* const sink = ctx->sink;
+ const SerdNode* const subject = serd_statement_subject(statement);
+ const NodeStyle subject_style = get_node_style(model, subject);
+ const SerdNode* const predicate = serd_statement_predicate(statement);
+ const SerdNode* const object = serd_statement_object(statement);
+ const NodeStyle object_style = get_node_style(model, object);
+ const SerdNode* const graph = serd_statement_graph(statement);
+ SerdStatus st = SERD_SUCCESS;
+
if (depth == 0u) {
if (skip_range_statement(model, statement)) {
return SERD_SUCCESS; // Skip subject that will be inlined elsewhere
@@ -202,9 +233,8 @@ write_range_statement(const SerdSink* const sink,
if (subject_style == LIST_S) {
// First write inline list subject, which this statement will follow
- if (zix_hash_insert(list_subjects, subject) != ZIX_STATUS_EXISTS) {
- st = write_list(
- sink, model, list_subjects, 2, flags | SERD_LIST_S, subject, graph);
+ if (zix_hash_insert(ctx->list_subjects, subject) != ZIX_STATUS_EXISTS) {
+ st = write_list(ctx, 2, statement_flags | SERD_LIST_S, subject, graph);
}
}
}
@@ -213,29 +243,42 @@ write_range_statement(const SerdSink* const sink,
return st;
}
- if (object_style == ANON_O) { // Write anonymous object like "[ ... ]"
- SerdCursor* const iter = serd_model_find(model, object, NULL, NULL, NULL);
+ // If this is a new subject, write types first if necessary
+ const bool types_first = types_first_for_subject(ctx, subject_style);
+ if (subject != last_subject && types_first) {
+ st = write_subject_types(ctx, depth, subject, graph);
+ }
- flags |= SERD_ANON_O;
- if (!(st = serd_sink_write_statement(sink, flags, statement))) {
- if (!(st = write_pretty_range(sink, depth + 1, model, iter))) {
- st = serd_sink_write_end(sink, object);
- }
- }
+ // Skip type statement if it would be written another time (just above)
+ if (subject_style != LIST_S && !write_types &&
+ serd_node_equals(predicate, model->world->rdf_type)) {
+ return st;
+ }
- serd_cursor_free(iter);
+ // Set up the flags for this statement
+ statement_flags |=
+ (((subject_style == ANON_S) * (SerdStatementFlags)SERD_EMPTY_S) |
+ ((object_style == ANON_O) * (SerdStatementFlags)SERD_ANON_O) |
+ ((object_style == LIST_O) * (SerdStatementFlags)SERD_LIST_O));
- } else if (object_style == LIST_O) { // Write list object like "( ... )"
- if (!(st =
- serd_sink_write_statement(sink, flags | SERD_LIST_O, statement))) {
- flags = flags & ~((unsigned)SERD_LIST_S);
+ // Finally write this statement
+ if ((st = serd_sink_write_statement(sink, statement_flags, statement))) {
+ return st;
+ }
- st =
- write_list(sink, model, list_subjects, depth + 1, flags, object, graph);
+ if (object_style == ANON_O) {
+ // Follow an anonymous object with its description like "[ ... ]"
+ SerdCursor* const iter = serd_model_find(model, object, NULL, NULL, NULL);
+
+ if (!(st = write_pretty_range(ctx, depth + 1, iter, last_subject, false))) {
+ st = serd_sink_write_end(sink, object);
}
- } else {
- st = serd_sink_write_statement(sink, flags, statement);
+ serd_cursor_free(iter);
+
+ } else if (object_style == LIST_O) {
+ // Follow a list object with its description like "( ... )"
+ st = write_list(ctx, depth + 1, 0u, object, graph);
}
return st;
@@ -264,7 +307,12 @@ serd_describe_range(const SerdCursor* const range,
}
}
} else {
- st = write_pretty_range(sink, 0, range->model, &copy);
+ DescribeContext ctx = {
+ range->model, sink, zix_hash_new(identity, ptr_hash, ptr_equals), flags};
+
+ st = write_pretty_range(&ctx, 0, &copy, NULL, (flags & SERD_NO_TYPE_FIRST));
+
+ zix_hash_free(ctx.list_subjects);
}
return st;
diff --git a/src/writer.c b/src/writer.c
index 30e09a4f..b7814158 100644
--- a/src/writer.c
+++ b/src/writer.c
@@ -841,7 +841,7 @@ write_uri_node(SerdWriter* const writer,
const char* node_str = serd_node_string(node);
const bool has_scheme = serd_uri_string_has_scheme(node_str);
if (supports_abbrev(writer)) {
- if (field == SERD_PREDICATE &&
+ if (!(writer->flags & SERD_WRITE_RDF_TYPE) && field == SERD_PREDICATE &&
serd_node_equals(node, writer->world->rdf_type)) {
return esink("a", 1, writer);
}
diff --git a/test/sort/GOPS.nq b/test/sort/GOPS.nq
index c7472e03..3d033b6e 100644
--- a/test/sort/GOPS.nq
+++ b/test/sort/GOPS.nq
@@ -1,10 +1,13 @@
_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "1"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "2"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
<http://example.org/s> <http://example.org/literal> "s1" <http://example.org/graph1> .
+_:b1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Anonymous> <http://example.org/graph1> .
+<http://example.org/s> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Subject> <http://example.org/graph1> .
_:b1 <http://example.org/with> <http://example.org/aProperty> <http://example.org/graph1> .
_:b1 <http://example.org/with> <http://example.org/orAnother> <http://example.org/graph1> .
_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> <http://example.org/graph1> .
<http://example.org/s> <http://example.org/blank> _:b1 <http://example.org/graph1> .
<http://example.org/s> <http://example.org/list> _:b2 <http://example.org/graph1> .
_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:b3 <http://example.org/graph1> .
+<http://example.org/a> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/OtherSubject> <http://example.org/graph2> .
<http://example.org/a> <http://example.org/b> <http://example.org/c> <http://example.org/graph2> .
diff --git a/test/sort/GOSP.nq b/test/sort/GOSP.nq
index c7472e03..3d033b6e 100644
--- a/test/sort/GOSP.nq
+++ b/test/sort/GOSP.nq
@@ -1,10 +1,13 @@
_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "1"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "2"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
<http://example.org/s> <http://example.org/literal> "s1" <http://example.org/graph1> .
+_:b1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Anonymous> <http://example.org/graph1> .
+<http://example.org/s> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Subject> <http://example.org/graph1> .
_:b1 <http://example.org/with> <http://example.org/aProperty> <http://example.org/graph1> .
_:b1 <http://example.org/with> <http://example.org/orAnother> <http://example.org/graph1> .
_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> <http://example.org/graph1> .
<http://example.org/s> <http://example.org/blank> _:b1 <http://example.org/graph1> .
<http://example.org/s> <http://example.org/list> _:b2 <http://example.org/graph1> .
_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:b3 <http://example.org/graph1> .
+<http://example.org/a> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/OtherSubject> <http://example.org/graph2> .
<http://example.org/a> <http://example.org/b> <http://example.org/c> <http://example.org/graph2> .
diff --git a/test/sort/GPSO.nq b/test/sort/GPSO.nq
index 1a858017..67e13aa7 100644
--- a/test/sort/GPSO.nq
+++ b/test/sort/GPSO.nq
@@ -7,4 +7,7 @@ _:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "1"^^<http://www.w3.org/
_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "2"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:b3 <http://example.org/graph1> .
_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> <http://example.org/graph1> .
+<http://example.org/s> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Subject> <http://example.org/graph1> .
+_:b1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Anonymous> <http://example.org/graph1> .
<http://example.org/a> <http://example.org/b> <http://example.org/c> <http://example.org/graph2> .
+<http://example.org/a> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/OtherSubject> <http://example.org/graph2> .
diff --git a/test/sort/GSOP.nq b/test/sort/GSOP.nq
index fc073a00..dbfcb7c1 100644
--- a/test/sort/GSOP.nq
+++ b/test/sort/GSOP.nq
@@ -1,10 +1,13 @@
<http://example.org/s> <http://example.org/literal> "s1" <http://example.org/graph1> .
+<http://example.org/s> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Subject> <http://example.org/graph1> .
<http://example.org/s> <http://example.org/blank> _:b1 <http://example.org/graph1> .
<http://example.org/s> <http://example.org/list> _:b2 <http://example.org/graph1> .
+_:b1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Anonymous> <http://example.org/graph1> .
_:b1 <http://example.org/with> <http://example.org/aProperty> <http://example.org/graph1> .
_:b1 <http://example.org/with> <http://example.org/orAnother> <http://example.org/graph1> .
_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "1"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:b3 <http://example.org/graph1> .
_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "2"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> <http://example.org/graph1> .
+<http://example.org/a> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/OtherSubject> <http://example.org/graph2> .
<http://example.org/a> <http://example.org/b> <http://example.org/c> <http://example.org/graph2> .
diff --git a/test/sort/GSPO.nq b/test/sort/GSPO.nq
index 726b1d42..5aab6e1e 100644
--- a/test/sort/GSPO.nq
+++ b/test/sort/GSPO.nq
@@ -1,10 +1,13 @@
<http://example.org/s> <http://example.org/blank> _:b1 <http://example.org/graph1> .
<http://example.org/s> <http://example.org/list> _:b2 <http://example.org/graph1> .
<http://example.org/s> <http://example.org/literal> "s1" <http://example.org/graph1> .
+<http://example.org/s> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Subject> <http://example.org/graph1> .
_:b1 <http://example.org/with> <http://example.org/aProperty> <http://example.org/graph1> .
_:b1 <http://example.org/with> <http://example.org/orAnother> <http://example.org/graph1> .
+_:b1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Anonymous> <http://example.org/graph1> .
_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "1"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:b3 <http://example.org/graph1> .
_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "2"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> <http://example.org/graph1> .
<http://example.org/a> <http://example.org/b> <http://example.org/c> <http://example.org/graph2> .
+<http://example.org/a> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/OtherSubject> <http://example.org/graph2> .
diff --git a/test/sort/OPS.nq b/test/sort/OPS.nq
index 456ade7f..593760be 100644
--- a/test/sort/OPS.nq
+++ b/test/sort/OPS.nq
@@ -1,6 +1,9 @@
_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "1"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "2"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
<http://example.org/s> <http://example.org/literal> "s1" <http://example.org/graph1> .
+_:b1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Anonymous> <http://example.org/graph1> .
+<http://example.org/a> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/OtherSubject> <http://example.org/graph2> .
+<http://example.org/s> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Subject> <http://example.org/graph1> .
_:b1 <http://example.org/with> <http://example.org/aProperty> <http://example.org/graph1> .
<http://example.org/a> <http://example.org/b> <http://example.org/c> <http://example.org/graph2> .
_:b1 <http://example.org/with> <http://example.org/orAnother> <http://example.org/graph1> .
diff --git a/test/sort/OSP.nq b/test/sort/OSP.nq
index 456ade7f..593760be 100644
--- a/test/sort/OSP.nq
+++ b/test/sort/OSP.nq
@@ -1,6 +1,9 @@
_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "1"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "2"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
<http://example.org/s> <http://example.org/literal> "s1" <http://example.org/graph1> .
+_:b1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Anonymous> <http://example.org/graph1> .
+<http://example.org/a> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/OtherSubject> <http://example.org/graph2> .
+<http://example.org/s> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Subject> <http://example.org/graph1> .
_:b1 <http://example.org/with> <http://example.org/aProperty> <http://example.org/graph1> .
<http://example.org/a> <http://example.org/b> <http://example.org/c> <http://example.org/graph2> .
_:b1 <http://example.org/with> <http://example.org/orAnother> <http://example.org/graph1> .
diff --git a/test/sort/POS.nq b/test/sort/POS.nq
index 51c675de..20eabfe1 100644
--- a/test/sort/POS.nq
+++ b/test/sort/POS.nq
@@ -8,3 +8,6 @@ _:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "1"^^<http://www.w3.org/
_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "2"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> <http://example.org/graph1> .
_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:b3 <http://example.org/graph1> .
+_:b1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Anonymous> <http://example.org/graph1> .
+<http://example.org/a> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/OtherSubject> <http://example.org/graph2> .
+<http://example.org/s> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Subject> <http://example.org/graph1> .
diff --git a/test/sort/PSO.nq b/test/sort/PSO.nq
index 0fb7bd68..113dd549 100644
--- a/test/sort/PSO.nq
+++ b/test/sort/PSO.nq
@@ -8,3 +8,6 @@ _:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "1"^^<http://www.w3.org/
_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "2"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:b3 <http://example.org/graph1> .
_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> <http://example.org/graph1> .
+<http://example.org/a> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/OtherSubject> <http://example.org/graph2> .
+<http://example.org/s> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Subject> <http://example.org/graph1> .
+_:b1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Anonymous> <http://example.org/graph1> .
diff --git a/test/sort/SOP.nq b/test/sort/SOP.nq
index 1692689c..7867eb24 100644
--- a/test/sort/SOP.nq
+++ b/test/sort/SOP.nq
@@ -1,7 +1,10 @@
+<http://example.org/a> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/OtherSubject> <http://example.org/graph2> .
<http://example.org/a> <http://example.org/b> <http://example.org/c> <http://example.org/graph2> .
<http://example.org/s> <http://example.org/literal> "s1" <http://example.org/graph1> .
+<http://example.org/s> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Subject> <http://example.org/graph1> .
<http://example.org/s> <http://example.org/blank> _:b1 <http://example.org/graph1> .
<http://example.org/s> <http://example.org/list> _:b2 <http://example.org/graph1> .
+_:b1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Anonymous> <http://example.org/graph1> .
_:b1 <http://example.org/with> <http://example.org/aProperty> <http://example.org/graph1> .
_:b1 <http://example.org/with> <http://example.org/orAnother> <http://example.org/graph1> .
_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "1"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
diff --git a/test/sort/SPO.nq b/test/sort/SPO.nq
index 508debc7..2b09a976 100644
--- a/test/sort/SPO.nq
+++ b/test/sort/SPO.nq
@@ -1,9 +1,12 @@
<http://example.org/a> <http://example.org/b> <http://example.org/c> <http://example.org/graph2> .
+<http://example.org/a> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/OtherSubject> <http://example.org/graph2> .
<http://example.org/s> <http://example.org/blank> _:b1 <http://example.org/graph1> .
<http://example.org/s> <http://example.org/list> _:b2 <http://example.org/graph1> .
<http://example.org/s> <http://example.org/literal> "s1" <http://example.org/graph1> .
+<http://example.org/s> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Subject> <http://example.org/graph1> .
_:b1 <http://example.org/with> <http://example.org/aProperty> <http://example.org/graph1> .
_:b1 <http://example.org/with> <http://example.org/orAnother> <http://example.org/graph1> .
+_:b1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Anonymous> <http://example.org/graph1> .
_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "1"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:b3 <http://example.org/graph1> .
_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "2"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
diff --git a/test/sort/input.trig b/test/sort/input.trig
index 154a9fb8..9561d9b8 100644
--- a/test/sort/input.trig
+++ b/test/sort/input.trig
@@ -1,19 +1,22 @@
@prefix eg: <http://example.org/> .
eg:graph1 {
-eg:s
- eg:blank [
- eg:with eg:aProperty ,
- eg:orAnother
- ] ;
- eg:list (
- 1
- 2
- ) ;
- eg:literal "s1" .
+ eg:s
+ a eg:Subject ;
+ eg:blank [
+ a eg:Anonymous ;
+ eg:with eg:aProperty ,
+ eg:orAnother
+ ] ;
+ eg:list (
+ 1
+ 2
+ ) ;
+ eg:literal "s1" .
}
eg:graph2 {
-eg:a
- eg:b eg:c .
+ eg:a
+ a eg:OtherSubject ;
+ eg:b eg:c .
}
diff --git a/test/sort/pretty.nq b/test/sort/pretty.nq
index 451247d4..97851b82 100644
--- a/test/sort/pretty.nq
+++ b/test/sort/pretty.nq
@@ -1,4 +1,6 @@
+<http://example.org/s> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Subject> <http://example.org/graph1> .
<http://example.org/s> <http://example.org/blank> _:b1 <http://example.org/graph1> .
+_:b1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Anonymous> <http://example.org/graph1> .
_:b1 <http://example.org/with> <http://example.org/aProperty> <http://example.org/graph1> .
_:b1 <http://example.org/with> <http://example.org/orAnother> <http://example.org/graph1> .
<http://example.org/s> <http://example.org/list> _:b2 <http://example.org/graph1> .
@@ -7,4 +9,5 @@ _:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:b3 <http://example.org/
_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "2"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> <http://example.org/graph1> .
<http://example.org/s> <http://example.org/literal> "s1" <http://example.org/graph1> .
+<http://example.org/a> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/OtherSubject> <http://example.org/graph2> .
<http://example.org/a> <http://example.org/b> <http://example.org/c> <http://example.org/graph2> .
diff --git a/test/sort/untyped.nq b/test/sort/untyped.nq
new file mode 100644
index 00000000..74625d7d
--- /dev/null
+++ b/test/sort/untyped.nq
@@ -0,0 +1,12 @@
+<http://example.org/s> <http://example.org/blank> _:b1 <http://example.org/graph1> .
+_:b1 <http://example.org/with> <http://example.org/aProperty> <http://example.org/graph1> .
+_:b1 <http://example.org/with> <http://example.org/orAnother> <http://example.org/graph1> .
+<http://example.org/s> <http://example.org/list> _:b2 <http://example.org/graph1> .
+_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "1"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
+_:b2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:b3 <http://example.org/graph1> .
+_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "2"^^<http://www.w3.org/2001/XMLSchema#integer> <http://example.org/graph1> .
+_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> <http://example.org/graph1> .
+<http://example.org/s> <http://example.org/literal> "s1" <http://example.org/graph1> .
+<http://example.org/s> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Subject> <http://example.org/graph1> .
+<http://example.org/a> <http://example.org/b> <http://example.org/c> <http://example.org/graph2> .
+<http://example.org/a> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/OtherSubject> <http://example.org/graph2> .
diff --git a/test/test_sort.py b/test/test_sort.py
index 4080b93c..04c8ba10 100755
--- a/test/test_sort.py
+++ b/test/test_sort.py
@@ -28,15 +28,17 @@ collations = [
]
-def check(test_dir, command_prefix, out_dir, input_path, name):
+def check(test_dir, command_prefix, out_dir, input_path, name, flags=None):
"""Sort a single input in the named order and check the output.
- The expected output is assumed to exist at test_dir/NAME.nq.
+ The expected output is assumed to exist at test_dir/NAME.untyped.nq.
"""
output_path = os.path.join(out_dir, name + ".nq")
result_path = os.path.join(test_dir, name + ".nq")
- options = [] if name == "pretty" else ["-c", name]
+ options = flags if flags is not None else []
+ if name not in ["pretty", "untyped"]:
+ options += ["-c", name]
# Randomly add irrelevant options just to cover them
if random.choice([True, False]):
@@ -68,10 +70,18 @@ def run_tests(test_dir, command_prefix, out_dir):
input_trig = os.path.join(test_dir, "input.trig")
n_failures = 0
+
+ # Test all the basic collations, and "pretty" with type first
for name in collations:
if not check(test_dir, command_prefix, out_dir, input_trig, name):
n_failures += 1
+ # Test "pretty" without type first
+ if not check(
+ test_dir, command_prefix, out_dir, input_trig, "untyped", ["-t"]
+ ):
+ n_failures += 1
+
return n_failures
diff --git a/tools/console.c b/tools/console.c
index f1e78d75..d7f67c35 100644
--- a/tools/console.c
+++ b/tools/console.c
@@ -218,6 +218,7 @@ serd_set_output_option(const SerdStringView name,
{"verbatim", SERD_WRITE_VERBATIM},
{"terse", SERD_WRITE_TERSE},
{"lax", SERD_WRITE_LAX},
+ {"rdf_type", SERD_WRITE_RDF_TYPE},
{NULL, SERD_WRITE_ASCII},
};
diff --git a/tools/serd-sort.c b/tools/serd-sort.c
index 8ba99445..5e71e95e 100644
--- a/tools/serd-sort.c
+++ b/tools/serd-sort.c
@@ -176,7 +176,8 @@ print_usage(const char* const name, const bool error)
" -c COLLATION An optional \"G\" then the letters \"SPO\" in any order.\n"
" -h Display this help and exit.\n"
" -k BYTES Parser stack size.\n"
- " -o FILENAME Write output to FILENAME instead of stdout.\n";
+ " -o FILENAME Write output to FILENAME instead of stdout.\n"
+ " -t Do not write type as \"a\" before other properties.\n";
FILE* const os = error ? stderr : stdout;
fprintf(os, "%s", error ? "\n" : "");
@@ -221,6 +222,11 @@ parse_option(OptionIter* const iter, Options* const opts)
case 's':
return serd_get_argument(iter, &opts->input_string);
+ case 't':
+ opts->common.output.flags |= SERD_WRITE_RDF_TYPE;
+ opts->flags |= SERD_NO_TYPE_FIRST;
+ return serd_option_iter_advance(iter);
+
default:
break;
}