zotonic_turtle
An Erlang RDF 1.1 Turtle parser and generator using the document and triple maps
from zotonic_rdf. Standard output prefixes come exclusively from
zotonic_rdf:namespaces/0, including the Zotonic predicate namespace. The parser
never fetches IRIs or reads referenced files: prefix/base directives only resolve
identifiers.
Quick start
Turtle = <<"@prefix schema: <https://schema.org/> . "
"<https://example.org/alice> schema:name \"Alice\" .">>,
{ok, Documents} = zotonic_turtle:parse(Turtle),
{ok, Output} = zotonic_turtle:generate(Documents),
{ok, Triples} = zotonic_turtle:parse_triples(Turtle),
{ok, Output2} = zotonic_turtle:generate_triples(Triples).
API
All operations return {ok, Result} or {error, Reason}. decode/1 and
encode/1 alias document parsing and generation.
parse/1,2 accepts UTF-8 iodata and returns a list of standard Zotonic document
maps with a standard @context. Explicit datatypes and lexical values survive;
blank-only graphs, shared blank nodes, and cycles are retained as separate
identified documents. RDF collections remain their underlying first/rest graph.
parse_triples/1,2 returns flat binary-keyed RDF triple maps with expanded IRIs.
The parser accepts prefix/base directives in both Turtle and SPARQL spelling,
Unicode IRIs and names, short/long quoted strings, language/datatype literals,
numeric/boolean literals, predicate/object lists, blank-node property lists,
and collections. Syntax errors include a line number where available.
Parsing options
| Option | Meaning | Default |
|---|---|---|
base |
Binary IRI used to resolve relative IRIs. | No base. |
prefixes |
Map of initial binary prefix names to namespace IRIs. | Empty map. |
max_depth |
Maximum nesting of collections and blank-node property lists. | 128. |
Relative IRIs need a base. To accept undeclared standard prefixes explicitly, pass
#{prefixes => zotonic_rdf:namespaces()}.
Generation and format limits
generate/1,2 accepts Zotonic/JSON-LD document maps. It uses zotonic_jsonld to
resolve the entire input context before RDF conversion, and accepts that
application's expansion options. External JSON-LD contexts are disabled by
default. Set allow_external_contexts => true explicitly to enable fetching or
custom loader callbacks; set it to false to disable them. The contexts option
can supply context documents in memory without enabling external loading.
These options apply to document generation; Turtle parsing itself performs no
external loading, regardless of IRI scheme.
{ok, Output} = zotonic_turtle:generate(Documents, #{allow_external_contexts => true}).
generate_triples/1 accepts expanded RDF triples directly. The writer emits sorted prefix declarations and one triple per
line, preserving literal lexical forms. It uses full IRIs where a standard
prefixed name cannot represent the IRI.
Turtle represents a single RDF graph. Named graphs, JSON-LD directional literals
and @json conversion are rejected explicitly. TriG and RDF 1.2 triple terms are
not part of this RDF 1.1 implementation.
JSON-LD interoperability
Both applications use the same document maps, so conversion needs no intermediate string format:
{ok, Documents} = zotonic_turtle:parse(Turtle),
{ok, Json} = zotonic_jsonld:generate(Documents),
{ok, ParsedDocuments} = zotonic_jsonld:parse(Json),
{ok, TurtleAgain} = zotonic_turtle:generate(ParsedDocuments).
Build and test
The Makefile downloads a local rebar3 when needed (requires curl). To use an
existing installation, pass its absolute path, for example
make REBAR="$(command -v rebar3)". GNU make is required; on systems whose
default make is not GNU make, the wrapper uses gmake. GitHub Actions runs
compilation, EUnit (including the vendored W3C cases), XRef and Dialyzer on
OTP 27, 28 and 29 for pushes and pull requests to main.
Requires Erlang/OTP 25 or later and rebar3. The dependency requirements include
zotonic_rdf 1.2.0 and zotonic_jsonld 1.0.0; JSON-LD requires
jsxrecord 2.3.0 or later within the 2.x series. For local JSON-LD development,
place that application in rebar3's _checkouts directory.
make
make test
make xref
make dialyzer
make doc
make doc generates ExDoc documentation in doc/, with the README as its
landing page. make edoc remains available for EDoc output.
The 313 W3C RDF 1.1 Turtle tests are vendored in
test/data/w3c-turtle, with the original manifest,
input/output fixtures and license. turtle_w3c_tests runs them by default, checks
positive and negative syntax, compares evaluation results modulo blank-node IDs,
and verifies writer round trips. W3C_TURTLE_TESTS can select another fixture
checkout. Application tests also cover document conversion and JSON-LD round trips.
License and provenance
Copyright 2026 Marc Worrell. The Erlang implementation and test runners use Apache-2.0; see NOTICE for attribution and references. This is an implementation written for Zotonic, not a port or direct transliteration of Jena or RDF.ex. Those projects provided API and serialization references; their implementation source is not included.
The vendored W3C fixtures retain their original copyright notices and their separate W3C licensing. The full W3C 3-clause BSD terms and source details are included alongside them.
The completed license review records the checked source headers, dependency metadata, pinned fixture revisions and redistribution notices. The fixtures are used under the BSD option for development testing; local test results do not constitute W3C conformance certification or endorsement.
References
The implementation follows the W3C Turtle grammar. API and serialization examples were checked in Apache Jena and Elixir's RDF.ex.