Skip to content


Switch branches/tags

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time

A JSON-LD implementation for Rust

Documentation Crate informations Repository

This crate is a Rust implementation of the JSON-LD data interchange format.

Linked Data (LD) is a World Wide Web Consortium (W3C) initiative built upon standard Web technologies to create an interrelated network of datasets across the Web. The JavaScript Object Notation (JSON) is a widely used, simple, unstructured data serialization format to describe data objects in a human readable way. JSON-LD brings these two technologies together, adding semantics to JSON to create a lightweight data serialization format that can organize data and help Web applications to inter-operate at a large scale.

This crate aims to provide a set of types to build and process expanded JSON-LD documents. With the help of the json crate it can also expand, compact and flatten JSON-LD documents of any kind.

Basic Usage

JSON-LD documents are represented by the Document trait, implemented for instance by the json::JsonValue type. This trait represent compact JSON-LD documents that must be expanded in order to be processed. Expansion is done asynchronously through the Document::expand method by specifying an initial context, and document loader (which may be needed to load remote documents during expansion).

use async_std::task;
use iref::IriBuf;
use json_ld::{context, NoLoader, Document, Object, Reference};
use serde_json::Value;

async fn main() -> Result<(), json_ld::Error> {
  // The JSON-LD document to expand.
  let doc: Value = serde_json::from_str(r#"
      "@context": {
        "name": ""
      "@id": "",
      "name": "Rust Programming Language"

  // JSON document loader.
  let mut loader = NoLoader::<Value>::new();

  // Expansion.
  let expanded_doc = doc.expand::<context::Json<Value>, _>(&mut loader).await?;

  // Reference to the `name` property.
  let name_property = Reference::Id(IriBuf::new("").unwrap());

  // Iterate through the expanded objects.
  for object in expanded_doc {
    if let Object::Node(node) = object.as_ref() {
      println!("node: {}",; // print the `@id`
      for name in node.get(&name_property) { // get the names.
        println!("name: {}", name.as_str().unwrap());


This crate provides multiple loader implementations:

  • NoLoader that always fail. Useful when it is known in advance that the document expansion will not require external resources.
  • FsLoader to load remote resources from the file system through a mount point system.
  • reqwest::Loader provided by the reqwest-loader feature that uses the reqwest crate to load remote documents. Note that reqwest requires the tokio runtime to work.


The Document trait also provides a Document::compact function to compact a document using a given context.

async fn main() -> Result<(), json_ld::Error> {
  // Input JSON-LD document to compact.
  let input: Value = serde_json::from_str(r#"
      "": ["Timothée Haudebourg"],
      "": [{"@id": ""}]

  // JSON-LD context.
  let context: Value = serde_json::from_str(r#"
      "name": "",
      "homepage": {"@id": "", "@type": "@id"}

  // JSON document loader.
  let mut loader = NoLoader::<Value>::new();

  // Process the context.
  let processed_context = context.process::<context::Json<Value>, _>(&mut loader, None).await?;

  // Compact the input document.
  let output = input.compact(&processed_context, &mut loader).await.unwrap();
  println!("{}", serde_json::to_string_pretty(&output).unwrap());



Flattening is not yet implemented, but will be in the future.

Custom identifiers

Storing and comparing IRIs can be costly. This is why while JSON-LD uses IRIs to identify nodes and properties, this implementation allows you to use different data types, as long as they can be easily converted into IRIs (they implement the Id trait). One usage example is through the Vocab trait and Lexicon wrapper that can transform any enum type into an identifier type.

use iref_enum::IriEnum;
use json_ld::Lexicon;

// Vocabulary used in the implementation.
#[derive(IriEnum, Clone, Copy, PartialEq, Eq, Hash)]
#[iri_prefix("manifest" = "")]
pub enum MyVocab {
  #[iri("manifest:name")] Name,
  #[iri("manifest:entries")] Entries,
  #[iri("manifest:action")] Action,
  #[iri("manifest:result")] Result,

// A fully functional identifier type.
pub type Id = Lexicon<MyVocab>;

fn handle_node(node: &json_ld::Node<Value, Id>) {
  for name in node.get(MyVocab::Name) { // <- NOTE: we can directly use `MyVocab` here.
    println!("node name: {}", name.as_str().unwrap());

Note that we use the iref-enum crate that provides the IriEnum derive macro which automatically generate conversions between the MyVocab and iref::Iri types.

RDF Serialization/Deserialization

This is not and will not be handled directly by this crate.

Running the tests

The implementation currently passes the expansion test suite. It can be imported using the generate-expand-tests example:

$ git submodule init
$ git submodule update
$ cargo run --example generate-expand-tests > tests/
$ cargo run --example generate-compact-tests > tests/

This will checkout the JSON-LD test suite included in a submodule, and write the associated Rust test file tests/ Then use cargo test to run the tests. All the tests should pass except for the compaction test p004 (see #517 on the json-ld-api repository).


Many thanks to Spruce for sponsoring this project!


Licensed under either of

at your option.


Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.


JSON-LD implementation for Rust



Apache-2.0, MIT licenses found

Licenses found





Sponsor this project


No packages published

Contributors 4