From 2f51df8eed40bb808dce0ce1d5ba218a1b2b0071 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Mon, 24 Jun 2024 15:07:33 -0400 Subject: Fix rewriting special literals when datatype URIs are prefixed names --- src/writer.c | 45 ++++++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/writer.c b/src/writer.c index bea1efcd..08192bb1 100644 --- a/src/writer.c +++ b/src/writer.c @@ -647,6 +647,31 @@ reset_context(SerdWriter* writer, const unsigned flags) return SERD_SUCCESS; } +// Return the name of the XSD datatype referred to by `datatype`, if any +static const char* +get_xsd_name(const SerdEnv* const env, const SerdNode* const datatype) +{ + const char* const datatype_str = (const char*)datatype->buf; + + if (datatype->type == SERD_URI && + (!strncmp(datatype_str, NS_XSD, sizeof(NS_XSD) - 1))) { + return datatype_str + sizeof(NS_XSD) - 1U; + } + + if (datatype->type == SERD_CURIE) { + SerdChunk prefix = {NULL, 0}; + SerdChunk suffix = {NULL, 0}; + // We can be a bit lazy/presumptive here due to grammar limitations + if (!serd_env_expand(env, datatype, &prefix, &suffix)) { + if (!strcmp((const char*)prefix.buf, NS_XSD)) { + return (const char*)suffix.buf; + } + } + } + + return ""; +} + SERD_NODISCARD static SerdStatus write_literal(SerdWriter* writer, const SerdNode* node, @@ -657,21 +682,11 @@ write_literal(SerdWriter* writer, SerdStatus st = SERD_SUCCESS; if (supports_abbrev(writer) && datatype && datatype->buf) { - const char* type_uri = (const char*)datatype->buf; - if (!strncmp(type_uri, NS_XSD, sizeof(NS_XSD) - 1)) { - const char* const xsd_name = type_uri + sizeof(NS_XSD) - 1; - if (!strcmp(xsd_name, "boolean") || !strcmp(xsd_name, "integer")) { - return esink(node->buf, node->n_bytes, writer); - } - - if (!strcmp(xsd_name, "decimal") && strchr((const char*)node->buf, '.') && - node->buf[node->n_bytes - 1] != '.') { - /* xsd:decimal literals without trailing digits, e.g. "5.", can't be - written bare in Turtle. We could add a 0 which is prettier, but - changes the text and breaks round tripping. - */ - return esink(node->buf, node->n_bytes, writer); - } + const char* const xsd_name = get_xsd_name(writer->env, datatype); + if (!strcmp(xsd_name, "boolean") || !strcmp(xsd_name, "integer") || + (!strcmp(xsd_name, "decimal") && strchr((const char*)node->buf, '.') && + node->buf[node->n_bytes - 1] != '.')) { + return esink(node->buf, node->n_bytes, writer); } } -- cgit v1.2.1