Skip to content

Commit 71b7f41

Browse files
committed
GH-3681 Fix TurtleWriter list handling for rdf:type rdf:List
1 parent 2f6ae3b commit 71b7f41

2 files changed

Lines changed: 45 additions & 0 deletions

File tree

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,11 @@ protected void handleStatementInternal(Statement st, boolean endRDFCalled, boole
305305

306306
try {
307307
if (inlineBNodes) {
308+
if (pred.equals(RDF.TYPE) && obj.equals(RDF.LIST) && subj instanceof BNode
309+
&& isWellFormedCollection(subj)) {
310+
// skip explicit rdf:type rdf:List for collections we will inline as Turtle lists
311+
return;
312+
}
308313
if ((pred.equals(RDF.FIRST) || pred.equals(RDF.REST)) && isWellFormedCollection(subj)) {
309314
// we only use list shorthand syntax if the collection is considered well-formed
310315
handleList(st, canShortenObjectBNode);
@@ -357,6 +362,9 @@ private boolean isWellFormedCollection(Resource subj) {
357362
// second rdf:rest statement on same subject is invalid.
358363
return false;
359364
}
365+
} else if (pred.equals(RDF.TYPE) && RDF.LIST.equals(st.getObject())) {
366+
// allow explicit rdf:type rdf:List
367+
continue;
360368
} else {
361369
// non-list-structure statement connected to collection subject blank node
362370
return false;

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

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,17 @@
1515

1616
import java.io.StringReader;
1717
import java.io.StringWriter;
18+
import java.util.List;
1819

20+
import org.eclipse.rdf4j.model.BNode;
1921
import org.eclipse.rdf4j.model.IRI;
2022
import org.eclipse.rdf4j.model.Model;
2123
import org.eclipse.rdf4j.model.impl.DynamicModelFactory;
24+
import org.eclipse.rdf4j.model.impl.TreeModel;
2225
import org.eclipse.rdf4j.model.util.Models;
26+
import org.eclipse.rdf4j.model.util.RDFCollections;
27+
import org.eclipse.rdf4j.model.util.Values;
28+
import org.eclipse.rdf4j.model.vocabulary.RDF;
2329
import org.eclipse.rdf4j.model.vocabulary.RDFS;
2430
import org.eclipse.rdf4j.rio.RDFFormat;
2531
import org.eclipse.rdf4j.rio.Rio;
@@ -390,6 +396,37 @@ public void testBNodeValuesInList() throws Exception {
390396
assertTrue(Models.isomorphic(expected, actual));
391397
}
392398

399+
@Test
400+
public void testRdfCollectionsListNotFullyInlined() throws Exception {
401+
String namespace = "http://example.com/ns#";
402+
IRI cities = Values.iri(namespace, "Cities");
403+
IRI listPredicate = Values.iri(namespace, "list");
404+
BNode listHead = vf.createBNode("n1");
405+
406+
Model model = new TreeModel();
407+
model.setNamespace("ex", namespace);
408+
model.setNamespace("rdf", RDF.NAMESPACE);
409+
410+
RDFCollections.asRDF(List.of(
411+
Values.iri(namespace, "NewYork"),
412+
Values.iri(namespace, "Rio"),
413+
Values.iri(namespace, "Tokyo")), listHead, model);
414+
model.add(cities, listPredicate, listHead);
415+
416+
WriterConfig config = new WriterConfig();
417+
config.set(BasicWriterSettings.INLINE_BLANK_NODES, true);
418+
config.set(BasicWriterSettings.PRETTY_PRINT, true);
419+
420+
StringWriter stringWriter = new StringWriter();
421+
Rio.write(model, stringWriter, RDFFormat.TURTLE, config);
422+
423+
String expected = String.join("\n", "@prefix ex: <http://example.com/ns#> .",
424+
"@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .",
425+
"", "ex:Cities ex:list (ex:NewYork ex:Rio ex:Tokyo) .", "");
426+
427+
assertThat(stringWriter.toString()).isEqualTo(expected);
428+
}
429+
393430
@Test
394431
public void testBNodeValuesInList2() throws Exception {
395432
String data = "" +

0 commit comments

Comments
 (0)