Skip to content
tentrisPublic

About

rdf4cpp is a modern C++20 library providing basic RDF support.

Topics

Resources

Code of conduct

Contributing

Stars

38 stars

Watchers

6 watching

Forks

Repository files navigation

Read the Docs Conan GitHub Release GitHub License

rdf4cpp

rdf4cpp is a modern C++23 library providing basic RDF support.

The focus is correctness, performance and ease-of-use for basic building blocks like:

  • parsing, validating and writing RDF data (N-Triples, Turtle, N-Quads, TriG)
  • parsing and validating RDF/XML and JSON-LD (json-ld-1.1, see the users guide for the limitations)
  • Complete and extensible literal datatypes (validation, functions, operations, subtype and promotion casting, mapping to C++ types, error handling, ...)
  • Managing RDF nodes efficiently
  • Blank node scoping (e.g., for RDF datasets)

rdf4cpp is not a SPARQL engine or reasoning engine, although it provides very basic support for triple/quad pattern matching on RDF graphs/datasets. rdf4cpp rather provides the necessary primitives to implement such engines.

We implement the following W3C standards:

JSON-LD conformance

tests/parser/tests_JSON_LD_Parser.cpp runs the json-ld-streaming test suite. The tests below are deactivated there. Every entry names the reason.

Tests of json-ld-1.0. This parser implements json-ld-1.1 only, and each of these documents is either valid in 1.1 or needs a 1.0 processing mode:

test what it needs
0118 the generalized RDF flag, a blank node as predicate
e026, e071 1.0 term semantics, the same documents are the negative tests er43 and er44 in 1.1
e075 @vocab as a blank node identifier, deprecated in 1.1
c029 @propagate reported outside a scoped context
e115, e116 a relative IRI as a property with @vocab reported
ep02 the processing mode json-ld-1.0, conflicting with @version
er21 @container: @id reported, m001 and m002 cover the 1.1 behavior
er24, er32 a list inside a list reported, li01 and li02 cover the 1.1 behavior
er42 a redefined keyword reported
tn01 @type: @none reported

Missing features:

test what it needs
e077 an expandContext option on the parser, the document carries no context
js06 to js16, js19, js20, js21 canonicalization of rdf:JSON literals after RFC 8785

Different behavior on purpose:

test what it expects
wf01 to wf04, wf07, e111, e112 a triple with an invalid IRI dropped without a message. This parser reports a ParsingError for it, like the other parsers do.
wf05 a triple with an invalid language tag dropped without a message. This parser reports a ParsingError for it.
0035 the literal "9.9E0"^^xsd:integer, whose lexical form does not fit its datatype. rdf4cpp validates literals, the test above it covers the rest of the document.
se01 to se09 the key order of the streaming profile, @context before @id and before the properties. This parser reads the whole document before it expands it, so the key order does not change its result.

Open bug:

test cause
e109 IRIView takes the text before the first : as a scheme even when a ? or # comes first, so a fragment containing : is reported as an invalid scheme. The fix changes IRI resolution for every parser and needs its own version bump.

Example

#include <iostream>
#include <rdf4cpp.hpp>

int main() {
    using namespace ::rdf4cpp;
    using namespace ::rdf4cpp::shorthands;
    using namespace ::rdf4cpp::namespaces;
    using namespace ::rdf4cpp::datatypes;

    /// 1) basic dataset, graph and RDF node usage
    // using namespaces
    FOAF foaf{};                               // common, predefined namespace
    Namespace const ex{"http://example.com/"}; // self-declared namespace

    Dataset dataset;
    // populate a named graph in the dataset
    auto &graph = dataset.graph(IRI{"http://ex.com/MyGraph"});                                                  // IRI constructor
    graph.add({"http://example.com/Bob"_iri, "http://example.com/knows"_iri, "http://example.com/Alice"_iri});  // IRI shorthand
    graph.add({ex + "Alice", foaf + "knows", ex + "Bob"});                                                      // using namespaces
    graph.add({ex + "Bob", foaf + "name", "Bob"_xsd_string}); // Literal datatype shorthand

    // serialize the dataset as N-Quads
    std::cout << "Dataset as N-Quads: \n"
              << dataset << std::endl;

    // 2) Using datatypes and arithmetics
    // typed Literal instantiation
    auto const d = Literal::make_typed_from_value<xsd::Double>(2.3); // factory function
    auto const ui = 42_xsd_uint;         // Literal datatype shorthand
    auto const dec = "42.1"_xsd_decimal; // infinite precision decimals

    // basic arithmetics with automatic result type deduction
    auto const r1 = d * dec;            // double * decimal → double
    auto const r2 = (ui + dec).round(); // round(integer + decimal) → decimal

    std::cout << "Using XSD datatypes, functions and operators: \n"
              << std::format("{} * {} = {}\n", d, dec, r1)
              << std::format("ceil({} + {}) = {}", ui, dec, r2) << std::endl;

    return 0;
}

Using rdf4cpp

rdf4cpp is consumed via Conan 2 but it is not available via Conan Center. Instead, it can be found on the artifactory of the DICE Research Group.

You need the package manager conan installed and set up. You can add the DICE artifactory with:

conan remote add dice-group https://conan.dice-research.org/artifactory/api/conan/tentris

To use rdf4cpp, add it to your conanfile.txt:

[requires]
rdf4cpp/0.4.0

For getting started how to use rdf4cpp, check out the examples directory and refer to our documentation.

Developing rdf4cpp

Prerequisites

Dependencies are fetched by conan through the cmake-conan dependency provider, which cmake/conan_provider.cmake downloads and pins. No separate conan install is needed. You only need a conan profile and the DICE artifactory as remote:

conan profile detect
conan remote add dice-group https://conan.dice-research.org/artifactory/api/conan/tentris

Build and test

Everything is driven via CMakePresets.json:

cmake --preset dev
cmake --build --preset dev
ctest --preset dev

In CLion, set Settings | Advanced Settings | CMake | Automatically import CMake Presets to Build only, open the project as a folder and enable the presets you want under Settings | Build, Execution, Deployment | CMake.

By default, the presets use clang-21 and mold on Linux and gcc-14 on macOS (see cmake/toolchains). To use another compiler, set the CC and CXX environment variables before configuring, or add your own presets in a CMakeUserPresets.json.

Presets

preset build type notes
dev RelWithDebInfo tests and examples
debug Debug tests and examples
release Release library only
asan RelWithDebInfo address and undefined behavior, not on macOS
ci-* Debug see below

The ci-* presets are also workflow presets, which is how GitHub Actions invoke them and how you can reproduce a failing CI locally, as the build setup will match:

cmake --workflow --preset ci-static-sanitizer

To install the library to your system, run:

cmake --preset release
cmake --build --preset release
sudo cmake --install build/release

Limits for Datatypes

By default, unlimited precision datatypes are limited in accordance with https://www.w3.org/TR/xmlschema11-2/#partial-implementation .

For http://www.w3.org/2001/XMLSchema#integer (and the related: http://www.w3.org/2001/XMLSchema#nonNegativeInteger http://www.w3.org/2001/XMLSchema#positiveInteger http://www.w3.org/2001/XMLSchema#nonPositiveInteger http://www.w3.org/2001/XMLSchema#negativeInteger) this limit is a signed 128-bit integer with the usual range of [-2^127,2^127-1]

And http://www.w3.org/2001/XMLSchema#decimal is composed of the following parts: i/10^k, where i is a signed 128-bit integer ([-2^127,2^127-1]) and k is an unsigned 32-bit integer ([0,2^32-1]).

For http://www.w3.org/2001/XMLSchema#dateTime (and all derived types) there are 2 limits:

  • represented as a time point with nanosecond precision with a 128-bit signed integer
  • the year part alone in a 64-bit signed integer Both limits are enough to cover both the current best theories of the big bang and the projected heat death of the universe.

For http://www.w3.org/2001/XMLSchema#duration (and all derived types), both parts have a separate signed 64-bit integer and with it its associated limits. The seconds part of the duration supports nanosecond precision.

Additional CMake config options:

  • -DBUILD_EXAMPLES=ON/OFF [default: OFF]: Build the examples.
  • -DBUILD_TESTING=ON/OFF [default: OFF]: Build the tests.
  • -DBUILD_SHARED_LIBS=ON/OFF [default: OFF]: Build a shared library instead of a static one.

Supported Platforms

  • Linux distributions (x86-64, aarch64) (e.g. Ubuntu>=24.04, Fedora>=41, etc.) with:
    • gcc>=14 (libstdc++>=14; used with both GCC and Clang)
    • clang>=21
    • glibc>=2.35 or musl>=1.2.4
  • macOS (aarch64): macOS Sonoma (>=14) with GCC>=14 (via Homebrew)

Stability

API Stability

From version 0.1 onwards (before 1.0.0), all high-level public API that the average user is expected to interact with is considered stable. This includes basically everything, except what is in the rdf4cpp::storage and rdf4cpp::datatypes::registry namespaces. Should we ever break anything in these high-level interfaces, we will bump the minor version (for example, from 0.1.0 to 0.2.0).

ABI Stability

ABI stability is not guaranteed.

POBR Stability

The POBR (Persisted Object Binary Representation) version tracks on-disk format stability (e.g., with allocators like Metall). This includes everything in rdf4cpp::storage::identifiers but nothing else. The current POBR version can be retrieved via rdf4cpp::pobr_version.

About

rdf4cpp is a modern C++20 library providing basic RDF support.

Topics

Resources

Code of conduct

Contributing

Stars

38 stars

Watchers

6 watching

Forks

Releases

Used by

Contributors

Languages