sophia_turtle/parser/
turtle.rs

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