Skip to content

Commit 1c36f76

Browse files
committed
GH-4921 Turtle writer does not respect namespaces in IRIs
- Added tests to check to which degree parsing a Turtle file with unconventional prefixes and serializing it back again results preserves format
1 parent e2db6a9 commit 1c36f76

2 files changed

Lines changed: 59 additions & 8 deletions

File tree

core/rio/turtle/src/main/java/org/eclipse/rdf4j/rio/turtle/TurtleUtil.java

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -460,14 +460,17 @@ public static String encodeURIString(String s) {
460460
}
461461

462462
public static boolean isValidPrefixedName(String s) {
463-
final int numberOfCodePoints = s.codePointCount(0, s.length());
464-
for (int i = 1; i < numberOfCodePoints; i++) {
465-
final int codePoint = s.codePointAt(i);
466-
if (!isPN_CHARS(codePoint)) {
467-
return false;
468-
}
463+
if (s == null || s.isEmpty()) {
464+
return false;
469465
}
470-
return true;
466+
467+
if (!isPN_CHARS_BASE(s.codePointAt(0))) {
468+
return false;
469+
}
470+
471+
return s.codePoints() //
472+
.skip(1) // Skip the first code point
473+
.allMatch(TurtleUtil::isPN_CHARS);
471474
}
472475

473476
/**

core/rio/turtle/src/test/java/org/eclipse/rdf4j/rio/turtle/TurtleWriterTest.java

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.eclipse.rdf4j.model.Model;
2121
import org.eclipse.rdf4j.model.impl.DynamicModelFactory;
2222
import org.eclipse.rdf4j.model.util.Models;
23+
import org.eclipse.rdf4j.model.vocabulary.RDFS;
2324
import org.eclipse.rdf4j.rio.RDFFormat;
2425
import org.eclipse.rdf4j.rio.Rio;
2526
import org.eclipse.rdf4j.rio.WriterConfig;
@@ -97,7 +98,6 @@ public void testBlankNodeInlining1() throws Exception {
9798
Model actual = Rio.parse(new StringReader(stringWriter.toString()), "", RDFFormat.TURTLE);
9899

99100
assertTrue(Models.isomorphic(expected, actual));
100-
101101
}
102102

103103
@Test
@@ -194,6 +194,54 @@ public void testNoBuffering() throws Exception {
194194
assertTrue(Models.isomorphic(expected, actual));
195195
}
196196

197+
@Test
198+
public void testUnusualIrisAndPrefixesParseWriteCompare() throws Exception {
199+
String data = "@prefix server-news: <news:comp.infosystems.www.servers.> .\n" +
200+
"@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n" +
201+
"server-news:unix rdfs:label \"News on Unix\" .\n" +
202+
"server-news:windows rdfs:label \"News on Windows\" .\n";
203+
204+
var expected = Rio.parse(new StringReader(data), "", RDFFormat.TURTLE);
205+
206+
var stringWriter = new StringWriter();
207+
var config = new WriterConfig();
208+
config.set(BasicWriterSettings.INLINE_BLANK_NODES, false);
209+
config.set(BasicWriterSettings.PRETTY_PRINT, false);
210+
Rio.write(expected, stringWriter, RDFFormat.TURTLE, config);
211+
212+
var actual = Rio.parse(new StringReader(stringWriter.toString()), "", RDFFormat.TURTLE);
213+
assertThat(Models.isomorphic(expected, actual)).as("isomorphic").isTrue();
214+
215+
assertThat(stringWriter.toString()).isEqualTo(data);
216+
}
217+
218+
@Test
219+
public void testUnusualIrisAndPrefixesWriteParserWriteCompare() throws Exception {
220+
var prefix = "server-news";
221+
var ns = "news:comp.infosystems.www.servers.";
222+
223+
var config = new WriterConfig();
224+
config.set(BasicWriterSettings.INLINE_BLANK_NODES, false);
225+
config.set(BasicWriterSettings.PRETTY_PRINT, false);
226+
227+
var expectedModel = new DynamicModelFactory().createEmptyModel();
228+
expectedModel.setNamespace(prefix, ns);
229+
expectedModel.setNamespace(RDFS.PREFIX, RDFS.NAMESPACE);
230+
expectedModel.add(vf.createIRI(ns, "unix"), RDFS.LABEL, vf.createLiteral("News on Unix"));
231+
expectedModel.add(vf.createIRI(ns, "windows"), RDFS.LABEL, vf.createLiteral("News on Windows"));
232+
233+
var turtle1 = new StringWriter();
234+
Rio.write(expectedModel, turtle1, RDFFormat.TURTLE, config);
235+
236+
var actualModel = Rio.parse(new StringReader(turtle1.toString()), "", RDFFormat.TURTLE);
237+
assertThat(Models.isomorphic(expectedModel, actualModel)).as("isomorphic").isTrue();
238+
239+
var turtle2 = new StringWriter();
240+
Rio.write(actualModel, turtle2, RDFFormat.TURTLE, config);
241+
242+
assertThat(turtle2.toString()).isEqualTo(turtle1.toString());
243+
}
244+
197245
@Test
198246
@Disabled
199247
public void anotherBnodeTest() throws Exception {

0 commit comments

Comments
 (0)