sophia_turtle/parser/
trig.rs

1//! Adapter for the TriG parser from [RIO](https://github.com/Tpt/rio/blob/master/turtle/src/turtle.rs)
2
3use rio_turtle::TriGParser as RioTriGParser;
4use sophia_api::parser::QuadParser;
5use sophia_iri::Iri;
6use sophia_rio::parser::*;
7use std::io::BufRead;
8
9/// TriG parser based on RIO.
10#[derive(Clone, Debug, Default)]
11pub struct TriGParser {
12    /// The base IRI used by this parser to resolve relative IRI-references.
13    pub base: Option<Iri<String>>,
14}
15
16impl<B: BufRead> QuadParser<B> for TriGParser {
17    type Source = StrictRioSource<RioTriGParser<B>>;
18    fn parse(&self, data: B) -> Self::Source {
19        let base = self
20            .base
21            .clone()
22            .map(Iri::unwrap)
23            .map(oxiri::Iri::parse)
24            .map(Result::unwrap);
25        StrictRioSource(RioTriGParser::new(data, base))
26    }
27}
28
29sophia_api::def_mod_functions_for_bufread_parser!(TriGParser, QuadParser);
30
31// ---------------------------------------------------------------------------------
32//                                      tests
33// ---------------------------------------------------------------------------------
34
35#[cfg(test)]
36mod test {
37    use super::*;
38    use sophia_api::dataset::Dataset;
39    use sophia_api::ns::rdf;
40    use sophia_api::quad::Spog;
41    use sophia_api::source::QuadSource;
42    use sophia_api::term::{SimpleTerm, TermKind};
43    use sophia_iri::Iri;
44    use std::collections::HashSet;
45
46    type MyDataset = Vec<Spog<SimpleTerm<'static>>>;
47
48    #[test]
49    fn test_simple_trig_string() -> std::result::Result<(), Box<dyn std::error::Error>> {
50        let trig = r#"
51            @prefix : <http://example.org/ns/> .
52
53            <#me> :knows _:alice {|
54                :since 2002 ;
55            |}.
56            <tag:g1> {
57                _:alice a :Person ; :name "Alice".
58            }
59        "#;
60
61        let mut d = MyDataset::new();
62        let p = TriGParser {
63            base: Some(Iri::new_unchecked("http://localhost/ex".to_string())),
64        };
65        let c = p.parse_str(trig).add_to_dataset(&mut d)?;
66        assert_eq!(c, 4);
67        assert_eq!(
68            d.quads_matching(
69                [Iri::new_unchecked("http://localhost/ex#me")],
70                [Iri::new_unchecked("http://example.org/ns/knows")],
71                TermKind::BlankNode,
72                [None as Option<&SimpleTerm>],
73            )
74            .count(),
75            1
76        );
77        assert_eq!(
78            d.quads_matching(
79                TermKind::BlankNode,
80                [&rdf::type_],
81                [Iri::new_unchecked("http://example.org/ns/Person")],
82                [Some(Iri::new_unchecked("tag:g1"))],
83            )
84            .count(),
85            1
86        );
87        assert_eq!(
88            d.quads_matching(
89                TermKind::BlankNode,
90                [Iri::new_unchecked("http://example.org/ns/name")],
91                ["Alice"],
92                [Some(Iri::new_unchecked("tag:g1"))],
93            )
94            .count(),
95            1
96        );
97        assert_eq!(
98            d.quads_matching(
99                (
100                    [Iri::new_unchecked("http://localhost/ex#me")],
101                    [Iri::new_unchecked("http://example.org/ns/knows")],
102                    TermKind::BlankNode,
103                ),
104                [Iri::new_unchecked("http://example.org/ns/since")],
105                [2002],
106                [None as Option<&SimpleTerm>],
107            )
108            .count(),
109            1
110        );
111        assert_eq!(d.blank_nodes().collect::<HashSet<_>>().len(), 1);
112        Ok(())
113    }
114}