Skip to content

Commit 66012db

Browse files
authored
Merge pull request #260 from fsteeg/232-iri
Improve IRI resolution according to RFC3986
2 parents 44c1bba + fce53a4 commit 66012db

28 files changed

+680
-7
lines changed

core/src/main/java/com/github/jsonldjava/utils/JsonLdUrl.java

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -261,21 +261,30 @@ public static String resolve(String baseUri, String pathToResolve) {
261261
}
262262
try {
263263
URI uri = new URI(baseUri);
264+
// URI#resolve drops base scheme for opaque URIs, https://github.com/jsonld-java/jsonld-java/issues/232
265+
if (uri.isOpaque()) {
266+
String basePath = uri.getPath() != null ? uri.getPath() : uri.getSchemeSpecificPart();
267+
// Drop the last segment, see https://tools.ietf.org/html/rfc3986#section-5.2.3 (2nd bullet point)
268+
basePath = basePath.contains("/") ? basePath.substring(0, basePath.lastIndexOf('/') + 1) : "";
269+
return new URI(uri.getScheme(), basePath + pathToResolve, null).toString();
270+
}
271+
// "a base URI [...] does not allow a fragment" (https://tools.ietf.org/html/rfc3986#section-4.3)
272+
uri = new URI(uri.getScheme(), uri.getAuthority(), uri.getPath(), uri.getQuery(), null);
264273
// query string parsing
265274
if (pathToResolve.startsWith("?")) {
266-
// drop fragment from uri if it has one
267-
if (uri.getFragment() != null) {
268-
uri = new URI(uri.getScheme(), uri.getAuthority(), uri.getPath(), null, null);
269-
}
270-
// add query to the end manually (as URI.resolve does it wrong)
275+
// drop query, https://tools.ietf.org/html/rfc3986#section-5.2.2: T.query = R.query;
276+
uri = new URI(uri.getScheme(), uri.getAuthority(), uri.getPath(), null, null);
277+
// add query to the end manually (as URI#resolve does it wrong)
278+
return uri.toString() + pathToResolve;
279+
} else if (pathToResolve.startsWith("#")) {
280+
// add fragment to the end manually (as URI#resolve does it wrong)
271281
return uri.toString() + pathToResolve;
272282
}
273-
274283
uri = uri.resolve(pathToResolve);
275284
// java doesn't discard unnecessary dot segments
276285
String path = uri.getPath();
277286
if (path != null) {
278-
path = JsonLdUrl.removeDotSegments(uri.getPath(), true);
287+
path = JsonLdUrl.removeDotSegments(path, true);
279288
}
280289
return new URI(uri.getScheme(), uri.getAuthority(), path, uri.getQuery(),
281290
uri.getFragment()).toString();
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"@id":"relativeURIWithNoBase","@type":"http://example.org/SomeRDFSClass"}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<http://example.org/relativeURIWithNoBase> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/SomeRDFSClass> .
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<tag:/example/relativeURIWithNoBase> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/SomeRDFSClass> .
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<tag:relativeURIWithNoBase> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/SomeRDFSClass> .
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{
2+
"@context": {"@base": "http://a/bb/ccc/d;p?q", "urn:ex:p": {"@type": "@id"}},
3+
"@graph": [
4+
{"@id": "urn:ex:s001", "urn:ex:p": "g:h"},
5+
{"@id": "urn:ex:s002", "urn:ex:p": "g"},
6+
{"@id": "urn:ex:s003", "urn:ex:p": "./g"},
7+
{"@id": "urn:ex:s004", "urn:ex:p": "g/"},
8+
{"@id": "urn:ex:s005", "urn:ex:p": "/g"},
9+
{"@id": "urn:ex:s006", "urn:ex:p": "//g"},
10+
{"@id": "urn:ex:s007", "urn:ex:p": "?y"},
11+
{"@id": "urn:ex:s008", "urn:ex:p": "g?y"},
12+
{"@id": "urn:ex:s009", "urn:ex:p": "#s"},
13+
{"@id": "urn:ex:s010", "urn:ex:p": "g#s"},
14+
{"@id": "urn:ex:s011", "urn:ex:p": "g?y#s"},
15+
{"@id": "urn:ex:s012", "urn:ex:p": ";x"},
16+
{"@id": "urn:ex:s013", "urn:ex:p": "g;x"},
17+
{"@id": "urn:ex:s014", "urn:ex:p": "g;x?y#s"},
18+
{"@id": "urn:ex:s015", "urn:ex:p": ""},
19+
{"@id": "urn:ex:s016", "urn:ex:p": "."},
20+
{"@id": "urn:ex:s017", "urn:ex:p": "./"},
21+
{"@id": "urn:ex:s018", "urn:ex:p": ".."},
22+
{"@id": "urn:ex:s019", "urn:ex:p": "../"},
23+
{"@id": "urn:ex:s020", "urn:ex:p": "../g"},
24+
{"@id": "urn:ex:s021", "urn:ex:p": "../.."},
25+
{"@id": "urn:ex:s022", "urn:ex:p": "../../"},
26+
{"@id": "urn:ex:s023", "urn:ex:p": "../../g"},
27+
{"@id": "urn:ex:s024", "urn:ex:p": "../../../g"},
28+
{"@id": "urn:ex:s025", "urn:ex:p": "../../../../g"},
29+
{"@id": "urn:ex:s026", "urn:ex:p": "/./g"},
30+
{"@id": "urn:ex:s027", "urn:ex:p": "/../g"},
31+
{"@id": "urn:ex:s028", "urn:ex:p": "g."},
32+
{"@id": "urn:ex:s029", "urn:ex:p": ".g"},
33+
{"@id": "urn:ex:s030", "urn:ex:p": "g.."},
34+
{"@id": "urn:ex:s031", "urn:ex:p": "..g"},
35+
{"@id": "urn:ex:s032", "urn:ex:p": "./../g"},
36+
{"@id": "urn:ex:s033", "urn:ex:p": "./g/."},
37+
{"@id": "urn:ex:s034", "urn:ex:p": "g/./h"},
38+
{"@id": "urn:ex:s035", "urn:ex:p": "g/../h"},
39+
{"@id": "urn:ex:s036", "urn:ex:p": "g;x=1/./y"},
40+
{"@id": "urn:ex:s037", "urn:ex:p": "g;x=1/../y"},
41+
{"@id": "urn:ex:s038", "urn:ex:p": "g?y/./x"},
42+
{"@id": "urn:ex:s039", "urn:ex:p": "g?y/../x"},
43+
{"@id": "urn:ex:s040", "urn:ex:p": "g#s/./x"},
44+
{"@id": "urn:ex:s041", "urn:ex:p": "g#s/../x"},
45+
{"@id": "urn:ex:s042", "urn:ex:p": "http:g"}
46+
]
47+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<urn:ex:s001> <urn:ex:p> <g:h> .
2+
<urn:ex:s002> <urn:ex:p> <http://a/bb/ccc/g> .
3+
<urn:ex:s003> <urn:ex:p> <http://a/bb/ccc/g> .
4+
<urn:ex:s004> <urn:ex:p> <http://a/bb/ccc/g/> .
5+
<urn:ex:s005> <urn:ex:p> <http://a/g> .
6+
<urn:ex:s006> <urn:ex:p> <http://g> .
7+
<urn:ex:s007> <urn:ex:p> <http://a/bb/ccc/d;p?y> .
8+
<urn:ex:s008> <urn:ex:p> <http://a/bb/ccc/g?y> .
9+
<urn:ex:s009> <urn:ex:p> <http://a/bb/ccc/d;p?q#s> .
10+
<urn:ex:s010> <urn:ex:p> <http://a/bb/ccc/g#s> .
11+
<urn:ex:s011> <urn:ex:p> <http://a/bb/ccc/g?y#s> .
12+
<urn:ex:s012> <urn:ex:p> <http://a/bb/ccc/;x> .
13+
<urn:ex:s013> <urn:ex:p> <http://a/bb/ccc/g;x> .
14+
<urn:ex:s014> <urn:ex:p> <http://a/bb/ccc/g;x?y#s> .
15+
<urn:ex:s015> <urn:ex:p> <http://a/bb/ccc/d;p?q> .
16+
<urn:ex:s016> <urn:ex:p> <http://a/bb/ccc/> .
17+
<urn:ex:s017> <urn:ex:p> <http://a/bb/ccc/> .
18+
<urn:ex:s018> <urn:ex:p> <http://a/bb/> .
19+
<urn:ex:s019> <urn:ex:p> <http://a/bb/> .
20+
<urn:ex:s020> <urn:ex:p> <http://a/bb/g> .
21+
<urn:ex:s021> <urn:ex:p> <http://a/> .
22+
<urn:ex:s022> <urn:ex:p> <http://a/> .
23+
<urn:ex:s023> <urn:ex:p> <http://a/g> .
24+
<urn:ex:s024> <urn:ex:p> <http://a/g> .
25+
<urn:ex:s025> <urn:ex:p> <http://a/g> .
26+
<urn:ex:s026> <urn:ex:p> <http://a/g> .
27+
<urn:ex:s027> <urn:ex:p> <http://a/g> .
28+
<urn:ex:s028> <urn:ex:p> <http://a/bb/ccc/g.> .
29+
<urn:ex:s029> <urn:ex:p> <http://a/bb/ccc/.g> .
30+
<urn:ex:s030> <urn:ex:p> <http://a/bb/ccc/g..> .
31+
<urn:ex:s031> <urn:ex:p> <http://a/bb/ccc/..g> .
32+
<urn:ex:s032> <urn:ex:p> <http://a/bb/g> .
33+
<urn:ex:s033> <urn:ex:p> <http://a/bb/ccc/g/> .
34+
<urn:ex:s034> <urn:ex:p> <http://a/bb/ccc/g/h> .
35+
<urn:ex:s035> <urn:ex:p> <http://a/bb/ccc/h> .
36+
<urn:ex:s036> <urn:ex:p> <http://a/bb/ccc/g;x=1/y> .
37+
<urn:ex:s037> <urn:ex:p> <http://a/bb/ccc/y> .
38+
<urn:ex:s038> <urn:ex:p> <http://a/bb/ccc/g?y/./x> .
39+
<urn:ex:s039> <urn:ex:p> <http://a/bb/ccc/g?y/../x> .
40+
<urn:ex:s040> <urn:ex:p> <http://a/bb/ccc/g#s/./x> .
41+
<urn:ex:s041> <urn:ex:p> <http://a/bb/ccc/g#s/../x> .
42+
<urn:ex:s042> <urn:ex:p> <http:g> .
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{
2+
"@context": {"@base": "http://a/bb/ccc/d/", "urn:ex:p": {"@type": "@id"}},
3+
"@graph": [
4+
{"@id": "urn:ex:s043", "urn:ex:p": "g:h"},
5+
{"@id": "urn:ex:s044", "urn:ex:p": "g"},
6+
{"@id": "urn:ex:s045", "urn:ex:p": "./g"},
7+
{"@id": "urn:ex:s046", "urn:ex:p": "g/"},
8+
{"@id": "urn:ex:s047", "urn:ex:p": "/g"},
9+
{"@id": "urn:ex:s048", "urn:ex:p": "//g"},
10+
{"@id": "urn:ex:s049", "urn:ex:p": "?y"},
11+
{"@id": "urn:ex:s050", "urn:ex:p": "g?y"},
12+
{"@id": "urn:ex:s051", "urn:ex:p": "#s"},
13+
{"@id": "urn:ex:s052", "urn:ex:p": "g#s"},
14+
{"@id": "urn:ex:s053", "urn:ex:p": "g?y#s"},
15+
{"@id": "urn:ex:s054", "urn:ex:p": ";x"},
16+
{"@id": "urn:ex:s055", "urn:ex:p": "g;x"},
17+
{"@id": "urn:ex:s056", "urn:ex:p": "g;x?y#s"},
18+
{"@id": "urn:ex:s057", "urn:ex:p": ""},
19+
{"@id": "urn:ex:s058", "urn:ex:p": "."},
20+
{"@id": "urn:ex:s059", "urn:ex:p": "./"},
21+
{"@id": "urn:ex:s060", "urn:ex:p": ".."},
22+
{"@id": "urn:ex:s061", "urn:ex:p": "../"},
23+
{"@id": "urn:ex:s062", "urn:ex:p": "../g"},
24+
{"@id": "urn:ex:s063", "urn:ex:p": "../.."},
25+
{"@id": "urn:ex:s064", "urn:ex:p": "../../"},
26+
{"@id": "urn:ex:s065", "urn:ex:p": "../../g"},
27+
{"@id": "urn:ex:s066", "urn:ex:p": "../../../g"},
28+
{"@id": "urn:ex:s067", "urn:ex:p": "../../../../g"},
29+
{"@id": "urn:ex:s068", "urn:ex:p": "/./g"},
30+
{"@id": "urn:ex:s069", "urn:ex:p": "/../g"},
31+
{"@id": "urn:ex:s070", "urn:ex:p": "g."},
32+
{"@id": "urn:ex:s071", "urn:ex:p": ".g"},
33+
{"@id": "urn:ex:s072", "urn:ex:p": "g.."},
34+
{"@id": "urn:ex:s073", "urn:ex:p": "..g"},
35+
{"@id": "urn:ex:s074", "urn:ex:p": "./../g"},
36+
{"@id": "urn:ex:s075", "urn:ex:p": "./g/."},
37+
{"@id": "urn:ex:s076", "urn:ex:p": "g/./h"},
38+
{"@id": "urn:ex:s077", "urn:ex:p": "g/../h"},
39+
{"@id": "urn:ex:s078", "urn:ex:p": "g;x=1/./y"},
40+
{"@id": "urn:ex:s079", "urn:ex:p": "g;x=1/../y"},
41+
{"@id": "urn:ex:s080", "urn:ex:p": "g?y/./x"},
42+
{"@id": "urn:ex:s081", "urn:ex:p": "g?y/../x"},
43+
{"@id": "urn:ex:s082", "urn:ex:p": "g#s/./x"},
44+
{"@id": "urn:ex:s083", "urn:ex:p": "g#s/../x"},
45+
{"@id": "urn:ex:s084", "urn:ex:p": "http:g"}
46+
]
47+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<urn:ex:s043> <urn:ex:p> <g:h> .
2+
<urn:ex:s044> <urn:ex:p> <http://a/bb/ccc/d/g> .
3+
<urn:ex:s045> <urn:ex:p> <http://a/bb/ccc/d/g> .
4+
<urn:ex:s046> <urn:ex:p> <http://a/bb/ccc/d/g/> .
5+
<urn:ex:s047> <urn:ex:p> <http://a/g> .
6+
<urn:ex:s048> <urn:ex:p> <http://g> .
7+
<urn:ex:s049> <urn:ex:p> <http://a/bb/ccc/d/?y> .
8+
<urn:ex:s050> <urn:ex:p> <http://a/bb/ccc/d/g?y> .
9+
<urn:ex:s051> <urn:ex:p> <http://a/bb/ccc/d/#s> .
10+
<urn:ex:s052> <urn:ex:p> <http://a/bb/ccc/d/g#s> .
11+
<urn:ex:s053> <urn:ex:p> <http://a/bb/ccc/d/g?y#s> .
12+
<urn:ex:s054> <urn:ex:p> <http://a/bb/ccc/d/;x> .
13+
<urn:ex:s055> <urn:ex:p> <http://a/bb/ccc/d/g;x> .
14+
<urn:ex:s056> <urn:ex:p> <http://a/bb/ccc/d/g;x?y#s> .
15+
<urn:ex:s057> <urn:ex:p> <http://a/bb/ccc/d/> .
16+
<urn:ex:s058> <urn:ex:p> <http://a/bb/ccc/d/> .
17+
<urn:ex:s059> <urn:ex:p> <http://a/bb/ccc/d/> .
18+
<urn:ex:s060> <urn:ex:p> <http://a/bb/ccc/> .
19+
<urn:ex:s061> <urn:ex:p> <http://a/bb/ccc/> .
20+
<urn:ex:s062> <urn:ex:p> <http://a/bb/ccc/g> .
21+
<urn:ex:s063> <urn:ex:p> <http://a/bb/> .
22+
<urn:ex:s064> <urn:ex:p> <http://a/bb/> .
23+
<urn:ex:s065> <urn:ex:p> <http://a/bb/g> .
24+
<urn:ex:s066> <urn:ex:p> <http://a/g> .
25+
<urn:ex:s067> <urn:ex:p> <http://a/g> .
26+
<urn:ex:s068> <urn:ex:p> <http://a/g> .
27+
<urn:ex:s069> <urn:ex:p> <http://a/g> .
28+
<urn:ex:s070> <urn:ex:p> <http://a/bb/ccc/d/g.> .
29+
<urn:ex:s071> <urn:ex:p> <http://a/bb/ccc/d/.g> .
30+
<urn:ex:s072> <urn:ex:p> <http://a/bb/ccc/d/g..> .
31+
<urn:ex:s073> <urn:ex:p> <http://a/bb/ccc/d/..g> .
32+
<urn:ex:s074> <urn:ex:p> <http://a/bb/ccc/g> .
33+
<urn:ex:s075> <urn:ex:p> <http://a/bb/ccc/d/g/> .
34+
<urn:ex:s076> <urn:ex:p> <http://a/bb/ccc/d/g/h> .
35+
<urn:ex:s077> <urn:ex:p> <http://a/bb/ccc/d/h> .
36+
<urn:ex:s078> <urn:ex:p> <http://a/bb/ccc/d/g;x=1/y> .
37+
<urn:ex:s079> <urn:ex:p> <http://a/bb/ccc/d/y> .
38+
<urn:ex:s080> <urn:ex:p> <http://a/bb/ccc/d/g?y/./x> .
39+
<urn:ex:s081> <urn:ex:p> <http://a/bb/ccc/d/g?y/../x> .
40+
<urn:ex:s082> <urn:ex:p> <http://a/bb/ccc/d/g#s/./x> .
41+
<urn:ex:s083> <urn:ex:p> <http://a/bb/ccc/d/g#s/../x> .
42+
<urn:ex:s084> <urn:ex:p> <http:g> .
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{
2+
"@context": {"@base": "http://a/bb/ccc/./d;p?q", "urn:ex:p": {"@type": "@id"}},
3+
"@graph": [
4+
{"@id": "urn:ex:s085", "urn:ex:p": "g:h"},
5+
{"@id": "urn:ex:s086", "urn:ex:p": "g"},
6+
{"@id": "urn:ex:s087", "urn:ex:p": "./g"},
7+
{"@id": "urn:ex:s088", "urn:ex:p": "g/"},
8+
{"@id": "urn:ex:s089", "urn:ex:p": "/g"},
9+
{"@id": "urn:ex:s090", "urn:ex:p": "//g"},
10+
{"@id": "urn:ex:s091", "urn:ex:p": "?y"},
11+
{"@id": "urn:ex:s092", "urn:ex:p": "g?y"},
12+
{"@id": "urn:ex:s093", "urn:ex:p": "#s"},
13+
{"@id": "urn:ex:s094", "urn:ex:p": "g#s"},
14+
{"@id": "urn:ex:s095", "urn:ex:p": "g?y#s"},
15+
{"@id": "urn:ex:s096", "urn:ex:p": ";x"},
16+
{"@id": "urn:ex:s097", "urn:ex:p": "g;x"},
17+
{"@id": "urn:ex:s098", "urn:ex:p": "g;x?y#s"},
18+
{"@id": "urn:ex:s099", "urn:ex:p": ""},
19+
{"@id": "urn:ex:s100", "urn:ex:p": "."},
20+
{"@id": "urn:ex:s101", "urn:ex:p": "./"},
21+
{"@id": "urn:ex:s102", "urn:ex:p": ".."},
22+
{"@id": "urn:ex:s103", "urn:ex:p": "../"},
23+
{"@id": "urn:ex:s104", "urn:ex:p": "../g"},
24+
{"@id": "urn:ex:s105", "urn:ex:p": "../.."},
25+
{"@id": "urn:ex:s106", "urn:ex:p": "../../"},
26+
{"@id": "urn:ex:s107", "urn:ex:p": "../../g"},
27+
{"@id": "urn:ex:s108", "urn:ex:p": "../../../g"},
28+
{"@id": "urn:ex:s109", "urn:ex:p": "../../../../g"},
29+
{"@id": "urn:ex:s110", "urn:ex:p": "/./g"},
30+
{"@id": "urn:ex:s111", "urn:ex:p": "/../g"},
31+
{"@id": "urn:ex:s112", "urn:ex:p": "g."},
32+
{"@id": "urn:ex:s113", "urn:ex:p": ".g"},
33+
{"@id": "urn:ex:s114", "urn:ex:p": "g.."},
34+
{"@id": "urn:ex:s115", "urn:ex:p": "..g"},
35+
{"@id": "urn:ex:s116", "urn:ex:p": "./../g"},
36+
{"@id": "urn:ex:s117", "urn:ex:p": "./g/."},
37+
{"@id": "urn:ex:s118", "urn:ex:p": "g/./h"},
38+
{"@id": "urn:ex:s119", "urn:ex:p": "g/../h"},
39+
{"@id": "urn:ex:s120", "urn:ex:p": "g;x=1/./y"},
40+
{"@id": "urn:ex:s121", "urn:ex:p": "g;x=1/../y"},
41+
{"@id": "urn:ex:s122", "urn:ex:p": "g?y/./x"},
42+
{"@id": "urn:ex:s123", "urn:ex:p": "g?y/../x"},
43+
{"@id": "urn:ex:s124", "urn:ex:p": "g#s/./x"},
44+
{"@id": "urn:ex:s125", "urn:ex:p": "g#s/../x"},
45+
{"@id": "urn:ex:s126", "urn:ex:p": "http:g"}
46+
]
47+
}

0 commit comments

Comments
 (0)