1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
//! This crate is a Rust implementation of the
//! [JSON-LD](https://www.w3.org/TR/json-ld/)
//! data interchange format.
//!
//! [Linked Data (LD)](https://www.w3.org/standards/semanticweb/data)
//! is a [World Wide Web Consortium (W3C)](https://www.w3.org/)
//! initiative built upon standard Web technologies to create an
//! interrelated network of datasets across the Web.
//! The [JavaScript Object Notation (JSON)](https://tools.ietf.org/html/rfc7159) 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](https://www.w3.org/TR/json-ld11/#the-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`](https://crates.io/crates/reqwest) crate to load remote documents.
//! Note that `reqwest` requires the
//! [`tokio`](https://crates.io/crates/tokio) runtime to work.
//!
//! ### Compaction
//!
//! The `Document` trait also provides a `Document::compact` function to compact a document using a given context.
//!
//! ```
//! # use async_std::task;
//! # use iref::IriBuf;
//! # use json_ld::{context::{self, Local}, Loc, NoLoader, Document, Object, Reference};
//! # use serde_json::Value;
//! #[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;
//! # use serde_json::Value;
//!
//! // 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`](https://crates.io/crates/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.
#![allow(clippy::derive_hash_xor_eq)]
#![feature(generic_associated_types)]
#![feature(trait_alias)]
extern crate iref;
extern crate log;
mod blank;
pub mod compaction;
pub mod context;
mod direction;
mod document;
mod error;
pub mod expansion;
mod id;
mod indexed;
mod lang;
pub mod loader;
mod loc;
mod mode;
mod null;
pub mod object;
mod reference;
pub mod syntax;
pub mod util;
mod vocab;
mod warning;
#[cfg(feature = "reqwest-loader")]
pub mod reqwest;
pub use blank::*;
pub use compaction::Compact;
pub use direction::*;
pub use document::*;
pub use error::*;
pub use id::*;
pub use indexed::*;
pub use lang::*;
pub use loader::{FsLoader, Loader, NoLoader};
pub use loc::Loc;
pub use mode::*;
pub use null::*;
pub use reference::*;
pub use vocab::*;
pub use warning::*;
pub use context::{Context, ContextMut, ContextMutProxy, JsonContext};
pub use object::{Node, Nodes, Object, Objects, Value};