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};