Skip to content

Commit 26fc597

Browse files
committed
sophia_resource now supports more formats
1 parent 1ca0a5d commit 26fc597

File tree

9 files changed

+276
-7
lines changed

9 files changed

+276
-7
lines changed

resource/Cargo.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,20 @@ keywords.workspace = true
1313
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
1414

1515
[features]
16+
# This feature enables the JSON-LD parser and serializer
17+
jsonld = ["sophia_jsonld"]
18+
# This feature enables the RDF/XML parser and serializer
19+
xml = ["sophia_xml"]
20+
# This feature enables the HTTP client in dependencies
21+
http_client = []
22+
1623

1724
[dependencies]
1825
sophia_api.workspace = true
1926
sophia_iri.workspace = true
27+
sophia_jsonld = { workspace = true, optional = true }
2028
sophia_turtle.workspace = true
29+
sophia_xml = { workspace = true, optional = true }
2130
thiserror.workspace = true
2231

2332
[dev-dependencies]

resource/src/lib.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,20 @@ mod test {
3333
pub const F2R1: Iri<&str> = Iri::new_unchecked_const("http://example.org/file2.ttl#res1");
3434
pub const F2R2: Iri<&str> = Iri::new_unchecked_const("http://example.org/file2.ttl#res2");
3535
pub const FAIL: Iri<&str> = Iri::new_unchecked_const("http://example.org/not_there");
36+
pub const F3: Iri<&str> = Iri::new_unchecked_const("http://example.org/file3.nt");
37+
#[cfg(feature = "jsonld")]
38+
pub const F4: Iri<&str> = Iri::new_unchecked_const("http://example.org/file4.jsonld");
39+
#[cfg(feature = "xml")]
40+
pub const F5: Iri<&str> = Iri::new_unchecked_const("http://example.org/file5.rdf");
3641
pub const SUBDIR: Iri<&str> = Iri::new_unchecked_const("http://example.org/subdir");
3742
// test with no extension (conneg emulation)
3843
pub const F1X: Iri<&str> = Iri::new_unchecked_const("http://example.org/file1");
3944
pub const F1XR1: Iri<&str> = Iri::new_unchecked_const("http://example.org/file1#res1");
45+
pub const F3X: Iri<&str> = Iri::new_unchecked_const("http://example.org/file3");
46+
#[cfg(feature = "jsonld")]
47+
pub const F4X: Iri<&str> = Iri::new_unchecked_const("http://example.org/file4");
48+
#[cfg(feature = "xml")]
49+
pub const F5X: Iri<&str> = Iri::new_unchecked_const("http://example.org/file5");
4050

4151
pub const EX_ID: Iri<&str> = Iri::new_unchecked_const("http://example.org/ns#id");
4252
pub const EX_LIST: Iri<&str> = Iri::new_unchecked_const("http://example.org/ns#list");
@@ -52,6 +62,14 @@ mod test {
5262
pub const F1_LEN: usize = 20;
5363
/// Number of triples in F2
5464
pub const F2_LEN: usize = 2;
65+
/// Number of triples in F3
66+
pub const F3_LEN: usize = 20;
67+
/// Number of triples in F4
68+
#[cfg(feature = "jsonld")]
69+
pub const F4_LEN: usize = 20;
70+
/// Number of triples in F5
71+
#[cfg(feature = "xml")]
72+
pub const F5_LEN: usize = 20;
5573

5674
pub type MyGraph = Vec<[SimpleTerm<'static>; 3]>;
5775
pub type TestResult = Result<(), Box<dyn std::error::Error>>;

resource/src/loader/_local.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ impl LocalLoader {
6060
fn ctype(&self, iri: &str) -> String {
6161
if iri.ends_with(".ttl") {
6262
"text/turtle".into()
63+
} else if iri.ends_with(".nt") {
64+
"application/n-triples".into()
65+
} else if cfg!(feature = "jsonld") && iri.ends_with(".jsonld") {
66+
"application/ld+json".into()
67+
} else if cfg!(feature = "xml") && iri.ends_with(".rdf") {
68+
"application/rdf+xml".into()
6369
} else {
6470
"application/octet-stream".into()
6571
}
@@ -80,7 +86,14 @@ impl Loader for LocalLoader {
8086
// emulate conneg if there is no extension
8187
let no_ext = iri.as_bytes()[iri.rfind(['.', '/']).unwrap_or(0)] != b'.';
8288
if no_ext {
83-
for ext in ["ttl", "nt"] {
89+
for ext in [
90+
"ttl",
91+
"nt",
92+
#[cfg(feature = "jsonld")]
93+
"jsonld",
94+
#[cfg(feature = "xml")]
95+
"rdf",
96+
] {
8497
let alt = Iri::new_unchecked(format!("{}.{}", iri, ext));
8598
if let Ok(res) = self.get(alt) {
8699
return Ok(res);

resource/src/loader/_trait.rs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use sophia_api::parser::TripleParser;
55
use sophia_api::source::TripleSource;
66
use sophia_api::term::Term;
77
use sophia_iri::Iri;
8-
use sophia_turtle::parser::turtle;
8+
use sophia_turtle::parser::{nt, turtle};
99
use std::borrow::Borrow;
1010
use std::fmt::Debug;
1111
use std::io;
@@ -40,6 +40,36 @@ pub trait Loader: Sized {
4040
.parse(bufread)
4141
.collect_triples()
4242
.map_err(|err| LoaderError::ParseError(iri_buf(iri_str), Box::new(err))),
43+
44+
"application/n-triples" => nt::NTriplesParser {}
45+
.parse(bufread)
46+
.collect_triples()
47+
.map_err(|err| LoaderError::ParseError(iri_buf(iri_str), Box::new(err))),
48+
49+
#[cfg(feature = "jsonld")]
50+
"application/ld+json" => {
51+
use sophia_api::prelude::{Quad, QuadParser, QuadSource};
52+
use sophia_jsonld::{JsonLdOptions, JsonLdParser};
53+
let options =
54+
JsonLdOptions::new().with_base(iri.as_ref().map_unchecked(|t| t.into()));
55+
// TODO use this loader as the document loader for the JSON-LD parser
56+
// (requires to provide an adaptater)
57+
JsonLdParser::new_with_options(options)
58+
.parse(bufread)
59+
.filter_quads(|q| q.g().is_none())
60+
.map_quads(Quad::into_triple)
61+
.collect_triples()
62+
.map_err(|err| LoaderError::ParseError(iri_buf(iri_str), Box::new(err)))
63+
}
64+
65+
#[cfg(feature = "xml")]
66+
"application/rdf+xml" => sophia_xml::parser::RdfXmlParser {
67+
base: Some(iri.as_ref().map_unchecked(|t| t.borrow().to_string())),
68+
}
69+
.parse(bufread)
70+
.collect_triples()
71+
.map_err(|err| LoaderError::ParseError(iri_buf(iri_str), Box::new(err))),
72+
4373
_ => Err(LoaderError::CantGuessSyntax(iri_buf(iri_str))),
4474
}
4575
}

resource/src/loader/test.rs

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,70 @@ fn get_file1_with_add() -> TestResult {
4848
Ok(())
4949
}
5050

51+
#[test]
52+
fn get_file3() -> TestResult {
53+
let ldr = make_loader();
54+
assert_eq!(
55+
ldr.get(F3)?,
56+
(read("test/file3.nt")?, "application/n-triples".into()),
57+
);
58+
Ok(())
59+
}
60+
61+
#[test]
62+
fn get_file3_no_ext() -> TestResult {
63+
let ldr = make_loader();
64+
assert_eq!(
65+
ldr.get(F3X)?,
66+
(read("test/file3.nt")?, "application/n-triples".into()),
67+
);
68+
Ok(())
69+
}
70+
71+
#[cfg(feature = "jsonld")]
72+
#[test]
73+
fn get_file4() -> TestResult {
74+
let ldr = make_loader();
75+
assert_eq!(
76+
ldr.get(F4)?,
77+
(read("test/file4.jsonld")?, "application/ld+json".into()),
78+
);
79+
Ok(())
80+
}
81+
82+
#[cfg(feature = "jsonld")]
83+
#[test]
84+
fn get_file4_no_ext() -> TestResult {
85+
let ldr = make_loader();
86+
assert_eq!(
87+
ldr.get(F4X)?,
88+
(read("test/file4.jsonld")?, "application/ld+json".into()),
89+
);
90+
Ok(())
91+
}
92+
93+
#[cfg(feature = "xml")]
94+
#[test]
95+
fn get_file5() -> TestResult {
96+
let ldr = make_loader();
97+
assert_eq!(
98+
ldr.get(F5)?,
99+
(read("test/file5.rdf")?, "application/rdf+xml".into()),
100+
);
101+
Ok(())
102+
}
103+
104+
#[cfg(feature = "xml")]
105+
#[test]
106+
fn get_file5_no_ext() -> TestResult {
107+
let ldr = make_loader();
108+
assert_eq!(
109+
ldr.get(F5X)?,
110+
(read("test/file5.rdf")?, "application/rdf+xml".into()),
111+
);
112+
Ok(())
113+
}
114+
51115
#[test]
52116
fn file_not_found() -> TestResult {
53117
let ldr = make_loader();
@@ -73,13 +137,39 @@ fn io_error() -> TestResult {
73137
}
74138

75139
#[test]
76-
fn graph() -> TestResult {
140+
fn graph_from_ttl() -> TestResult {
77141
let ldr = make_loader();
78142
let g: MyGraph = ldr.get_graph(F1)?;
79143
assert_eq!(g.len(), F1_LEN);
80144
Ok(())
81145
}
82146

147+
#[test]
148+
fn graph_from_nt() -> TestResult {
149+
let ldr = make_loader();
150+
let g: MyGraph = ldr.get_graph(F3)?;
151+
assert_eq!(g.len(), F3_LEN);
152+
Ok(())
153+
}
154+
155+
#[cfg(feature = "jsonld")]
156+
#[test]
157+
fn graph_from_jsonld() -> TestResult {
158+
let ldr = make_loader();
159+
let g: MyGraph = ldr.get_graph(F4)?;
160+
assert_eq!(g.len(), F4_LEN);
161+
Ok(())
162+
}
163+
164+
#[cfg(feature = "xml")]
165+
#[test]
166+
fn graph_from_rdfxml() -> TestResult {
167+
let ldr = make_loader();
168+
let g: MyGraph = ldr.get_graph(F5)?;
169+
assert_eq!(g.len(), F5_LEN);
170+
Ok(())
171+
}
172+
83173
#[test]
84174
fn resource() -> TestResult {
85175
let ldr = make_loader().arced();

resource/test/file3.nt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<file:///home/pa/dev/sophia_rs/resource/test/file1.ttl#res1> <http://example.org/ns#id> "res1".
2+
<file:///home/pa/dev/sophia_rs/resource/test/file1.ttl#res1> <http://example.org/ns#next> <file:///home/pa/dev/sophia_rs/resource/test/file1.ttl#res2>.
3+
<file:///home/pa/dev/sophia_rs/resource/test/file1.ttl#res1> <http://example.org/ns#related> <file:///home/pa/dev/sophia_rs/resource/test/file1.ttl#res2>.
4+
<file:///home/pa/dev/sophia_rs/resource/test/file1.ttl#res1> <http://example.org/ns#related> <file:///home/pa/dev/sophia_rs/resource/test/file1.ttl#res3>.
5+
<file:///home/pa/dev/sophia_rs/resource/test/file1.ttl#res1> <http://example.org/ns#related> _:b.
6+
<file:///home/pa/dev/sophia_rs/resource/test/file1.ttl#res1> <http://example.org/ns#foreign1> <file:///home/pa/dev/sophia_rs/resource/test/file2.ttl#res1>.
7+
<file:///home/pa/dev/sophia_rs/resource/test/file1.ttl#res1> <http://example.org/ns#foreign2> <file:///home/pa/dev/sophia_rs/resource/test/file2.ttl#res2>.
8+
<file:///home/pa/dev/sophia_rs/resource/test/file1.ttl#res1> <http://example.org/ns#unreachable> <http://somewhere.else/>.
9+
_:riog00000001 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> <file:///home/pa/dev/sophia_rs/resource/test/file1.ttl#res3>.
10+
_:riog00000001 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:riog00000002.
11+
_:riog00000002 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> <file:///home/pa/dev/sophia_rs/resource/test/file1.ttl#res2>.
12+
_:riog00000002 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:riog00000003.
13+
_:riog00000003 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> <file:///home/pa/dev/sophia_rs/resource/test/file2.ttl#res1>.
14+
_:riog00000003 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil>.
15+
<file:///home/pa/dev/sophia_rs/resource/test/file1.ttl#res1> <http://example.org/ns#list> _:riog00000001.
16+
<file:///home/pa/dev/sophia_rs/resource/test/file1.ttl#res2> <http://example.org/ns#id> "res2".
17+
<file:///home/pa/dev/sophia_rs/resource/test/file1.ttl#res2> <http://example.org/ns#list> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil>.
18+
<file:///home/pa/dev/sophia_rs/resource/test/file1.ttl#res3> <http://example.org/ns#id> "res3".
19+
<file:///home/pa/dev/sophia_rs/resource/test/file1.ttl#res3> <http://example.org/ns#related> <file:///home/pa/dev/sophia_rs/resource/test/file1.ttl#res2>.
20+
_:b <http://example.org/ns#id> "res4".

resource/test/file4.jsonld

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
[
2+
{
3+
"@id": "file:///home/pa/dev/sophia_rs/resource/test/file1.ttl#res1",
4+
"http://example.org/ns#next": [
5+
{
6+
"@id": "file:///home/pa/dev/sophia_rs/resource/test/file1.ttl#res2"
7+
}
8+
],
9+
"http://example.org/ns#id": [
10+
{
11+
"@value": "res1"
12+
}
13+
],
14+
"http://example.org/ns#list": [
15+
{
16+
"@list": [
17+
{
18+
"@id": "file:///home/pa/dev/sophia_rs/resource/test/file1.ttl#res3"
19+
},
20+
{
21+
"@id": "file:///home/pa/dev/sophia_rs/resource/test/file1.ttl#res2"
22+
},
23+
{
24+
"@id": "file:///home/pa/dev/sophia_rs/resource/test/file2.ttl#res1"
25+
}
26+
]
27+
}
28+
],
29+
"http://example.org/ns#foreign1": [
30+
{
31+
"@id": "file:///home/pa/dev/sophia_rs/resource/test/file2.ttl#res1"
32+
}
33+
],
34+
"http://example.org/ns#related": [
35+
{
36+
"@id": "file:///home/pa/dev/sophia_rs/resource/test/file1.ttl#res2"
37+
},
38+
{
39+
"@id": "file:///home/pa/dev/sophia_rs/resource/test/file1.ttl#res3"
40+
},
41+
{ "@id": "_:b" }
42+
],
43+
"http://example.org/ns#foreign2": [
44+
{
45+
"@id": "file:///home/pa/dev/sophia_rs/resource/test/file2.ttl#res2"
46+
}
47+
],
48+
"http://example.org/ns#unreachable": [
49+
{
50+
"@id": "http://somewhere.else/"
51+
}
52+
]
53+
},
54+
{
55+
"@id": "file:///home/pa/dev/sophia_rs/resource/test/file1.ttl#res2",
56+
"http://example.org/ns#list": [
57+
{
58+
"@list": []
59+
}
60+
],
61+
"http://example.org/ns#id": [
62+
{
63+
"@value": "res2"
64+
}
65+
]
66+
},
67+
{
68+
"@id": "file:///home/pa/dev/sophia_rs/resource/test/file1.ttl#res3",
69+
"http://example.org/ns#id": [
70+
{
71+
"@value": "res3"
72+
}
73+
],
74+
"http://example.org/ns#related": [
75+
{
76+
"@id": "file:///home/pa/dev/sophia_rs/resource/test/file1.ttl#res2"
77+
}
78+
]
79+
},
80+
{
81+
"@id": "_:b",
82+
"http://example.org/ns#id": [
83+
{
84+
"@value": "res4"
85+
}
86+
]
87+
}
88+
]

resource/test/file5.rdf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<?xml version="1.0" encoding="UTF-8"?><rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><rdf:Description rdf:about="file:///home/pa/dev/sophia_rs/resource/test/file1.ttl#res1"><id xmlns="http://example.org/ns#">res1</id><next xmlns="http://example.org/ns#" rdf:resource="file:///home/pa/dev/sophia_rs/resource/test/file1.ttl#res2"/><related xmlns="http://example.org/ns#" rdf:resource="file:///home/pa/dev/sophia_rs/resource/test/file1.ttl#res2"/><related xmlns="http://example.org/ns#" rdf:resource="file:///home/pa/dev/sophia_rs/resource/test/file1.ttl#res3"/><related xmlns="http://example.org/ns#" rdf:nodeID="b"/><foreign1 xmlns="http://example.org/ns#" rdf:resource="file:///home/pa/dev/sophia_rs/resource/test/file2.ttl#res1"/><foreign2 xmlns="http://example.org/ns#" rdf:resource="file:///home/pa/dev/sophia_rs/resource/test/file2.ttl#res2"/><unreachable xmlns="http://example.org/ns#" rdf:resource="http://somewhere.else/"/></rdf:Description><rdf:Description rdf:nodeID="riog00000001"><first xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" rdf:resource="file:///home/pa/dev/sophia_rs/resource/test/file1.ttl#res3"/><rest xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" rdf:nodeID="riog00000002"/></rdf:Description><rdf:Description rdf:nodeID="riog00000002"><first xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" rdf:resource="file:///home/pa/dev/sophia_rs/resource/test/file1.ttl#res2"/><rest xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" rdf:nodeID="riog00000003"/></rdf:Description><rdf:Description rdf:nodeID="riog00000003"><first xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" rdf:resource="file:///home/pa/dev/sophia_rs/resource/test/file2.ttl#res1"/><rest xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" rdf:resource="http://www.w3.org/1999/02/22-rdf-syntax-ns#nil"/></rdf:Description><rdf:Description rdf:about="file:///home/pa/dev/sophia_rs/resource/test/file1.ttl#res1"><list xmlns="http://example.org/ns#" rdf:nodeID="riog00000001"/></rdf:Description><rdf:Description rdf:about="file:///home/pa/dev/sophia_rs/resource/test/file1.ttl#res2"><id xmlns="http://example.org/ns#">res2</id><list xmlns="http://example.org/ns#" rdf:resource="http://www.w3.org/1999/02/22-rdf-syntax-ns#nil"/></rdf:Description><rdf:Description rdf:about="file:///home/pa/dev/sophia_rs/resource/test/file1.ttl#res3"><id xmlns="http://example.org/ns#">res3</id><related xmlns="http://example.org/ns#" rdf:resource="file:///home/pa/dev/sophia_rs/resource/test/file1.ttl#res2"/></rdf:Description><rdf:Description rdf:nodeID="b"><id xmlns="http://example.org/ns#">res4</id></rdf:Description></rdf:RDF>

sophia/Cargo.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@ all-features = true
1616
[features]
1717
default = []
1818
# This feature enables the JSON-LD parser and serializer
19-
jsonld = ["sophia_jsonld"]
19+
jsonld = ["sophia_jsonld", "sophia_resource/jsonld"]
2020
# This feature enables the RDF/XML parser and serializer
21-
xml = ["sophia_xml"]
21+
xml = ["sophia_xml", "sophia_resource/xml"]
2222
# This feature enables to use the graph and dataset test macros in other crates
2323
test_macro = ["sophia_api/test_macro"]
24-
# This feature enables the HTTP client crate in dependencies
25-
http_client = ["sophia_jsonld/http_client"]
24+
# This feature enables the HTTP client in dependencies
25+
http_client = ["sophia_jsonld/http_client", "sophia_resource/http_client"]
2626

2727
[dependencies]
2828
sophia_iri.workspace = true

0 commit comments

Comments
 (0)