Expand description

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. It can expand, compact and flatten JSON-LD documents backed by various JSON implementations thanks to the [generic-json] crate.

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, Loc, NoLoader, Document, Object, Reference};
use serde_json::Value;

#[async_std::main]
async fn main() -> Result<(), Loc<json_ld::Error, ()>> {
  // The JSON-LD document to expand.
  let doc: Value = serde_json::from_str(r#"
    {
      "@context": {
        "name": "http://xmlns.com/foaf/0.1/name"
      },
      "@id": "https://www.rust-lang.org",
      "name": "Rust Programming Language"
    }
  "#).unwrap();

  // 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("http://xmlns.com/foaf/0.1/name").unwrap());

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

  Ok(())
}

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.

Compaction

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

#[async_std::main]
async fn main() -> Result<(), Loc<json_ld::Error, ()>> {
  // Input JSON-LD document to compact.
  let input: Value = serde_json::from_str(r#"
    [{
      "http://xmlns.com/foaf/0.1/name": ["Timothée Haudebourg"],
      "http://xmlns.com/foaf/0.1/homepage": [{"@id": "https://haudebourg.net/"}]
    }]
  "#).unwrap();

  // JSON-LD context.
  let context: Value = serde_json::from_str(r#"
    {
      "name": "http://xmlns.com/foaf/0.1/name",
      "homepage": {"@id": "http://xmlns.com/foaf/0.1/homepage", "@type": "@id"}
    }
  "#).unwrap();

  // 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());

  Ok(())
}

Flattening

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" = "http://www.w3.org/2001/sw/DataAccess/tests/test-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 directly handled by this crate.

Re-exports

pub use compaction::Compact;
pub use loader::FsLoader;
pub use loader::Loader;
pub use loader::NoLoader;
pub use context::Context;
pub use context::ContextMut;
pub use context::ContextMutProxy;
pub use context::JsonContext;
pub use object::Node;
pub use object::Nodes;
pub use object::Object;
pub use object::Objects;
pub use object::Value;

Modules

Compaction algorithm and related types.

Context processing algorithm and related types.

Expansion algorithm and related types.

Nodes, lists and values.

Syntax elements.

Utility functions.

Structs

Blank node identifier.

Error type.

Result of the document expansion algorithm.

Indexed objects.

Raised when something tried to build a language string without language tag or direction.

Language string.

Value located behind an IRI reference.

Remote JSON-LD document.

Enums

Internationalized string direction.

Error code.

Language tag that may not be well-formed.

Language tag buffer that may not be well-formed.

Lexicon identifier.

Value that can be null.

Processing mode.

Node reference.

Warning that can occur during JSON-LD documents processing.

Traits

JSON-LD document.

Unique identifier types.

Types that can be converted into a borrowed node reference.

Vocabulary type.

Type Definitions

Document expansion error.