static SerdStatus write_statement(SordModel* sord, SerdWriter* writer, SordQuad tup, SerdStatementFlags flags) { const SordNode* s = tup[SORD_SUBJECT]; const SordNode* p = tup[SORD_PREDICATE]; const SordNode* o = tup[SORD_OBJECT]; const SordNode* d = sord_node_get_datatype(o); const SerdNode* ss = sord_node_to_serd_node(s); const SerdNode* sp = sord_node_to_serd_node(p); const SerdNode* so = sord_node_to_serd_node(o); const SerdNode* sd = sord_node_to_serd_node(d); const char* lang_str = sord_node_get_language(o); size_t lang_len = lang_str ? strlen(lang_str) : 0; SerdNode language = SERD_NODE_NULL; if (lang_str) { language.type = SERD_LITERAL; language.n_bytes = lang_len; language.n_chars = lang_len; language.buf = (const uint8_t*)lang_str; }; // TODO: Subject abbreviation if (sord_node_is_inline_object(s) && !(flags & SERD_ANON_CONT)) { return SERD_SUCCESS; } SerdStatus st = SERD_SUCCESS; if (sord_node_is_inline_object(o)) { SordQuad sub_pat = { o, 0, 0, 0 }; SordIter* sub_iter = sord_find(sord, sub_pat); SerdStatementFlags start_flags = flags | ((sub_iter) ? SERD_ANON_O_BEGIN : SERD_EMPTY_O); st = serd_writer_write_statement( writer, start_flags, NULL, ss, sp, so, sd, &language); if (!st && sub_iter) { flags |= SERD_ANON_CONT; for (; !st && !sord_iter_end(sub_iter); sord_iter_next(sub_iter)) { SordQuad sub_tup; sord_iter_get(sub_iter, sub_tup); st = write_statement(sord, writer, sub_tup, flags); } sord_iter_free(sub_iter); serd_writer_end_anon(writer, so); } } else { st = serd_writer_write_statement( writer, flags, NULL, ss, sp, so, sd, &language); } return st; }
/** Create a new LilvNode from `node`, or return NULL if impossible */ LilvNode* lilv_node_new_from_node(LilvWorld* world, const SordNode* node) { if (!node) { return NULL; } LilvNode* result = NULL; SordNode* datatype_uri = NULL; LilvNodeType type = LILV_VALUE_STRING; size_t len = 0; switch (sord_node_get_type(node)) { case SORD_URI: result = (LilvNode*)malloc(sizeof(LilvNode)); result->world = (LilvWorld*)world; result->type = LILV_VALUE_URI; result->node = sord_node_copy(node); break; case SORD_BLANK: result = (LilvNode*)malloc(sizeof(LilvNode)); result->world = (LilvWorld*)world; result->type = LILV_VALUE_BLANK; result->node = sord_node_copy(node); break; case SORD_LITERAL: datatype_uri = sord_node_get_datatype(node); if (datatype_uri) { if (sord_node_equals(datatype_uri, world->uris.xsd_boolean)) type = LILV_VALUE_BOOL; else if (sord_node_equals(datatype_uri, world->uris.xsd_decimal) || sord_node_equals(datatype_uri, world->uris.xsd_double)) type = LILV_VALUE_FLOAT; else if (sord_node_equals(datatype_uri, world->uris.xsd_integer)) type = LILV_VALUE_INT; else if (sord_node_equals(datatype_uri, world->uris.xsd_base64Binary)) type = LILV_VALUE_BLOB; else LILV_ERRORF("Unknown datatype `%s'\n", sord_node_get_string(datatype_uri)); } result = lilv_node_new( world, type, (const char*)sord_node_get_string_counted(node, &len)); lilv_node_set_numerics_from_string(result, len); break; } return result; }
static int check_properties(SordModel* model, URIs* uris) { int st = 0; SordIter* i = sord_begin(model); for (; !sord_iter_end(i); sord_iter_next(i)) { SordQuad quad; sord_iter_get(i, quad); const SordNode* subj = quad[SORD_SUBJECT]; const SordNode* pred = quad[SORD_PREDICATE]; const SordNode* obj = quad[SORD_OBJECT]; bool is_any_property = false; SordIter* t = sord_search(model, pred, uris->rdf_type, NULL, NULL); for (; !sord_iter_end(t); sord_iter_next(t)) { if (is_descendant_of(model, uris, sord_iter_get_node(t, SORD_OBJECT), uris->rdf_Property, uris->rdfs_subClassOf)) { is_any_property = true; break; } } sord_iter_free(t); const bool is_ObjectProperty = sord_ask( model, pred, uris->rdf_type, uris->owl_ObjectProperty, 0); const bool is_FunctionalProperty = sord_ask( model, pred, uris->rdf_type, uris->owl_FunctionalProperty, 0); const bool is_InverseFunctionalProperty = sord_ask( model, pred, uris->rdf_type, uris->owl_InverseFunctionalProperty, 0); const bool is_DatatypeProperty = sord_ask( model, pred, uris->rdf_type, uris->owl_DatatypeProperty, 0); if (!is_any_property) { st = error("Use of undefined property", quad); } if (!sord_ask(model, pred, uris->rdfs_label, NULL, NULL)) { st = errorf("Property <%s> has no label\n", sord_node_get_string(pred)); } if (is_DatatypeProperty && sord_node_get_type(obj) != SORD_LITERAL) { st = error("Datatype property with non-literal value", quad); } if (is_ObjectProperty && sord_node_get_type(obj) == SORD_LITERAL) { st = error("Object property with literal value", quad); } if (is_FunctionalProperty && sord_count(model, subj, pred, NULL, NULL) > 1) { st = error("Functional property with several objects", quad); } if (is_InverseFunctionalProperty && sord_count(model, NULL, pred, obj, NULL) > 1) { st = error("Inverse functional property with several subjects", quad); } if (sord_node_equals(pred, uris->rdf_type) && !sord_ask(model, obj, uris->rdf_type, uris->rdfs_Class, NULL) && !sord_ask(model, obj, uris->rdf_type, uris->owl_Class, NULL)) { st = error("Type is not a rdfs:Class or owl:Class", quad); } if (sord_node_get_type(obj) == SORD_LITERAL && !literal_is_valid(model, uris, obj, sord_node_get_datatype(obj))) { st = error("Literal does not match datatype", quad); } SordIter* r = sord_search(model, pred, uris->rdfs_range, NULL, NULL); for (; !sord_iter_end(r); sord_iter_next(r)) { const SordNode* range = sord_iter_get_node(r, SORD_OBJECT); if (!check_type(model, uris, obj, range)) { st = error("Object not in property range", quad); fprintf(stderr, "note: Range is <%s>\n", sord_node_get_string(range)); } } sord_iter_free(r); SordIter* d = sord_search(model, pred, uris->rdfs_domain, NULL, NULL); if (d) { const SordNode* domain = sord_iter_get_node(d, SORD_OBJECT); if (!check_type(model, uris, subj, domain)) { st = error("Subject not in property domain", quad); fprintf(stderr, "note: Domain is <%s>\n", sord_node_get_string(domain)); } sord_iter_free(d); } } sord_iter_free(i); return st; }
static bool literal_is_valid(SordModel* model, const URIs* uris, const SordNode* literal, const SordNode* type) { if (!type) { return true; } /* Check that literal data is related to required type. We don't do a strict subtype check here because e.g. an xsd:decimal might be a valid xsd:unsignedInt, which the pattern checks will verify, but if the literal type is not related to the required type at all (e.g. xsd:decimal and xsd:string) there is a problem. */ const SordNode* datatype = sord_node_get_datatype(literal); if (datatype && datatype != type) { if (!is_descendant_of( model, uris, datatype, type, uris->owl_onDatatype) && !is_descendant_of( model, uris, type, datatype, uris->owl_onDatatype)) { errorf("Literal `%s' datatype <%s> is not compatible with <%s>\n", sord_node_get_string(literal), sord_node_get_string(datatype), sord_node_get_string(type)); return false; } } // Find restrictions list SordIter* rs = sord_search(model, type, uris->owl_withRestrictions, 0, 0); if (sord_iter_end(rs)) { return true; // No restrictions } // Walk list, checking each restriction const SordNode* head = sord_iter_get_node(rs, SORD_OBJECT); while (head) { SordIter* f = sord_search(model, head, uris->rdf_first, 0, 0); if (!f) { break; // Reached end of restrictions list without failure } // Check this restriction const bool good = check_restriction( model, uris, literal, type, sord_iter_get_node(f, SORD_OBJECT)); sord_iter_free(f); if (!good) { sord_iter_free(rs); return false; // Failed, literal is invalid } // Seek to next list node SordIter* n = sord_search(model, head, uris->rdf_rest, 0, 0); head = n ? sord_iter_get_node(n, SORD_OBJECT) : NULL; sord_iter_free(n); } sord_iter_free(rs); SordIter* s = sord_search(model, type, uris->owl_onDatatype, 0, 0); if (s) { const SordNode* super = sord_iter_get_node(s, SORD_OBJECT); const bool good = literal_is_valid(model, uris, literal, super); sord_iter_free(s); return good; // Match iff literal also matches supertype } return true; // Matches top level type }