Beispiel #1
0
SERD_API
SerdNode
serd_node_new_uri(const SerdURI* uri, const SerdURI* base, SerdURI* out)
{
	SerdURI abs_uri = *uri;
	if (base) {
		serd_uri_resolve(uri, base, &abs_uri);
	}

	const size_t len = serd_uri_string_length(&abs_uri);
	uint8_t*     buf = (uint8_t*)malloc(len + 1);

	SerdNode node = { buf, len, len, 0, SERD_URI };  // FIXME: UTF-8

	uint8_t*     ptr        = buf;
	const size_t actual_len = serd_uri_serialise(&abs_uri, string_sink, &ptr);

	buf[actual_len] = '\0';
	node.n_bytes    = actual_len;
	node.n_chars    = actual_len;

	if (out) {
		serd_uri_parse(buf, out);  // TODO: cleverly avoid double parse
	}

	return node;
}
Beispiel #2
0
static bool
write_node(SerdWriter*        writer,
           const SerdNode*    node,
           const SerdNode*    datatype,
           const SerdNode*    lang,
           Field              field,
           SerdStatementFlags flags)
{
	SerdChunk uri_prefix;
	SerdChunk uri_suffix;
	bool      has_scheme;
	switch (node->type) {
	case SERD_BLANK:
		if (writer->syntax != SERD_NTRIPLES
		    && ((field == FIELD_SUBJECT && (flags & SERD_ANON_S_BEGIN))
		        || (field == FIELD_OBJECT && (flags & SERD_ANON_O_BEGIN)))) {
			++writer->indent;
			write_sep(writer, SEP_ANON_BEGIN);
		} else if (writer->syntax != SERD_NTRIPLES
		           && (field == FIELD_SUBJECT && (flags & SERD_LIST_S_BEGIN))) {
			assert(writer->list_depth == 0);
			copy_node(&writer->list_subj, node);
			++writer->list_depth;
			++writer->indent;
			write_sep(writer, SEP_LIST_BEGIN);
		} else if (writer->syntax != SERD_NTRIPLES
		           && (field == FIELD_OBJECT && (flags & SERD_LIST_O_BEGIN))) {
			++writer->indent;
			++writer->list_depth;
			write_sep(writer, SEP_LIST_BEGIN);
		} else if (writer->syntax != SERD_NTRIPLES
		           && ((field == FIELD_SUBJECT && (flags & SERD_EMPTY_S))
		               || (field == FIELD_OBJECT && (flags & SERD_EMPTY_O)))) {
			sink("[]", 2, writer);
		} else {
			sink("_:", 2, writer);
			if (writer->bprefix && !strncmp((const char*)node->buf,
			                                (const char*)writer->bprefix,
			                                writer->bprefix_len)) {
				sink(node->buf + writer->bprefix_len,
				     node->n_bytes - writer->bprefix_len,
				     writer);
			} else {
				sink(node->buf, node->n_bytes, writer);
			}
		}
		break;
	case SERD_CURIE:
		switch (writer->syntax) {
		case SERD_NTRIPLES:
			if (serd_env_expand(writer->env, node, &uri_prefix, &uri_suffix)) {
				w_err(writer, SERD_ERR_BAD_CURIE,
				      "undefined namespace prefix `%s'\n", node->buf);
				return false;
			}
			sink("<", 1, writer);
			write_uri(writer, uri_prefix.buf, uri_prefix.len);
			write_uri(writer, uri_suffix.buf, uri_suffix.len);
			sink(">", 1, writer);
			break;
		case SERD_TURTLE:
			write_lname(writer, node->buf, node->n_bytes);
		}
		break;
	case SERD_LITERAL:
		if (writer->syntax == SERD_TURTLE && datatype && datatype->buf) {
			const char* type_uri = (const char*)datatype->buf;
			if (!strncmp(type_uri, NS_XSD, sizeof(NS_XSD) - 1) && (
				    !strcmp(type_uri + sizeof(NS_XSD) - 1, "boolean") ||
				    !strcmp(type_uri + sizeof(NS_XSD) - 1, "integer"))) {
				sink(node->buf, node->n_bytes, writer);
				break;
			} else if (!strcmp(type_uri + sizeof(NS_XSD) - 1, "decimal") &&
			           strchr((const char*)node->buf, '.') &&
			           node->buf[node->n_bytes - 1] != '.') {
				/* xsd:decimal literals without trailing digits, e.g. "5.", can
				   not be written bare in Turtle.  We could add a 0 which is
				   prettier, but changes the text and breaks round tripping.
				*/
				sink(node->buf, node->n_bytes, writer);
				break;
			}
		}
		if (writer->syntax != SERD_NTRIPLES
		    && (node->flags & (SERD_HAS_NEWLINE|SERD_HAS_QUOTE))) {
			sink("\"\"\"", 3, writer);
			write_text(writer, WRITE_LONG_STRING, node->buf, node->n_bytes);
			sink("\"\"\"", 3, writer);
		} else {
			sink("\"", 1, writer);
			write_text(writer, WRITE_STRING, node->buf, node->n_bytes);
			sink("\"", 1, writer);
		}
		if (lang && lang->buf) {
			sink("@", 1, writer);
			sink(lang->buf, lang->n_bytes, writer);
		} else if (datatype && datatype->buf) {
			sink("^^", 2, writer);
			write_node(writer, datatype, NULL, NULL, FIELD_NONE, flags);
		}
		break;
	case SERD_URI:
		has_scheme = serd_uri_string_has_scheme(node->buf);
		if (field == FIELD_PREDICATE && (writer->syntax == SERD_TURTLE)
		    && !strcmp((const char*)node->buf, NS_RDF "type")) {
			sink("a", 1, writer);
			break;
		} else if ((writer->syntax == SERD_TURTLE)
		           && !strcmp((const char*)node->buf, NS_RDF "nil")) {
			sink("()", 2, writer);
			break;
		} else if (has_scheme && (writer->style & SERD_STYLE_CURIED)) {
			SerdNode  prefix;
			SerdChunk suffix;
			if (serd_env_qualify(writer->env, node, &prefix, &suffix)) {
				write_uri(writer, prefix.buf, prefix.n_bytes);
				sink(":", 1, writer);
				write_uri(writer, suffix.buf, suffix.len);
				break;
			}
		}
		sink("<", 1, writer);
		if (writer->style & SERD_STYLE_RESOLVED) {
			SerdURI in_base_uri, uri, abs_uri;
			serd_env_get_base_uri(writer->env, &in_base_uri);
			serd_uri_parse(node->buf, &uri);
			serd_uri_resolve(&uri, &in_base_uri, &abs_uri);
			bool rooted = uri_is_under(&writer->base_uri, &writer->root_uri);
			SerdURI* root = rooted ? &writer->root_uri : & writer->base_uri;
			if (!uri_is_under(&abs_uri, root) ||
			    writer->syntax == SERD_NTRIPLES) {
				serd_uri_serialise(&abs_uri, uri_sink, writer);
			} else {
				serd_uri_serialise_relative(
					&uri, &writer->base_uri, root, uri_sink, writer);
			}
		} else {
			write_uri(writer, node->buf, node->n_bytes);
		}
		sink(">", 1, writer);
	default:
		break;
	}
	writer->last_sep = SEP_NONE;
	return true;
}
Beispiel #3
0
static bool
write_node(SerdWriter*        writer,
           const SerdNode*    node,
           const SerdNode*    datatype,
           const SerdNode*    lang,
           Field              field,
           SerdStatementFlags flags)
{
	SerdChunk uri_prefix;
	SerdChunk uri_suffix;
	switch (node->type) {
	case SERD_NOTHING:
		return false;
	case SERD_BLANK:
		if (writer->syntax != SERD_NTRIPLES
		    && ((field == FIELD_SUBJECT && (flags & SERD_ANON_S_BEGIN))
		        || (field == FIELD_OBJECT && (flags & SERD_ANON_O_BEGIN)))) {
			++writer->indent;
			serd_writer_write_delim(writer, '[');
		} else if (writer->syntax != SERD_NTRIPLES
		    && ((field == FIELD_SUBJECT && (flags & SERD_EMPTY_S))
		        || (field == FIELD_OBJECT && (flags & SERD_EMPTY_O)))) {
			writer->sink("[]", 2, writer->stream);
		} else {
			writer->sink("_:", 2, writer->stream);
			if (writer->bprefix && !strncmp((const char*)node->buf,
			                                (const char*)writer->bprefix,
			                                writer->bprefix_len)) {
				writer->sink(node->buf + writer->bprefix_len,
				             node->n_bytes - writer->bprefix_len,
				             writer->stream);
			} else {
				writer->sink(node->buf, node->n_bytes, writer->stream);
			}
		}
		break;
	case SERD_CURIE:
		switch (writer->syntax) {
		case SERD_NTRIPLES:
			if (serd_env_expand(writer->env, node, &uri_prefix, &uri_suffix)) {
				fprintf(stderr, "Undefined namespace prefix `%s'\n", node->buf);
				return false;
			}
			writer->sink("<", 1, writer->stream);
			write_text(writer, WRITE_URI, uri_prefix.buf, uri_prefix.len, '>');
			write_text(writer, WRITE_URI, uri_suffix.buf, uri_suffix.len, '>');
			writer->sink(">", 1, writer->stream);
			break;
		case SERD_TURTLE:
			writer->sink(node->buf, node->n_bytes, writer->stream);
		}
		break;
	case SERD_LITERAL:
		if (writer->syntax == SERD_TURTLE && datatype && datatype->buf) {
			// TODO: compare against NS_XSD prefix once
			if (!strcmp((const char*)datatype->buf,    NS_XSD "boolean")
			    || !strcmp((const char*)datatype->buf, NS_XSD "decimal")
			    || !strcmp((const char*)datatype->buf, NS_XSD "integer")) {
				writer->sink(node->buf, node->n_bytes, writer->stream);
				break;
			}
		}
		if (writer->syntax != SERD_NTRIPLES
		    && ((node->flags & SERD_HAS_NEWLINE)
		        || (node->flags & SERD_HAS_QUOTE))) {
			writer->sink("\"\"\"", 3, writer->stream);
			write_text(writer, WRITE_LONG_STRING,
			           node->buf, node->n_bytes, '\0');
			writer->sink("\"\"\"", 3, writer->stream);
		} else {
			writer->sink("\"", 1, writer->stream);
			write_text(writer, WRITE_STRING, node->buf, node->n_bytes, '"');
			writer->sink("\"", 1, writer->stream);
		}
		if (lang && lang->buf) {
			writer->sink("@", 1, writer->stream);
			writer->sink(lang->buf, lang->n_bytes, writer->stream);
		} else if (datatype && datatype->buf) {
			writer->sink("^^", 2, writer->stream);
			write_node(writer, datatype, NULL, NULL, FIELD_NONE, flags);
		}
		break;
	case SERD_URI:
		if ((writer->syntax == SERD_TURTLE)
		    && !strcmp((const char*)node->buf, NS_RDF "type")) {
			writer->sink("a", 1, writer->stream);
			return true;
		} else if ((writer->style & SERD_STYLE_CURIED)
		           && serd_uri_string_has_scheme(node->buf)) {
			SerdNode  prefix;
			SerdChunk suffix;
			if (serd_env_qualify(writer->env, node, &prefix, &suffix)) {
				write_text(writer, WRITE_URI, prefix.buf, prefix.n_bytes, '>');
				writer->sink(":", 1, writer->stream);
				write_text(writer, WRITE_URI, suffix.buf, suffix.len, '>');
				return true;
			}
		} else if ((writer->style & SERD_STYLE_RESOLVED)
		           && !serd_uri_string_has_scheme(node->buf)) {
			SerdURI uri;
			if (!serd_uri_parse(node->buf, &uri)) {
				SerdURI abs_uri;
				serd_uri_resolve(&uri, &writer->base_uri, &abs_uri);
				writer->sink("<", 1, writer->stream);
				serd_uri_serialise(&abs_uri, writer->sink, writer->stream);
				writer->sink(">", 1, writer->stream);
				return true;
			}
		}
		writer->sink("<", 1, writer->stream);
		write_text(writer, WRITE_URI, node->buf, node->n_bytes, '>');
		writer->sink(">", 1, writer->stream);
		return true;
	}
	return true;
}