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.
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).
```rust use asyncstd::task; use iref::IriBuf; use jsonld::{context, NoLoader, Document, Object, Reference}; use ijson::IValue;
async fn main() -> Result<(), jsonld::Error> { // The JSON-LD document to expand. let doc: IValue = serdejson::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::
// Expansion.
let expanded_doc = doc.expand::
// 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 expandeddoc {
if let Object::Node(node) = object.asref() {
println!("node: {}", node.id().unwrap()); // print the @id
for name in node.get(&nameproperty) { // get the names.
println!("name: {}", name.asstr().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.
The Document
trait also provides a Document::compact
function to compact a document using a given context.
```rust
async fn main() -> Result<(), jsonld::Error> { // Input JSON-LD document to compact. let input: IValue = serdejson::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: IValue = serdejson::fromstr(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::
// Process the context.
let processed_context = context.process::
// Compact the input document. let output = input.compact(&processedcontext, &mut loader).await.unwrap(); println!("{}", serdejson::tostringpretty(&output).unwrap());
Ok(()) } ```
Flattening is not yet implemented, but will be in the future.
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.
```rust use irefenum::IriEnum; use jsonld::Lexicon;
// Vocabulary used in the implementation.
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
fn handlenode(node: &jsonld::NodeMyVocab
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.
This is not and will not be handled directly by this crate.
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/expand.rs
$ cargo run --example generate-compact-tests > tests/compact.rs
This will checkout the JSON-LD test suite included in a submodule,
and write the associated Rust test file tests/expand.rs
.
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.