spruceid / treeldr

https://www.spruceid.dev/treeldr/treeldr-overview
Apache License 2.0
26 stars 3 forks source link

Rust × RDF #24

Open timothee-haudebourg opened 2 years ago

timothee-haudebourg commented 2 years ago

This is a tracking issue for the RDF loader generated in Rust. This loader should be able to load RDF documents in various formats (JSON-LD in particular) into a data structure generated from the TreeLDR layouts definitions.

Import from RDF dataset

Any data structure generated from TreeLDR should define a method to instantiate the data structure from an RDF dataset (using the grdf library). This would be the common representation for various input formats like JSON-LD.

Define static JSON-LD contexts

This is outside the direct scope of TreeLDR, but necessary to have the best experience with it. The goal here would be to statically define the set of known JSON-LD context as a type, that can then be used hen loading a JSON-LD document.

#[derive(JsonLdContext)]
pub enum Context {
  #[context("https://json-ld.org/contexts/person.jsonld")]
  Person,
  #[context("https://www.w3.org/2018/credentials/v1")]
  Credentials
}

pub struct StaticContextLoader;
pub struct UnknownContext(IriRefBuf);

impl json_ld::context::Loader for StaticContextLoader {
  type Error = UnknownContext;
  type Output = Context;

  fn load_context(&mut self, iri: Iri) -> Result<Context, UnknownContext> {
    if iri == iri!("https://json-ld.org/contexts/person.jsonld") {
      Ok(Context::Person)
    } else if iri == iri!("https://www.w3.org/2018/credentials/v1") {
      Ok(Context::Credentials)
    } else {
      Err(UnknownContext)
    }
  }
}

Import from JSON-LD

Once static contexts defined, one should be able to load a JSON-LD document like so:

#[treeldr("example.tldr")]
mod schema {
   #[prefix("https://example.com/")]
   pub example;
}

fn main() {
  let json_ld_input = json_ld::load("input.json-ld").unwrap();
  let doc = json_ld_input.expand::<Context, _>(&mut StaticContextLoader).unwrap();
  let dataset: grdf::HashDataset = doc.rdf_quads().into();
  let instance = schema::example::Type::import(dataset, node_id).unwrap();

  ...
}

One open question is how to get the identifier (an IRI or blank node identifier) node_id of the node we want to import from the dataset. It correspond to the top level objects in a JSON-LD document. For now it can be manually fetched once the JSON-LD document is expanded. One just need to be sure to manually assign a blank node id to anonymous nodes or else a random one will be assigned in the dataset, and will be harder to find. We may need to write a helper function to do all that.

Type traits

In addition to type definition, it is possible for TreeLDR to define a trait for each TreeLDR type, implemented by each of its Rust layout-type. This can add a level of abstraction. This would also be the way of translating the RDF type hierarchy in Rust.

timothee-haudebourg commented 2 years ago

The JSON-LD part requires timothee-haudebourg/json-ld/pull/37 to be done.