json_ld/
lib.rs

1//! This crate is a Rust implementation of the
2//! [JSON-LD](https://www.w3.org/TR/json-ld/)
3//! data interchange format.
4//!
5//! [Linked Data (LD)](https://www.w3.org/standards/semanticweb/data)
6//! is a [World Wide Web Consortium (W3C)](https://www.w3.org/)
7//! initiative built upon standard Web technologies to create an
8//! interrelated network of datasets across the Web.
9//! The [JavaScript Object Notation (JSON)](https://tools.ietf.org/html/rfc7159) is
10//! a widely used, simple, unstructured data serialization format to describe
11//! data objects in a human readable way.
12//! JSON-LD brings these two technologies together, adding semantics to JSON
13//! to create a lightweight data serialization format that can organize data and
14//! help Web applications to inter-operate at a large scale.
15//!
16//! # Usage
17//!
18//! The entry point for this library is the [`JsonLdProcessor`] trait
19//! that provides an access to all the JSON-LD transformation algorithms
20//! (context processing, expansion, compaction, etc.).
21//! If you want to explore and/or transform [`ExpandedDocument`]s, you may also
22//! want to check out the [`Object`] type representing a JSON object.
23//!
24//! [`JsonLdProcessor`]: crate::JsonLdProcessor
25//!
26//! ## Expansion
27//!
28//! If you want to expand a JSON-LD document, first describe the document to
29//! be expanded using either [`RemoteDocument`] or [`RemoteDocumentReference`]:
30//!   - [`RemoteDocument`] wraps the JSON representation of the document
31//!     alongside its remote URL.
32//!   - [`RemoteDocumentReference`] may represent only an URL, letting
33//!     some loader fetching the remote document by dereferencing the URL.
34//!
35//! After that, you can simply use the [`JsonLdProcessor::expand`] function on
36//! the remote document.
37//!
38//! [`RemoteDocument`]: crate::RemoteDocument
39//! [`RemoteDocumentReference`]: crate::RemoteDocumentReference
40//! [`JsonLdProcessor::expand`]: JsonLdProcessor::expand
41//!
42//! ### Example
43//!
44//! ```
45//! use iref::IriBuf;
46//! use static_iref::iri;
47//! use json_ld::{JsonLdProcessor, Options, RemoteDocument, syntax::{Value, Parse}};
48//!
49//! # #[async_std::main]
50//! # async fn main() {
51//! // Create a "remote" document by parsing a file manually.
52//! let input = RemoteDocument::new(
53//!   // We use `IriBuf` as IRI type.
54//!   Some(iri!("https://example.com/sample.jsonld").to_owned()),
55//!
56//!   // Optional content type.
57//!   Some("application/ld+json".parse().unwrap()),
58//!   
59//!   // Parse the file.
60//!   Value::parse_str(r#"
61//!     {
62//!       "@context": {
63//!         "name": "http://xmlns.com/foaf/0.1/name"
64//!       },
65//!       "@id": "https://www.rust-lang.org",
66//!       "name": "Rust Programming Language"
67//!     }"#).expect("unable to parse file").0
68//! );
69//!
70//! // Use `NoLoader` as we won't need to load any remote document.
71//! let mut loader = json_ld::NoLoader;
72//!
73//! // Expand the "remote" document.
74//! let expanded = input
75//!   .expand(&mut loader)
76//!   .await
77//!   .expect("expansion failed");
78//!
79//! for object in expanded {
80//!   if let Some(id) = object.id() {
81//!     let name = object.as_node().unwrap()
82//!       .get_any(&iri!("http://xmlns.com/foaf/0.1/name")).unwrap()
83//!       .as_str().unwrap();
84//!
85//!     println!("id: {id}");
86//!     println!("name: {name}");
87//!   }
88//! }
89//! # }
90//! ```
91//!
92//! Here is another example using `RemoteDocumentReference`.
93//!
94//! ```
95//! use static_iref::iri;
96//! use json_ld::{JsonLdProcessor, Options, RemoteDocumentReference};
97//!
98//! # #[async_std::main]
99//! # async fn main() {
100//! let input = RemoteDocumentReference::iri(iri!("https://example.com/sample.jsonld").to_owned());
101//!
102//! // Use `FsLoader` to redirect any URL starting with `https://example.com/` to
103//! // the local `example` directory. No HTTP query.
104//! let mut loader = json_ld::FsLoader::default();
105//! loader.mount(iri!("https://example.com/").to_owned(), "examples");
106//!
107//! let expanded = input.expand(&mut loader)
108//!   .await
109//!   .expect("expansion failed");
110//! # }
111//! ```
112//!
113//! Lastly, the same example replacing [`IriBuf`] with the lightweight
114//! [`rdf_types::vocabulary::Index`] type.
115//!
116//! [`IriBuf`]: https://docs.rs/iref/latest/iref/struct.IriBuf.html
117//!
118//! ```
119//! # use static_iref::iri;
120//! # use json_ld::{JsonLdProcessor, Options, RemoteDocumentReference};
121//! use rdf_types::{Subject, vocabulary::{IriVocabularyMut, IndexVocabulary}};
122//! use contextual::WithContext;
123//! # #[async_std::main]
124//! # async fn main() {
125//! // Creates the vocabulary that will map each `rdf_types::vocabulary::Index`
126//! // to an actual `IriBuf`.
127//! let mut vocabulary: IndexVocabulary = IndexVocabulary::new();
128//!
129//! let iri_index = vocabulary.insert(iri!("https://example.com/sample.jsonld"));
130//! let input = RemoteDocumentReference::iri(iri_index);
131//!
132//! // Use `FsLoader` to redirect any URL starting with `https://example.com/` to
133//! // the local `example` directory. No HTTP query.
134//! let mut loader = json_ld::FsLoader::default();
135//! loader.mount(iri!("https://example.com/").to_owned(), "examples");
136//!
137//! let expanded = input
138//!   .expand_with(&mut vocabulary, &mut loader)
139//!   .await
140//!   .expect("expansion failed");
141//!
142//! // `foaf:name` property identifier.
143//! let name_id = Subject::Iri(vocabulary.insert(iri!("http://xmlns.com/foaf/0.1/name")));
144//!
145//! for object in expanded {
146//!   if let Some(id) = object.id() {
147//!     let name = object.as_node().unwrap()
148//!       .get_any(&name_id).unwrap()
149//!       .as_value().unwrap()
150//!       .as_str().unwrap();
151//!
152//!     println!("id: {}", id.with(&vocabulary));
153//!     println!("name: {name}");
154//!   }
155//! }
156//! # }
157//! ```
158//!
159//! ## Compaction
160//!
161//! The JSON-LD Compaction is a transformation that consists in applying a
162//! context to a given JSON-LD document reducing its size.
163//! There are two ways to get a compact JSON-LD document with this library
164//! depending on your starting point:
165//!   - If you want to get a compact representation for an arbitrary remote
166//!     document, simply use the [`JsonLdProcessor::compact`]
167//!     (or [`JsonLdProcessor::compact_with`]) method.
168//!   - Otherwise to compact an [`ExpandedDocument`] you can use the
169//!     [`Compact::compact`] method.
170//!
171//! [`JsonLdProcessor::compact`]: crate::JsonLdProcessor::compact
172//! [`JsonLdProcessor::compact_with`]: crate::JsonLdProcessor::compact_with
173//! [`ExpandedDocument`]: crate::ExpandedDocument
174//! [`Compact::compact`]: crate::Compact::compact
175//!
176//! ### Example
177//!
178//! Here is an example compaction an arbitrary [`RemoteDocumentReference`]
179//! using [`JsonLdProcessor::compact`].
180//!
181//! ```
182//! use static_iref::iri;
183//! use json_ld::{JsonLdProcessor, Options, RemoteDocumentReference, RemoteContextReference, syntax::Print};
184//!
185//! # #[async_std::main]
186//! # async fn main() {
187//! let input = RemoteDocumentReference::iri(iri!("https://example.com/sample.jsonld").to_owned());
188//!
189//! let context = RemoteContextReference::iri(iri!("https://example.com/context.jsonld").to_owned());
190//!
191//! // Use `FsLoader` to redirect any URL starting with `https://example.com/` to
192//! // the local `example` directory. No HTTP query.
193//! let mut loader = json_ld::FsLoader::default();
194//! loader.mount(iri!("https://example.com/").to_owned(), "examples");
195//!
196//! let compact = input
197//!   .compact(context, &mut loader)
198//!   .await
199//!   .expect("compaction failed");
200//!
201//! println!("output: {}", compact.pretty_print());
202//! # }
203//! ```
204//!
205//! ## Flattening
206//!
207//! The JSON-LD Flattening is a transformation that consists in moving nested
208//! nodes out. The result is a list of all the nodes declared in the document.
209//! There are two ways to flatten JSON-LD document with this library
210//! depending on your starting point:
211//!   - If you want to get a compact representation for an arbitrary remote
212//!     document, simply use the [`JsonLdProcessor::flatten`]
213//!     (or [`JsonLdProcessor::flatten_with`]) method.
214//!     This will return a JSON-LD document.
215//!   - Otherwise to compact an [`ExpandedDocument`] you can use the
216//!     [`Flatten::flatten`] (or [`Flatten::flatten_with`]) method.
217//!     This will return the list of nodes as a [`FlattenedDocument`].
218//!
219//! Flattening requires assigning an identifier to nested anonymous nodes,
220//! which is why the flattening functions take an [`rdf_types::MetaGenerator`]
221//! as parameter. This generator is in charge of creating new fresh identifiers
222//! (with their metadata). The most common generator is
223//! [`rdf_types::generator::Blank`] that creates blank node identifiers.
224//!
225//! [`JsonLdProcessor::flatten`]: crate::JsonLdProcessor::flatten
226//! [`JsonLdProcessor::flatten_with`]: crate::JsonLdProcessor::flatten_with
227//! [`Flatten::flatten`]: crate::Flatten::flatten
228//! [`Flatten::flatten_with`]: crate::Flatten::flatten_with
229//! [`FlattenedDocument`]: crate::FlattenedDocument
230//! [`rdf_types::MetaGenerator`]: https://docs.rs/rdf-types/latest/rdf_types/generator/trait.MetaGenerator.html
231//! [`rdf_types::generator::Blank`]: https://docs.rs/rdf-types/latest/rdf_types/generator/struct.Blank.html
232//!
233//! ### Example
234//!
235//! Here is an example compaction an arbitrary [`RemoteDocumentReference`]
236//! using [`JsonLdProcessor::flatten`].
237//!
238//! ```
239//! use static_iref::iri;
240//! use json_ld::{JsonLdProcessor, Options, RemoteDocumentReference, syntax::Print};
241//!
242//! # #[async_std::main]
243//! # async fn main() {
244//! let input = RemoteDocumentReference::iri(iri!("https://example.com/sample.jsonld").to_owned());
245//!
246//! // Use `FsLoader` to redirect any URL starting with `https://example.com/` to
247//! // the local `example` directory. No HTTP query.
248//! let mut loader = json_ld::FsLoader::default();
249//! loader.mount(iri!("https://example.com/").to_owned(), "examples");
250//!
251//! let mut generator = rdf_types::generator::Blank::new();
252//!
253//! let nodes = input
254//!   .flatten(&mut generator, &mut loader)
255//!   .await
256//!   .expect("flattening failed");
257//!
258//! println!("output: {}", nodes.pretty_print());
259//! # }
260//! ```
261//!
262//! # Fast IRIs and Blank Node Identifiers
263//!
264//! This library gives you the opportunity to use any datatype you want to
265//! represent IRIs an Blank Node Identifiers. Most types have them
266//! parameterized.
267//! To avoid unnecessary allocations and expensive comparisons, it is highly
268//! recommended to use a cheap, lightweight datatype such as
269//! [`rdf_types::vocabulary::Index`]. This type will represent each distinct
270//! IRI/blank node identifier with a unique index. In this case a
271//! [`rdf_types::IndexVocabulary`] that maps each index back/to its
272//! original IRI/Blank identifier representation can be passed to every
273//! function.
274//!
275//! You can also use your own index type, with your own
276//! [`rdf_types::Vocabulary`] implementation.
277//!
278//! [`rdf_types::vocabulary::Index`]: https://docs.rs/rdf-types/latest/rdf_types/vocabulary/struct.Index.html
279//! [`rdf_types::IndexVocabulary`]: https://docs.rs/rdf-types/latest/rdf_types/vocabulary/struct.IndexVocabulary.html
280//! [`rdf_types::Vocabulary`]: https://docs.rs/rdf-types/latest/rdf_types/vocabulary/trait.Vocabulary.html
281//!
282//! ## Displaying vocabulary-dependent values
283//!
284//! Since using vocabularies separates IRIs and Blank ids from their textual
285//! representation, it complicates displaying data using them.
286//! Fortunately many types defined by `json-ld` implement the
287//! [`contextual::DisplayWithContext`] trait that allow displaying value with
288//! a "context", which here would be the vocabulary.
289//! By importing the [`contextual::WithContext`] which provides the `with`
290//! method you can display such value like this:
291//! ```
292//! use static_iref::iri;
293//! use rdf_types::vocabulary::{IriVocabularyMut, IndexVocabulary};
294//! use contextual::WithContext;
295//!
296//! let mut vocabulary: IndexVocabulary = IndexVocabulary::new();
297//! let i = vocabulary.insert(iri!("https://docs.rs/contextual"));
298//! let value = rdf_types::Subject::Iri(i);
299//!
300//! println!("{}", value.with(&vocabulary))
301//! ```
302//!
303//! [`contextual::DisplayWithContext`]: https://docs.rs/contextual/latest/contextual/trait.DisplayWithContext.html
304//! [`contextual::WithContext`]: https://docs.rs/contextual/latest/contextual/trait.WithContext.html
305pub use json_ld_compaction as compaction;
306pub use json_ld_context_processing as context_processing;
307pub use json_ld_core::*;
308pub use json_ld_expansion as expansion;
309pub use json_ld_serialization as ser;
310pub use json_ld_syntax as syntax;
311
312pub use compaction::Compact;
313pub use context_processing::Process;
314pub use expansion::Expand;
315
316mod processor;
317pub use processor::*;
318
319#[doc(hidden)]
320pub use iref;
321pub use iref::{InvalidIri, Iri, IriBuf, IriRef, IriRefBuf};
322
323pub use rdf_types;
324pub use rdf_types::{BlankId, BlankIdBuf};