oxjsonld/
to_rdf.rs

1use crate::context::{
2    JsonLdLoadDocumentOptions, JsonLdProcessingMode, JsonLdRemoteDocument, JsonLdTermDefinition,
3};
4use crate::error::{JsonLdParseError, JsonLdSyntaxError};
5use crate::expansion::{JsonLdEvent, JsonLdExpansionConverter, JsonLdValue};
6use crate::{JsonLdProfile, JsonLdProfileSet};
7#[cfg(feature = "async-tokio")]
8use json_event_parser::TokioAsyncReaderJsonParser;
9use json_event_parser::{JsonEvent, ReaderJsonParser, SliceJsonParser};
10use oxiri::{Iri, IriParseError};
11use oxrdf::vocab::{rdf, xsd};
12use oxrdf::{BlankNode, GraphName, Literal, NamedNode, NamedNodeRef, NamedOrBlankNode, Quad};
13use std::error::Error;
14use std::fmt::Write;
15use std::io::Read;
16use std::panic::{RefUnwindSafe, UnwindSafe};
17use std::str;
18#[cfg(feature = "async-tokio")]
19use tokio::io::AsyncRead;
20
21/// A [JSON-LD](https://www.w3.org/TR/json-ld/) parser.
22///
23/// The parser is a work in progress.
24/// Only JSON-LD 1.0 is supported at the moment. JSON-LD 1.1 is not supported yet.
25///
26/// The parser supports two modes:
27/// - regular JSON-LD parsing that needs to buffer the full file into memory.
28/// - [Streaming JSON-LD](https://www.w3.org/TR/json-ld11-streaming/) that can avoid buffering in a few cases.
29///   To enable it call the [`with_profile(JsonLdProfile::Streaming)`](JsonLdParser::with_profile) method.
30///
31/// Count the number of people:
32/// ```
33/// use oxjsonld::JsonLdParser;
34/// use oxrdf::vocab::rdf;
35/// use oxrdf::NamedNodeRef;
36///
37/// let file = br#"{
38///     "@context": {"schema": "http://schema.org/"},
39///     "@graph": [
40///         {
41///             "@type": "schema:Person",
42///             "@id": "http://example.com/foo",
43///             "schema:name": "Foo"
44///         },
45///         {
46///             "@type": "schema:Person",
47///             "schema:name": "Bar"
48///         }
49///     ]
50/// }"#;
51///
52/// let schema_person = NamedNodeRef::new("http://schema.org/Person")?;
53/// let mut count = 0;
54/// for quad in JsonLdParser::new().for_reader(file.as_ref()) {
55///     let quad = quad?;
56///     if quad.predicate == rdf::TYPE && quad.object == schema_person.into() {
57///         count += 1;
58///     }
59/// }
60/// assert_eq!(2, count);
61/// # Result::<_, Box<dyn std::error::Error>>::Ok(())
62/// ```
63#[derive(Default, Clone)]
64#[must_use]
65pub struct JsonLdParser {
66    lenient: bool,
67    profile: JsonLdProfileSet,
68    base: Option<Iri<String>>,
69}
70
71impl JsonLdParser {
72    /// Builds a new [`JsonLdParser`].
73    #[inline]
74    pub fn new() -> Self {
75        Self::default()
76    }
77
78    /// Assumes the file is valid to make parsing faster.
79    ///
80    /// It will skip some validations.
81    ///
82    /// Note that if the file is actually not valid, broken RDF might be emitted by the parser.
83    #[inline]
84    pub fn lenient(mut self) -> Self {
85        self.lenient = true;
86        self
87    }
88
89    /// Assume the given profile(s) during parsing.
90    ///
91    /// If you set the [Streaming JSON-LD](https://www.w3.org/TR/json-ld11-streaming/) profile ([`JsonLdProfile::Streaming`]),
92    /// the parser will skip some buffering to make parsing faster and memory consumption lower.
93    ///
94    /// ```
95    /// use oxjsonld::{JsonLdParser, JsonLdProfile};
96    /// use oxrdf::vocab::rdf;
97    /// use oxrdf::NamedNodeRef;
98    ///
99    /// let file = br#"{
100    ///     "@context": {"schema": "http://schema.org/"},
101    ///     "@graph": [
102    ///         {
103    ///             "@type": "schema:Person",
104    ///             "@id": "http://example.com/foo",
105    ///             "schema:name": "Foo"
106    ///         }
107    ///     ]
108    /// }"#;
109    ///
110    /// let schema_person = NamedNodeRef::new("http://schema.org/Person")?;
111    /// let mut count = 0;
112    /// for quad in JsonLdParser::new()
113    ///     .with_profile(JsonLdProfile::Streaming)
114    ///     .for_slice(file)
115    /// {
116    ///     let quad = quad?;
117    ///     if quad.predicate == rdf::TYPE && quad.object == schema_person.into() {
118    ///         count += 1;
119    ///     }
120    /// }
121    /// assert_eq!(1, count);
122    /// # Result::<_, Box<dyn std::error::Error>>::Ok(())
123    /// ```
124    #[inline]
125    pub fn with_profile(mut self, profile: impl Into<JsonLdProfileSet>) -> Self {
126        self.profile = profile.into();
127        self
128    }
129
130    /// Base IRI to use when expanding the document.
131    ///
132    /// It corresponds to the [`base` option from the algorithm specification](https://www.w3.org/TR/json-ld-api/#dom-jsonldoptions-base).
133    #[inline]
134    pub fn with_base_iri(mut self, base_iri: impl Into<String>) -> Result<Self, IriParseError> {
135        self.base = Some(Iri::parse(base_iri.into())?);
136        Ok(self)
137    }
138
139    /// Parses a JSON-LD file from a [`Read`] implementation.
140    ///
141    /// Count the number of people:
142    /// ```
143    /// use oxjsonld::JsonLdParser;
144    /// use oxrdf::vocab::rdf;
145    /// use oxrdf::NamedNodeRef;
146    ///
147    /// let file = br#"{
148    ///     "@context": {"schema": "http://schema.org/"},
149    ///     "@graph": [
150    ///         {
151    ///             "@type": "schema:Person",
152    ///             "@id": "http://example.com/foo",
153    ///             "schema:name": "Foo"
154    ///         },
155    ///         {
156    ///             "@type": "schema:Person",
157    ///             "schema:name": "Bar"
158    ///         }
159    ///     ]
160    /// }"#;
161    ///
162    /// let schema_person = NamedNodeRef::new("http://schema.org/Person")?;
163    /// let mut count = 0;
164    /// for quad in JsonLdParser::new().for_reader(file.as_ref()) {
165    ///     let quad = quad?;
166    ///     if quad.predicate == rdf::TYPE && quad.object == schema_person.into() {
167    ///         count += 1;
168    ///     }
169    /// }
170    /// assert_eq!(2, count);
171    /// # Result::<_, Box<dyn std::error::Error>>::Ok(())
172    /// ```
173    pub fn for_reader<R: Read>(self, reader: R) -> ReaderJsonLdParser<R> {
174        ReaderJsonLdParser {
175            results: Vec::new(),
176            errors: Vec::new(),
177            inner: self.into_inner(),
178            json_parser: ReaderJsonParser::new(reader),
179        }
180    }
181
182    /// Parses a JSON-LD file from a [`AsyncRead`] implementation.
183    ///
184    /// Count the number of people:
185    /// ```
186    /// # #[tokio::main(flavor = "current_thread")]
187    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
188    /// use oxjsonld::JsonLdParser;
189    /// use oxrdf::vocab::rdf;
190    /// use oxrdf::NamedNodeRef;
191    ///
192    /// let file = br#"{
193    ///     "@context": {"schema": "http://schema.org/"},
194    ///     "@graph": [
195    ///         {
196    ///             "@type": "schema:Person",
197    ///             "@id": "http://example.com/foo",
198    ///             "schema:name": "Foo"
199    ///         },
200    ///         {
201    ///             "@type": "schema:Person",
202    ///             "schema:name": "Bar"
203    ///         }
204    ///     ]
205    /// }"#;
206    ///
207    /// let schema_person = NamedNodeRef::new("http://schema.org/Person")?;
208    /// let mut count = 0;
209    /// let mut parser = JsonLdParser::new().for_tokio_async_reader(file.as_ref());
210    /// while let Some(quad) = parser.next().await {
211    ///     let quad = quad?;
212    ///     if quad.predicate == rdf::TYPE && quad.object == schema_person.into() {
213    ///         count += 1;
214    ///     }
215    /// }
216    /// assert_eq!(2, count);
217    /// # Ok(())
218    /// # }
219    /// ```
220    #[cfg(feature = "async-tokio")]
221    pub fn for_tokio_async_reader<R: AsyncRead + Unpin>(
222        self,
223        reader: R,
224    ) -> TokioAsyncReaderJsonLdParser<R> {
225        TokioAsyncReaderJsonLdParser {
226            results: Vec::new(),
227            errors: Vec::new(),
228            inner: self.into_inner(),
229            json_parser: TokioAsyncReaderJsonParser::new(reader),
230        }
231    }
232
233    /// Parses a JSON-LD file from a byte slice.
234    ///
235    /// Count the number of people:
236    /// ```
237    /// use oxjsonld::JsonLdParser;
238    /// use oxrdf::vocab::rdf;
239    /// use oxrdf::NamedNodeRef;
240    ///
241    /// let file = br#"{
242    ///     "@context": {"schema": "http://schema.org/"},
243    ///     "@graph": [
244    ///         {
245    ///             "@type": "schema:Person",
246    ///             "@id": "http://example.com/foo",
247    ///             "schema:name": "Foo"
248    ///         },
249    ///         {
250    ///             "@type": "schema:Person",
251    ///             "schema:name": "Bar"
252    ///         }
253    ///     ]
254    /// }"#;
255    ///
256    /// let schema_person = NamedNodeRef::new("http://schema.org/Person")?;
257    /// let mut count = 0;
258    /// for quad in JsonLdParser::new().for_slice(file) {
259    ///     let quad = quad?;
260    ///     if quad.predicate == rdf::TYPE && quad.object == schema_person.into() {
261    ///         count += 1;
262    ///     }
263    /// }
264    /// assert_eq!(2, count);
265    /// # Result::<_, Box<dyn std::error::Error>>::Ok(())
266    /// ```
267    pub fn for_slice(self, slice: &[u8]) -> SliceJsonLdParser<'_> {
268        SliceJsonLdParser {
269            results: Vec::new(),
270            errors: Vec::new(),
271            inner: self.into_inner(),
272            json_parser: SliceJsonParser::new(slice),
273        }
274    }
275
276    fn into_inner(self) -> InternalJsonLdParser {
277        InternalJsonLdParser {
278            expansion: JsonLdExpansionConverter::new(
279                self.base,
280                self.profile.contains(JsonLdProfile::Streaming),
281                self.lenient,
282                JsonLdProcessingMode::JsonLd1_0,
283            ),
284            expended_events: Vec::new(),
285            to_rdf: JsonLdToRdfConverter {
286                state: vec![JsonLdToRdfState::Graph(Some(GraphName::DefaultGraph))],
287                lenient: self.lenient,
288            },
289            json_error: false,
290        }
291    }
292}
293
294/// Parses a JSON-LD file from a [`Read`] implementation.
295///
296/// Can be built using [`JsonLdParser::for_reader`].
297///
298/// Count the number of people:
299/// ```
300/// use oxjsonld::JsonLdParser;
301/// use oxrdf::vocab::rdf;
302/// use oxrdf::NamedNodeRef;
303///
304/// let file = br#"{
305///     "@context": {"schema": "http://schema.org/"},
306///     "@graph": [
307///         {
308///             "@type": "schema:Person",
309///             "@id": "http://example.com/foo",
310///             "schema:name": "Foo"
311///         },
312///         {
313///             "@type": "schema:Person",
314///             "schema:name": "Bar"
315///         }
316///     ]
317/// }"#;
318///
319/// let schema_person = NamedNodeRef::new("http://schema.org/Person")?;
320/// let mut count = 0;
321/// for quad in JsonLdParser::new().for_reader(file.as_ref()) {
322///     let quad = quad?;
323///     if quad.predicate == rdf::TYPE && quad.object == schema_person.into() {
324///         count += 1;
325///     }
326/// }
327/// assert_eq!(2, count);
328/// # Result::<_, Box<dyn std::error::Error>>::Ok(())
329/// ```
330#[must_use]
331pub struct ReaderJsonLdParser<R: Read> {
332    results: Vec<Quad>,
333    errors: Vec<JsonLdSyntaxError>,
334    inner: InternalJsonLdParser,
335    json_parser: ReaderJsonParser<R>,
336}
337
338impl<R: Read> Iterator for ReaderJsonLdParser<R> {
339    type Item = Result<Quad, JsonLdParseError>;
340
341    fn next(&mut self) -> Option<Self::Item> {
342        loop {
343            if let Some(error) = self.errors.pop() {
344                return Some(Err(error.into()));
345            } else if let Some(quad) = self.results.pop() {
346                return Some(Ok(quad));
347            } else if self.inner.is_end() {
348                return None;
349            }
350            let step = self.parse_step();
351            if let Err(e) = step {
352                return Some(Err(e));
353            }
354            // We make sure to have data in the right order
355            self.results.reverse();
356            self.errors.reverse();
357        }
358    }
359}
360
361impl<R: Read> ReaderJsonLdParser<R> {
362    /// Allows to set a callback to load remote document and contexts
363    ///
364    /// The first argument is the document URL.
365    ///
366    /// It corresponds to the [`documentLoader` option from the algorithm specification](https://www.w3.org/TR/json-ld11-api/#dom-jsonldoptions-documentloader).
367    ///
368    /// See [`LoadDocumentCallback` API documentation](https://www.w3.org/TR/json-ld-api/#loaddocumentcallback) for more details
369    ///
370    /// ```
371    /// use oxjsonld::{JsonLdParser, JsonLdRemoteDocument};
372    /// use oxrdf::vocab::rdf;
373    /// use oxrdf::NamedNodeRef;
374    ///
375    /// let file = br#"{
376    ///     "@context": "file://context.jsonld",
377    ///     "@type": "schema:Person",
378    ///     "@id": "http://example.com/foo",
379    ///     "schema:name": "Foo"
380    /// }"#;
381    ///
382    /// let schema_person = NamedNodeRef::new("http://schema.org/Person")?;
383    /// let mut count = 0;
384    /// for quad in JsonLdParser::new()
385    ///     .for_reader(file.as_ref())
386    ///     .with_load_document_callback(|url, _options| {
387    ///         assert_eq!(url, "file://context.jsonld");
388    ///         Ok(JsonLdRemoteDocument {
389    ///             document: br#"{"@context":{"schema": "http://schema.org/"}}"#.to_vec(),
390    ///             document_url: "file://context.jsonld".into(),
391    ///         })
392    ///     })
393    /// {
394    ///     let quad = quad?;
395    ///     if quad.predicate == rdf::TYPE && quad.object == schema_person.into() {
396    ///         count += 1;
397    ///     }
398    /// }
399    /// assert_eq!(1, count);
400    /// # Result::<_, Box<dyn std::error::Error>>::Ok(())
401    /// ```
402    pub fn with_load_document_callback(
403        mut self,
404        callback: impl Fn(
405                &str,
406                &JsonLdLoadDocumentOptions,
407            ) -> Result<JsonLdRemoteDocument, Box<dyn Error + Send + Sync>>
408            + Send
409            + Sync
410            + UnwindSafe
411            + RefUnwindSafe
412            + 'static,
413    ) -> Self {
414        self.inner.expansion = self.inner.expansion.with_load_document_callback(callback);
415        self
416    }
417
418    /// The list of IRI prefixes considered at the current step of the parsing.
419    ///
420    /// This method returns (prefix name, prefix value) tuples.
421    /// It is empty at the beginning of the parsing and gets updated when prefixes are encountered.
422    /// It should be full at the end of the parsing (but if a prefix is overridden, only the latest version will be returned).
423    ///
424    /// ```
425    /// use oxjsonld::JsonLdParser;
426    ///
427    /// let file = br#"{
428    ///     "@context": {"schema": "http://schema.org/", "@base": "http://example.com/"},
429    ///     "@type": "schema:Person",
430    ///     "@id": "foo",
431    ///     "schema:name": "Foo"
432    /// }"#;
433    ///
434    /// let mut parser = JsonLdParser::new().for_reader(file.as_ref());
435    /// assert_eq!(parser.prefixes().collect::<Vec<_>>(), []); // No prefix at the beginning
436    ///
437    /// parser.next().unwrap()?; // We read the first quad
438    /// assert_eq!(
439    ///     parser.prefixes().collect::<Vec<_>>(),
440    ///     [("schema", "http://schema.org/")]
441    /// ); // There are now prefixes
442    /// # Result::<_, Box<dyn std::error::Error>>::Ok(())
443    /// ```
444    pub fn prefixes(&self) -> JsonLdPrefixesIter<'_> {
445        self.inner.prefixes()
446    }
447
448    /// The base IRI considered at the current step of the parsing.
449    ///
450    /// ```
451    /// use oxjsonld::JsonLdParser;
452    ///
453    /// let file = br#"{
454    ///     "@context": {"schema": "http://schema.org/", "@base": "http://example.com/"},
455    ///     "@type": "schema:Person",
456    ///     "@id": "foo",
457    ///     "schema:name": "Foo"
458    /// }"#;
459    ///
460    /// let mut parser = JsonLdParser::new().for_reader(file.as_ref());
461    /// assert!(parser.base_iri().is_none()); // No base at the beginning because none has been given to the parser.
462    ///
463    /// parser.next().unwrap()?; // We read the first quad
464    /// assert_eq!(parser.base_iri(), Some("http://example.com/")); // There is now a base IRI.
465    /// # Result::<_, Box<dyn std::error::Error>>::Ok(())
466    /// ```
467    pub fn base_iri(&self) -> Option<&str> {
468        self.inner.base_iri()
469    }
470
471    fn parse_step(&mut self) -> Result<(), JsonLdParseError> {
472        let event = self.json_parser.parse_next().map_err(|e| {
473            self.inner.json_error = true;
474            e
475        })?;
476        self.inner
477            .parse_event(event, &mut self.results, &mut self.errors);
478        Ok(())
479    }
480}
481
482/// Parses a JSON-LD file from a [`AsyncRead`] implementation.
483///
484/// Can be built using [`JsonLdParser::for_tokio_async_reader`].
485///
486/// Count the number of people:
487/// ```
488/// # #[tokio::main(flavor = "current_thread")]
489/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
490/// use oxjsonld::JsonLdParser;
491/// use oxrdf::vocab::rdf;
492/// use oxrdf::NamedNodeRef;
493///
494/// let file = br#"{
495///     "@context": {"schema": "http://schema.org/"},
496///     "@graph": [
497///         {
498///             "@type": "schema:Person",
499///             "@id": "http://example.com/foo",
500///             "schema:name": "Foo"
501///         },
502///         {
503///             "@type": "schema:Person",
504///             "schema:name": "Bar"
505///         }
506///     ]
507/// }"#;
508///
509/// let schema_person = NamedNodeRef::new("http://schema.org/Person")?;
510/// let mut count = 0;
511/// let mut parser = JsonLdParser::new().for_tokio_async_reader(file.as_ref());
512/// while let Some(quad) = parser.next().await {
513///     let quad = quad?;
514///     if quad.predicate == rdf::TYPE && quad.object == schema_person.into() {
515///         count += 1;
516///     }
517/// }
518/// assert_eq!(2, count);
519/// # Ok(())
520/// # }
521/// ```
522#[cfg(feature = "async-tokio")]
523#[must_use]
524pub struct TokioAsyncReaderJsonLdParser<R: AsyncRead + Unpin> {
525    results: Vec<Quad>,
526    errors: Vec<JsonLdSyntaxError>,
527    inner: InternalJsonLdParser,
528    json_parser: TokioAsyncReaderJsonParser<R>,
529}
530
531#[cfg(feature = "async-tokio")]
532impl<R: AsyncRead + Unpin> TokioAsyncReaderJsonLdParser<R> {
533    /// Reads the next quad or returns `None` if the file is finished.
534    pub async fn next(&mut self) -> Option<Result<Quad, JsonLdParseError>> {
535        loop {
536            if let Some(error) = self.errors.pop() {
537                return Some(Err(error.into()));
538            } else if let Some(quad) = self.results.pop() {
539                return Some(Ok(quad));
540            } else if self.inner.is_end() {
541                return None;
542            }
543            if let Err(e) = self.parse_step().await {
544                return Some(Err(e));
545            }
546            // We make sure to have data in the right order
547            self.results.reverse();
548            self.errors.reverse();
549        }
550    }
551
552    /// The list of IRI prefixes considered at the current step of the parsing.
553    ///
554    /// This method returns (prefix name, prefix value) tuples.
555    /// It is empty at the beginning of the parsing and gets updated when prefixes are encountered.
556    /// It should be full at the end of the parsing (but if a prefix is overridden, only the latest version will be returned).
557    ///
558    /// ```
559    /// # #[tokio::main(flavor = "current_thread")]
560    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
561    /// use oxjsonld::JsonLdParser;
562    ///
563    /// let file = br#"{
564    ///     "@context": {"schema": "http://schema.org/", "@base": "http://example.com/"},
565    ///     "@type": "schema:Person",
566    ///     "@id": "foo",
567    ///     "schema:name": "Foo"
568    /// }"#;
569    ///
570    /// let mut parser = JsonLdParser::new().for_tokio_async_reader(file.as_ref());
571    /// assert_eq!(parser.prefixes().collect::<Vec<_>>(), []); // No prefix at the beginning
572    ///
573    /// parser.next().await.unwrap()?; // We read the first quad
574    /// assert_eq!(
575    ///     parser.prefixes().collect::<Vec<_>>(),
576    ///     [("schema", "http://schema.org/")]
577    /// ); // There are now prefixes
578    /// # Ok(())
579    /// # }
580    /// ```
581    pub fn prefixes(&self) -> JsonLdPrefixesIter<'_> {
582        self.inner.prefixes()
583    }
584
585    /// The base IRI considered at the current step of the parsing.
586    ///
587    /// ```
588    /// # #[tokio::main(flavor = "current_thread")]
589    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
590    /// use oxjsonld::JsonLdParser;
591    ///
592    /// let file = br#"{
593    ///     "@context": {"schema": "http://schema.org/", "@base": "http://example.com/"},
594    ///     "@type": "schema:Person",
595    ///     "@id": "foo",
596    ///     "schema:name": "Foo"
597    /// }"#;
598    ///
599    /// let mut parser = JsonLdParser::new().for_tokio_async_reader(file.as_ref());
600    /// assert!(parser.base_iri().is_none()); // No base at the beginning because none has been given to the parser.
601    ///
602    /// parser.next().await.unwrap()?; // We read the first quad
603    /// assert_eq!(parser.base_iri(), Some("http://example.com/")); // There is now a base IRI.
604    /// # Ok(())
605    /// # }
606    /// ```
607    pub fn base_iri(&self) -> Option<&str> {
608        self.inner.base_iri()
609    }
610
611    async fn parse_step(&mut self) -> Result<(), JsonLdParseError> {
612        let event = self.json_parser.parse_next().await.map_err(|e| {
613            self.inner.json_error = true;
614            e
615        })?;
616        self.inner
617            .parse_event(event, &mut self.results, &mut self.errors);
618        Ok(())
619    }
620}
621
622/// Parses a JSON-LD file from a byte slice.
623///
624/// Can be built using [`JsonLdParser::for_slice`].
625///
626/// Count the number of people:
627/// ```
628/// use oxjsonld::JsonLdParser;
629/// use oxrdf::vocab::rdf;
630/// use oxrdf::NamedNodeRef;
631///
632/// let file = br#"{
633///     "@context": {"schema": "http://schema.org/"},
634///     "@graph": [
635///         {
636///             "@type": "schema:Person",
637///             "@id": "http://example.com/foo",
638///             "schema:name": "Foo"
639///         },
640///         {
641///             "@type": "schema:Person",
642///             "schema:name": "Bar"
643///         }
644///     ]
645/// }"#;
646///
647/// let schema_person = NamedNodeRef::new("http://schema.org/Person")?;
648/// let mut count = 0;
649/// for quad in JsonLdParser::new().for_slice(file) {
650///     let quad = quad?;
651///     if quad.predicate == rdf::TYPE && quad.object == schema_person.into() {
652///         count += 1;
653///     }
654/// }
655/// assert_eq!(2, count);
656/// # Result::<_, Box<dyn std::error::Error>>::Ok(())
657/// ```
658#[must_use]
659pub struct SliceJsonLdParser<'a> {
660    results: Vec<Quad>,
661    errors: Vec<JsonLdSyntaxError>,
662    inner: InternalJsonLdParser,
663    json_parser: SliceJsonParser<'a>,
664}
665
666impl Iterator for SliceJsonLdParser<'_> {
667    type Item = Result<Quad, JsonLdSyntaxError>;
668
669    fn next(&mut self) -> Option<Self::Item> {
670        loop {
671            if let Some(error) = self.errors.pop() {
672                return Some(Err(error));
673            } else if let Some(quad) = self.results.pop() {
674                return Some(Ok(quad));
675            } else if self.inner.is_end() {
676                return None;
677            }
678            if let Err(e) = self.parse_step() {
679                // I/O errors cannot happen
680                return Some(Err(e));
681            }
682            // We make sure to have data in the right order
683            self.results.reverse();
684            self.errors.reverse();
685        }
686    }
687}
688
689impl SliceJsonLdParser<'_> {
690    /// The list of IRI prefixes considered at the current step of the parsing.
691    ///
692    /// This method returns (prefix name, prefix value) tuples.
693    /// It is empty at the beginning of the parsing and gets updated when prefixes are encountered.
694    /// It should be full at the end of the parsing (but if a prefix is overridden, only the latest version will be returned).
695    ///
696    /// ```
697    /// use oxjsonld::JsonLdParser;
698    ///
699    /// let file = br#"{
700    ///     "@context": {"schema": "http://schema.org/", "@base": "http://example.com/"},
701    ///     "@type": "schema:Person",
702    ///     "@id": "foo",
703    ///     "schema:name": "Foo"
704    /// }"#;
705    ///
706    /// let mut parser = JsonLdParser::new().for_slice(file);
707    /// assert_eq!(parser.prefixes().collect::<Vec<_>>(), []); // No prefix at the beginning
708    ///
709    /// parser.next().unwrap()?; // We read the first quad
710    /// assert_eq!(
711    ///     parser.prefixes().collect::<Vec<_>>(),
712    ///     [("schema", "http://schema.org/")]
713    /// ); // There are now prefixes
714    /// # Result::<_, Box<dyn std::error::Error>>::Ok(())
715    /// ```
716    pub fn prefixes(&self) -> JsonLdPrefixesIter<'_> {
717        self.inner.prefixes()
718    }
719
720    /// The base IRI considered at the current step of the parsing.
721    ///
722    /// ```
723    /// use oxjsonld::JsonLdParser;
724    ///
725    /// let file = br#"{
726    ///     "@context": {"schema": "http://schema.org/", "@base": "http://example.com/"},
727    ///     "@type": "schema:Person",
728    ///     "@id": "foo",
729    ///     "schema:name": "Foo"
730    /// }"#;
731    ///
732    /// let mut parser = JsonLdParser::new().for_slice(file);
733    /// assert!(parser.base_iri().is_none()); // No base at the beginning because none has been given to the parser.
734    ///
735    /// parser.next().unwrap()?; // We read the first quad
736    /// assert_eq!(parser.base_iri(), Some("http://example.com/")); // There is now a base IRI.
737    /// # Result::<_, Box<dyn std::error::Error>>::Ok(())
738    /// ```
739    pub fn base_iri(&self) -> Option<&str> {
740        self.inner.base_iri()
741    }
742
743    fn parse_step(&mut self) -> Result<(), JsonLdSyntaxError> {
744        let event = self.json_parser.parse_next().map_err(|e| {
745            self.inner.json_error = true;
746            e
747        })?;
748        self.inner
749            .parse_event(event, &mut self.results, &mut self.errors);
750        Ok(())
751    }
752}
753
754/// Iterator on the file prefixes.
755///
756/// See [`ReaderJsonLdParser::prefixes`].
757pub struct JsonLdPrefixesIter<'a> {
758    term_definitions: std::collections::hash_map::Iter<'a, String, JsonLdTermDefinition>,
759    lenient: bool,
760}
761
762impl<'a> Iterator for JsonLdPrefixesIter<'a> {
763    type Item = (&'a str, &'a str);
764
765    #[inline]
766    fn next(&mut self) -> Option<Self::Item> {
767        loop {
768            let (prefix, term_definition) = self.term_definitions.next()?;
769            if term_definition.prefix_flag {
770                if let Some(Some(mapping)) = &term_definition.iri_mapping {
771                    if self.lenient || Iri::parse(mapping.as_str()).is_ok() {
772                        return Some((prefix, mapping));
773                    }
774                }
775            }
776        }
777    }
778
779    #[inline]
780    fn size_hint(&self) -> (usize, Option<usize>) {
781        (0, self.term_definitions.size_hint().1)
782    }
783}
784
785struct InternalJsonLdParser {
786    expansion: JsonLdExpansionConverter,
787    expended_events: Vec<JsonLdEvent>,
788    to_rdf: JsonLdToRdfConverter,
789    json_error: bool,
790}
791
792impl InternalJsonLdParser {
793    fn parse_event(
794        &mut self,
795        event: JsonEvent<'_>,
796        results: &mut Vec<Quad>,
797        errors: &mut Vec<JsonLdSyntaxError>,
798    ) {
799        self.expansion
800            .convert_event(event, &mut self.expended_events, errors);
801        for event in self.expended_events.drain(..) {
802            self.to_rdf.convert_event(event, results);
803        }
804    }
805
806    fn is_end(&self) -> bool {
807        self.json_error || self.expansion.is_end()
808    }
809
810    fn base_iri(&self) -> Option<&str> {
811        Some(self.expansion.context().base_iri.as_ref()?.as_str())
812    }
813
814    fn prefixes(&self) -> JsonLdPrefixesIter<'_> {
815        JsonLdPrefixesIter {
816            term_definitions: self.expansion.context().term_definitions.iter(),
817            lenient: self.to_rdf.lenient,
818        }
819    }
820}
821
822enum JsonLdToRdfState {
823    StartObject {
824        types: Vec<NamedOrBlankNode>,
825        /// Events before the @id event
826        buffer: Vec<JsonLdEvent>,
827        /// Nesting level of objects, useful during buffering
828        nesting: usize,
829    },
830    Object(Option<NamedOrBlankNode>),
831    Property {
832        id: Option<NamedNode>,
833        reverse: bool,
834    },
835    List(Option<NamedOrBlankNode>),
836    Graph(Option<GraphName>),
837}
838
839struct JsonLdToRdfConverter {
840    state: Vec<JsonLdToRdfState>,
841    lenient: bool,
842}
843
844impl JsonLdToRdfConverter {
845    fn convert_event(&mut self, event: JsonLdEvent, results: &mut Vec<Quad>) {
846        #[allow(clippy::expect_used)]
847        let state = self.state.pop().expect("Empty stack");
848        match state {
849            JsonLdToRdfState::StartObject {
850                types,
851                mut buffer,
852                nesting,
853            } => {
854                match event {
855                    JsonLdEvent::Id(id) => {
856                        if nesting > 0 {
857                            buffer.push(JsonLdEvent::Id(id));
858                            self.state.push(JsonLdToRdfState::StartObject {
859                                types,
860                                buffer,
861                                nesting,
862                            });
863                        } else {
864                            let id = self.convert_named_or_blank_node(id);
865                            self.emit_quads_for_new_object(id.as_ref(), types, results);
866                            self.state.push(JsonLdToRdfState::Object(id));
867                            for event in buffer {
868                                self.convert_event(event, results);
869                            }
870                        }
871                    }
872                    JsonLdEvent::EndObject => {
873                        if nesting > 0 {
874                            buffer.push(JsonLdEvent::EndObject);
875                            self.state.push(JsonLdToRdfState::StartObject {
876                                types,
877                                buffer,
878                                nesting: nesting - 1,
879                            });
880                        } else {
881                            let id = Some(BlankNode::default().into());
882                            self.emit_quads_for_new_object(id.as_ref(), types, results);
883                            if !buffer.is_empty() {
884                                self.state.push(JsonLdToRdfState::Object(id));
885                                for event in buffer {
886                                    self.convert_event(event, results);
887                                }
888                                // We properly end after playing the buffer
889                                self.convert_event(JsonLdEvent::EndObject, results);
890                            }
891                        }
892                    }
893                    JsonLdEvent::StartObject { .. } => {
894                        buffer.push(event);
895                        self.state.push(JsonLdToRdfState::StartObject {
896                            types,
897                            buffer,
898                            nesting: nesting + 1,
899                        });
900                    }
901                    _ => {
902                        buffer.push(event);
903                        self.state.push(JsonLdToRdfState::StartObject {
904                            types,
905                            buffer,
906                            nesting,
907                        });
908                    }
909                }
910            }
911            JsonLdToRdfState::Object(id) => match event {
912                JsonLdEvent::Id(_) => {
913                    unreachable!("Should have buffered before @id")
914                }
915                JsonLdEvent::EndObject => (),
916                JsonLdEvent::StartProperty { name, reverse } => {
917                    self.state.push(JsonLdToRdfState::Object(id));
918                    self.state.push(JsonLdToRdfState::Property {
919                        id: if self.has_defined_last_predicate() {
920                            self.convert_named_node(name)
921                        } else {
922                            None // We do not want to emit if one of the parent property is not emitted
923                        },
924                        reverse,
925                    });
926                }
927                JsonLdEvent::StartGraph => {
928                    let graph_name = id.clone().map(Into::into);
929                    self.state.push(JsonLdToRdfState::Object(id));
930                    self.state.push(JsonLdToRdfState::Graph(graph_name));
931                }
932                JsonLdEvent::StartObject { .. }
933                | JsonLdEvent::Value { .. }
934                | JsonLdEvent::EndProperty
935                | JsonLdEvent::EndGraph
936                | JsonLdEvent::StartList
937                | JsonLdEvent::EndList
938                | JsonLdEvent::StartSet
939                | JsonLdEvent::EndSet => unreachable!(),
940            },
941            JsonLdToRdfState::Property { .. } => match event {
942                JsonLdEvent::StartObject { types } => {
943                    self.state.push(state);
944                    self.state.push(JsonLdToRdfState::StartObject {
945                        types: types
946                            .into_iter()
947                            .filter_map(|t| self.convert_named_or_blank_node(t))
948                            .collect(),
949                        buffer: Vec::new(),
950                        nesting: 0,
951                    });
952                }
953                JsonLdEvent::Value {
954                    value,
955                    r#type,
956                    language,
957                } => {
958                    self.state.push(state);
959                    self.emit_quad_for_new_literal(
960                        self.convert_literal(value, language, r#type),
961                        results,
962                    )
963                }
964                JsonLdEvent::EndProperty => (),
965                JsonLdEvent::StartList => {
966                    self.state.push(state);
967                    self.state.push(JsonLdToRdfState::List(None));
968                }
969                JsonLdEvent::StartSet | JsonLdEvent::EndSet => {
970                    self.state.push(state);
971                }
972                JsonLdEvent::StartProperty { .. }
973                | JsonLdEvent::Id(_)
974                | JsonLdEvent::EndObject
975                | JsonLdEvent::StartGraph
976                | JsonLdEvent::EndGraph
977                | JsonLdEvent::EndList => unreachable!(),
978            },
979            JsonLdToRdfState::List(current_node) => match event {
980                JsonLdEvent::StartObject { types } => {
981                    self.add_new_list_node_state(current_node, results);
982                    self.state.push(JsonLdToRdfState::StartObject {
983                        types: types
984                            .into_iter()
985                            .filter_map(|t| self.convert_named_or_blank_node(t))
986                            .collect(),
987                        buffer: Vec::new(),
988                        nesting: 0,
989                    })
990                }
991                JsonLdEvent::Value {
992                    value,
993                    r#type,
994                    language,
995                } => {
996                    self.add_new_list_node_state(current_node, results);
997                    self.emit_quad_for_new_literal(
998                        self.convert_literal(value, language, r#type),
999                        results,
1000                    )
1001                }
1002                JsonLdEvent::StartList => {
1003                    self.add_new_list_node_state(current_node, results);
1004                    self.state.push(JsonLdToRdfState::List(None));
1005                }
1006                JsonLdEvent::EndList => {
1007                    if let Some(previous_node) = current_node {
1008                        if let Some(graph_name) = self.last_graph_name() {
1009                            results.push(Quad::new(
1010                                previous_node,
1011                                rdf::REST,
1012                                rdf::NIL.into_owned(),
1013                                graph_name.clone(),
1014                            ));
1015                        }
1016                    } else {
1017                        self.emit_quads_for_new_object(
1018                            Some(&rdf::NIL.into_owned().into()),
1019                            Vec::new(),
1020                            results,
1021                        )
1022                    }
1023                }
1024                JsonLdEvent::StartSet | JsonLdEvent::EndSet => {
1025                    // TODO: this is bad
1026                    self.state.push(JsonLdToRdfState::List(current_node));
1027                }
1028                JsonLdEvent::EndObject
1029                | JsonLdEvent::StartProperty { .. }
1030                | JsonLdEvent::EndProperty
1031                | JsonLdEvent::Id(_)
1032                | JsonLdEvent::StartGraph
1033                | JsonLdEvent::EndGraph => unreachable!(),
1034            },
1035            JsonLdToRdfState::Graph(_) => match event {
1036                JsonLdEvent::StartObject { types } => {
1037                    self.state.push(state);
1038                    self.state.push(JsonLdToRdfState::StartObject {
1039                        types: types
1040                            .into_iter()
1041                            .filter_map(|t| self.convert_named_or_blank_node(t))
1042                            .collect(),
1043                        buffer: Vec::new(),
1044                        nesting: 0,
1045                    });
1046                }
1047                JsonLdEvent::Value { .. } => {
1048                    self.state.push(state);
1049                }
1050                JsonLdEvent::EndGraph => (),
1051                JsonLdEvent::StartGraph
1052                | JsonLdEvent::StartProperty { .. }
1053                | JsonLdEvent::EndProperty
1054                | JsonLdEvent::Id(_)
1055                | JsonLdEvent::EndObject
1056                | JsonLdEvent::StartList
1057                | JsonLdEvent::EndList
1058                | JsonLdEvent::StartSet
1059                | JsonLdEvent::EndSet => unreachable!(),
1060            },
1061        }
1062    }
1063
1064    fn emit_quads_for_new_object(
1065        &self,
1066        id: Option<&NamedOrBlankNode>,
1067        types: Vec<NamedOrBlankNode>,
1068        results: &mut Vec<Quad>,
1069    ) {
1070        let Some(id) = id else {
1071            return;
1072        };
1073        let Some(graph_name) = self.last_graph_name() else {
1074            return;
1075        };
1076        if let (Some(subject), Some((predicate, reverse))) =
1077            (self.last_subject(), self.last_predicate())
1078        {
1079            results.push(if reverse {
1080                Quad::new(id.clone(), predicate, subject.clone(), graph_name.clone())
1081            } else {
1082                Quad::new(subject.clone(), predicate, id.clone(), graph_name.clone())
1083            })
1084        }
1085        for t in types {
1086            results.push(Quad::new(id.clone(), rdf::TYPE, t, graph_name.clone()))
1087        }
1088    }
1089
1090    fn emit_quad_for_new_literal(&self, literal: Option<Literal>, results: &mut Vec<Quad>) {
1091        let Some(literal) = literal else {
1092            return;
1093        };
1094        let Some(graph_name) = self.last_graph_name() else {
1095            return;
1096        };
1097        let Some(subject) = self.last_subject() else {
1098            return;
1099        };
1100        let Some((predicate, reverse)) = self.last_predicate() else {
1101            return;
1102        };
1103        if reverse {
1104            return;
1105        }
1106        results.push(Quad::new(
1107            subject.clone(),
1108            predicate,
1109            literal,
1110            graph_name.clone(),
1111        ))
1112    }
1113
1114    fn add_new_list_node_state(
1115        &mut self,
1116        current_node: Option<NamedOrBlankNode>,
1117        results: &mut Vec<Quad>,
1118    ) {
1119        let new_node = BlankNode::default();
1120        if let Some(previous_node) = current_node {
1121            if let Some(graph_name) = self.last_graph_name() {
1122                results.push(Quad::new(
1123                    previous_node,
1124                    rdf::REST,
1125                    new_node.clone(),
1126                    graph_name.clone(),
1127                ));
1128            }
1129        } else {
1130            self.emit_quads_for_new_object(Some(&new_node.clone().into()), Vec::new(), results)
1131        }
1132        self.state
1133            .push(JsonLdToRdfState::List(Some(new_node.into())));
1134    }
1135
1136    fn convert_named_or_blank_node(&self, value: String) -> Option<NamedOrBlankNode> {
1137        Some(if let Some(bnode_id) = value.strip_prefix("_:") {
1138            if self.lenient {
1139                Some(BlankNode::new_unchecked(bnode_id))
1140            } else {
1141                BlankNode::new(bnode_id).ok()
1142            }?
1143            .into()
1144        } else {
1145            self.convert_named_node(value)?.into()
1146        })
1147    }
1148
1149    fn convert_named_node(&self, value: String) -> Option<NamedNode> {
1150        if self.lenient {
1151            Some(NamedNode::new_unchecked(value))
1152        } else {
1153            NamedNode::new(&value).ok()
1154        }
1155    }
1156
1157    fn convert_literal(
1158        &self,
1159        value: JsonLdValue,
1160        language: Option<String>,
1161        r#type: Option<String>,
1162    ) -> Option<Literal> {
1163        let r#type = if let Some(t) = r#type {
1164            Some(self.convert_named_node(t)?)
1165        } else {
1166            None
1167        };
1168        Some(match value {
1169            JsonLdValue::String(value) => {
1170                if let Some(language) = language {
1171                    if r#type.is_some_and(|t| t != rdf::LANG_STRING) {
1172                        return None; // Expansion already returns an error
1173                    }
1174                    if self.lenient {
1175                        Literal::new_language_tagged_literal_unchecked(value, language)
1176                    } else {
1177                        Literal::new_language_tagged_literal(value, &language).ok()?
1178                    }
1179                } else if let Some(datatype) = r#type {
1180                    Literal::new_typed_literal(value, datatype)
1181                } else {
1182                    Literal::new_simple_literal(value)
1183                }
1184            }
1185            JsonLdValue::Number(value) => {
1186                if language.is_some() {
1187                    return None; // Expansion already returns an error
1188                }
1189                let value = canonicalize_json_number(
1190                    &value,
1191                    r#type.as_ref().is_some_and(|t| *t == xsd::DOUBLE),
1192                )
1193                .unwrap_or(RdfJsonNumber::Double(value));
1194                match value {
1195                    RdfJsonNumber::Integer(value) => Literal::new_typed_literal(
1196                        value,
1197                        r#type.unwrap_or_else(|| xsd::INTEGER.into()),
1198                    ),
1199                    RdfJsonNumber::Double(value) => Literal::new_typed_literal(
1200                        value,
1201                        r#type.unwrap_or_else(|| xsd::DOUBLE.into()),
1202                    ),
1203                }
1204            }
1205            JsonLdValue::Boolean(value) => {
1206                if language.is_some() {
1207                    return None; // Expansion already returns an error
1208                }
1209                Literal::new_typed_literal(
1210                    if value { "true" } else { "false" },
1211                    r#type.unwrap_or_else(|| xsd::BOOLEAN.into()),
1212                )
1213            }
1214        })
1215    }
1216
1217    fn last_subject(&self) -> Option<&NamedOrBlankNode> {
1218        for state in self.state.iter().rev() {
1219            match state {
1220                JsonLdToRdfState::Object(id) => {
1221                    return id.as_ref();
1222                }
1223                JsonLdToRdfState::StartObject { .. } => {
1224                    unreachable!()
1225                }
1226                JsonLdToRdfState::Property { .. } => (),
1227                JsonLdToRdfState::List(id) => return id.as_ref(),
1228                JsonLdToRdfState::Graph(_) => {
1229                    return None;
1230                }
1231            }
1232        }
1233        None
1234    }
1235
1236    fn last_predicate(&self) -> Option<(NamedNodeRef<'_>, bool)> {
1237        for state in self.state.iter().rev() {
1238            match state {
1239                JsonLdToRdfState::Property { id, reverse } => {
1240                    return Some((id.as_ref()?.as_ref(), *reverse));
1241                }
1242                JsonLdToRdfState::StartObject { .. } | JsonLdToRdfState::Object(_) => (),
1243                JsonLdToRdfState::List(_) => return Some((rdf::FIRST, false)),
1244                JsonLdToRdfState::Graph(_) => {
1245                    return None;
1246                }
1247            }
1248        }
1249        None
1250    }
1251
1252    fn has_defined_last_predicate(&self) -> bool {
1253        for state in self.state.iter().rev() {
1254            if let JsonLdToRdfState::Property { id, .. } = state {
1255                return id.is_some();
1256            }
1257        }
1258        true
1259    }
1260
1261    fn last_graph_name(&self) -> Option<&GraphName> {
1262        for state in self.state.iter().rev() {
1263            match state {
1264                JsonLdToRdfState::Graph(graph) => {
1265                    return graph.as_ref();
1266                }
1267                JsonLdToRdfState::StartObject { .. }
1268                | JsonLdToRdfState::Object(_)
1269                | JsonLdToRdfState::Property { .. }
1270                | JsonLdToRdfState::List(_) => (),
1271            }
1272        }
1273        None
1274    }
1275}
1276
1277#[derive(Eq, PartialEq, Debug, Clone)]
1278enum RdfJsonNumber {
1279    Integer(String),
1280    Double(String),
1281}
1282
1283/// Canonicalizes the JSON number to xsd:double canonical form.
1284fn canonicalize_json_number(value: &str, always_double: bool) -> Option<RdfJsonNumber> {
1285    // We parse
1286    let (value, is_negative) = if let Some(value) = value.strip_prefix('-') {
1287        (value, true)
1288    } else if let Some(value) = value.strip_prefix('+') {
1289        (value, false)
1290    } else {
1291        (value, false)
1292    };
1293    let (value, exp) = value.split_once(['e', 'E']).unwrap_or((value, "0"));
1294    let (mut integer_part, mut decimal_part) = value.split_once('.').unwrap_or((value, ""));
1295    let mut exp = exp.parse::<i64>().ok()?;
1296
1297    // We normalize
1298    // We trim the zeros
1299    while let Some(c) = integer_part.strip_prefix('0') {
1300        integer_part = c;
1301    }
1302    while let Some(c) = decimal_part.strip_suffix('0') {
1303        decimal_part = c;
1304    }
1305    if decimal_part.is_empty() {
1306        while let Some(c) = integer_part.strip_suffix('0') {
1307            integer_part = c;
1308            exp = exp.checked_add(1)?;
1309        }
1310    }
1311    if integer_part.is_empty() {
1312        while let Some(c) = decimal_part.strip_prefix('0') {
1313            decimal_part = c;
1314            exp = exp.checked_sub(1)?;
1315        }
1316    }
1317
1318    // We set the exponent in the 0.XXXEYYY form
1319    let exp_change = i64::try_from(integer_part.len()).ok()?;
1320    exp = exp.checked_add(exp_change)?;
1321
1322    // We handle the zero case
1323    if integer_part.is_empty() && decimal_part.is_empty() {
1324        integer_part = "0";
1325        exp = 1;
1326    }
1327
1328    // We serialize
1329    let mut buffer = String::with_capacity(value.len());
1330    if is_negative {
1331        buffer.push('-');
1332    }
1333    let digits_count = i64::try_from(integer_part.len() + decimal_part.len()).ok()?;
1334    Some(if !always_double && exp >= digits_count && exp < 21 {
1335        buffer.push_str(integer_part);
1336        buffer.push_str(decimal_part);
1337        buffer.extend((0..(exp - digits_count)).map(|_| '0'));
1338        RdfJsonNumber::Integer(buffer)
1339    } else {
1340        let mut all_digits = integer_part.chars().chain(decimal_part.chars());
1341        buffer.push(all_digits.next()?);
1342        buffer.push('.');
1343        if digits_count == 1 {
1344            buffer.push('0');
1345        } else {
1346            buffer.extend(all_digits);
1347        }
1348        write!(&mut buffer, "E{}", exp.checked_sub(1)?).ok()?;
1349        RdfJsonNumber::Double(buffer)
1350    })
1351}
1352
1353#[cfg(test)]
1354mod tests {
1355    use super::*;
1356
1357    #[test]
1358    fn test_canonicalize_json_number() {
1359        assert_eq!(
1360            canonicalize_json_number("12", false),
1361            Some(RdfJsonNumber::Integer("12".into()))
1362        );
1363        assert_eq!(
1364            canonicalize_json_number("-12", false),
1365            Some(RdfJsonNumber::Integer("-12".into()))
1366        );
1367        assert_eq!(
1368            canonicalize_json_number("1", true),
1369            Some(RdfJsonNumber::Double("1.0E0".into()))
1370        );
1371        assert_eq!(
1372            canonicalize_json_number("1", true),
1373            Some(RdfJsonNumber::Double("1.0E0".into()))
1374        );
1375        assert_eq!(
1376            canonicalize_json_number("+1", true),
1377            Some(RdfJsonNumber::Double("1.0E0".into()))
1378        );
1379        assert_eq!(
1380            canonicalize_json_number("-1", true),
1381            Some(RdfJsonNumber::Double("-1.0E0".into()))
1382        );
1383        assert_eq!(
1384            canonicalize_json_number("12", true),
1385            Some(RdfJsonNumber::Double("1.2E1".into()))
1386        );
1387        assert_eq!(
1388            canonicalize_json_number("-12", true),
1389            Some(RdfJsonNumber::Double("-1.2E1".into()))
1390        );
1391        assert_eq!(
1392            canonicalize_json_number("12.3456E3", false),
1393            Some(RdfJsonNumber::Double("1.23456E4".into()))
1394        );
1395        assert_eq!(
1396            canonicalize_json_number("12.3456e3", false),
1397            Some(RdfJsonNumber::Double("1.23456E4".into()))
1398        );
1399        assert_eq!(
1400            canonicalize_json_number("-12.3456E3", false),
1401            Some(RdfJsonNumber::Double("-1.23456E4".into()))
1402        );
1403        assert_eq!(
1404            canonicalize_json_number("12.34E-3", false),
1405            Some(RdfJsonNumber::Double("1.234E-2".into()))
1406        );
1407        assert_eq!(
1408            canonicalize_json_number("12.340E-3", false),
1409            Some(RdfJsonNumber::Double("1.234E-2".into()))
1410        );
1411        assert_eq!(
1412            canonicalize_json_number("0.01234E-1", false),
1413            Some(RdfJsonNumber::Double("1.234E-3".into()))
1414        );
1415        assert_eq!(
1416            canonicalize_json_number("1.0", false),
1417            Some(RdfJsonNumber::Integer("1".into()))
1418        );
1419        assert_eq!(
1420            canonicalize_json_number("1.0E0", false),
1421            Some(RdfJsonNumber::Integer("1".into()))
1422        );
1423        assert_eq!(
1424            canonicalize_json_number("0.01E2", false),
1425            Some(RdfJsonNumber::Integer("1".into()))
1426        );
1427        assert_eq!(
1428            canonicalize_json_number("1E2", false),
1429            Some(RdfJsonNumber::Integer("100".into()))
1430        );
1431        assert_eq!(
1432            canonicalize_json_number("1E21", false),
1433            Some(RdfJsonNumber::Double("1.0E21".into()))
1434        );
1435        assert_eq!(
1436            canonicalize_json_number("0", false),
1437            Some(RdfJsonNumber::Integer("0".into()))
1438        );
1439        assert_eq!(
1440            canonicalize_json_number("0", true),
1441            Some(RdfJsonNumber::Double("0.0E0".into()))
1442        );
1443        assert_eq!(
1444            canonicalize_json_number("-0", true),
1445            Some(RdfJsonNumber::Double("-0.0E0".into()))
1446        );
1447        assert_eq!(
1448            canonicalize_json_number("0E-10", true),
1449            Some(RdfJsonNumber::Double("0.0E0".into()))
1450        );
1451    }
1452}