JENA-908: Flush unwritten nodes due to bnode cycles
Project: http://git-wip-us.apache.org/repos/asf/jena/repo Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/76d77cc6 Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/76d77cc6 Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/76d77cc6 Branch: refs/heads/master Commit: 76d77cc6c5fce0d4163125ca8f61d5c4717ce78a Parents: c05169e Author: Andy Seaborne <[email protected]> Authored: Tue Mar 31 20:41:55 2015 +0100 Committer: Andy Seaborne <[email protected]> Committed: Tue Mar 31 20:41:55 2015 +0100 ---------------------------------------------------------------------- .../org/apache/jena/riot/system/RiotLib.java | 2 +- .../apache/jena/riot/writer/TurtleShell.java | 96 +++++++++++++------- .../jena/riot/writer/TestJenaWriters.java | 18 ---- .../jena/riot/writer/TestRiotWriterGraph.java | 1 + jena-arq/testing/RIOT/Writer/writer-rt-18.ttl | 12 +++ jena-arq/testing/RIOT/Writer/writer-rt-19.ttl | 18 ++++ 6 files changed, 96 insertions(+), 51 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/jena/blob/76d77cc6/jena-arq/src/main/java/org/apache/jena/riot/system/RiotLib.java ---------------------------------------------------------------------- diff --git a/jena-arq/src/main/java/org/apache/jena/riot/system/RiotLib.java b/jena-arq/src/main/java/org/apache/jena/riot/system/RiotLib.java index b4061c6..33593c9 100644 --- a/jena-arq/src/main/java/org/apache/jena/riot/system/RiotLib.java +++ b/jena-arq/src/main/java/org/apache/jena/riot/system/RiotLib.java @@ -257,7 +257,7 @@ public class RiotLib return PrefixMapFactory.create(dsg.getDefaultGraph().getPrefixMapping()) ; } - private static int calcWidth(PrefixMap prefixMap, String baseURI, Node p) + public static int calcWidth(PrefixMap prefixMap, String baseURI, Node p) { if ( ! prefixMap.contains(rdfNS) && RDF_type.equals(p) ) return 1 ; http://git-wip-us.apache.org/repos/asf/jena/blob/76d77cc6/jena-arq/src/main/java/org/apache/jena/riot/writer/TurtleShell.java ---------------------------------------------------------------------- diff --git a/jena-arq/src/main/java/org/apache/jena/riot/writer/TurtleShell.java b/jena-arq/src/main/java/org/apache/jena/riot/writer/TurtleShell.java index 0162c6c..57c4198 100644 --- a/jena-arq/src/main/java/org/apache/jena/riot/writer/TurtleShell.java +++ b/jena-arq/src/main/java/org/apache/jena/riot/writer/TurtleShell.java @@ -39,6 +39,7 @@ import org.apache.jena.atlas.io.IndentedWriter ; import org.apache.jena.atlas.iterator.Iter ; import org.apache.jena.atlas.lib.Lib ; import org.apache.jena.atlas.lib.Pair ; +import org.apache.jena.atlas.lib.SetUtils ; import org.apache.jena.riot.other.GLib ; import org.apache.jena.riot.out.NodeFormatter ; import org.apache.jena.riot.out.NodeFormatterTTL ; @@ -109,6 +110,7 @@ public abstract class TurtleShell { // Blank nodes that have one incoming triple private final Set<Node> nestedObjects ; + private final Set<Node> nestedObjectsWritten ; // Blank node subjects that are not referenced as objects or graph names // excluding unlnked lists. @@ -134,13 +136,13 @@ public abstract class TurtleShell { this.graph = graph ; this.nestedObjects = new HashSet<>() ; + this.nestedObjectsWritten = new HashSet<>() ; this.freeBnodes = new HashSet<>() ; this.lists = new HashMap<>() ; this.freeLists = new HashMap<>() ; this.nLinkedLists = new HashMap<>() ; this.listElts = new HashSet<>() ; - // Must be in this order. findLists() ; @@ -431,23 +433,23 @@ public abstract class TurtleShell { // ---- private void writeGraph() { + Iterator<Node> subjects = listSubjects() ; boolean somethingWritten = writeBySubject(subjects) ; // Write remainders // 1 - Shared lists + somethingWritten = writeRemainingNLinkedLists(somethingWritten) ; // 2 - Free standing lists - - if ( !nLinkedLists.isEmpty() ) - somethingWritten = writeNLinkedLists(somethingWritten) ; - - if ( !freeLists.isEmpty() ) - somethingWritten = writeFreeLists(somethingWritten) ; - + somethingWritten = writeRemainingFreeLists(somethingWritten) ; + + // 3 - Blank nodes that are unwrittern single objects. + Set<Node> singleNodes = SetUtils.difference(nestedObjects, nestedObjectsWritten) ; + somethingWritten = writeRemainingNestedObjects(singleNodes, somethingWritten) ; } - // Write lists that are shared objects - private boolean writeNLinkedLists(boolean somethingWritten) { + // Write any lists that are shared objects + private boolean writeRemainingNLinkedLists(boolean somethingWritten) { // Print carefully - need a label for the first cell. // So we write out the first element of the list in triples, then // put @@ -460,14 +462,9 @@ public abstract class TurtleShell { List<Node> x = nLinkedLists.get(n) ; writeNode(n) ; - if ( out.getCol() > LONG_SUBJECT ) - println() ; - else - gap(GAP_S_P) ; - out.incIndent(INDENT_PREDICATE) ; - // ---- - // DRY writeCluster. + write_S_P_Gap(); out.pad() ; + writeNode(RDF_First) ; print(" ") ; writeNode(x.get(0)) ; @@ -485,12 +482,9 @@ public abstract class TurtleShell { } // Write free standing lists - ones where the head is not an object of - // some other triple. - // Turtle does not (... ) . so write as a predicateObjectList for one - // element. - private boolean writeFreeLists(boolean somethingWritten) { - // out.println("# Free standing lists") ; - // Write free lists. + // some other triple. Turtle does not allow free standing (... ) . + // so write as a predicateObjectList for one element. + private boolean writeRemainingFreeLists(boolean somethingWritten) { for ( Node n : freeLists.keySet() ) { if ( somethingWritten ) out.println() ; @@ -514,6 +508,33 @@ public abstract class TurtleShell { return somethingWritten ; } + // Write any left over nested objects + // These come from blank node cycles : _:a <p> _:b . _b: <p> _:b . + private boolean writeRemainingNestedObjects(Set<Node> objects, boolean somethingWritten) { + for ( Node n : objects ) { + Iterator<Triple> iter = graph.find(null, null, n) ; + somethingWritten = true ; + if ( somethingWritten ) + out.println() ; + while(iter.hasNext()) { + Triple t = iter.next() ; + writeNode(t.getSubject()) ; + write_S_P_Gap(); + + out.incIndent(INDENT_PREDICATE) ; + Node p = t.getPredicate() ; + int pWidth = RiotLib.calcWidth(prefixMap, baseURI, p) ; + writePredicate(p, pWidth, true) ; + writeNode(t.getObject()) ; + out.decIndent(INDENT_PREDICATE) ; + print(" .") ; + println() ; + } + } + + return somethingWritten ; + } + // return true if did write something. private boolean writeBySubject(Iterator<Node> subjects) { boolean first = true ; @@ -521,7 +542,6 @@ public abstract class TurtleShell { Node subj = subjects.next() ; if ( nestedObjects.contains(subj) ) continue ; - if ( listElts.contains(subj) ) continue ; if ( !first ) @@ -529,7 +549,7 @@ public abstract class TurtleShell { first = false ; if ( freeBnodes.contains(subj) ) { // Write in "[....]" form. - nestedObject(subj) ; + writeNestedObject(subj) ; out.println(" .") ; continue ; } @@ -546,11 +566,7 @@ public abstract class TurtleShell { if ( cluster.isEmpty() ) return ; writeNode(subject) ; - - if ( out.getCol() > LONG_SUBJECT ) - out.println() ; - else - gap(GAP_S_P) ; + write_S_P_Gap() ; out.incIndent(INDENT_PREDICATE) ; out.pad() ; writePredicateObjectList(cluster) ; @@ -689,7 +705,7 @@ public abstract class TurtleShell { return x.size() ; } - private void nestedObject(Node node) { + private void writeNestedObject(Node node) { Collection<Triple> x = triplesOfSubject(node) ; if ( x.isEmpty() ) { @@ -758,11 +774,27 @@ public abstract class TurtleShell { if ( lists.containsKey(obj) ) list(lists.get(obj)) ; else if ( nestedObjects.contains(obj) ) - nestedObject(obj) ; + writeNestedObject(obj) ; else if ( RDF_Nil.equals(obj) ) out.println("()") ; else writeNode(obj) ; + if ( nestedObjects.contains(obj) ) + nestedObjectsWritten.add(obj) ; + + } + + // Order of properties. + // rdf:type ("a") + // RDF and RDFS + // Other. + // Sorted by URI. + + private void write_S_P_Gap() { + if ( out.getCol() > LONG_SUBJECT ) + out.println() ; + else + gap(GAP_S_P) ; } } http://git-wip-us.apache.org/repos/asf/jena/blob/76d77cc6/jena-arq/src/test/java/org/apache/jena/riot/writer/TestJenaWriters.java ---------------------------------------------------------------------- diff --git a/jena-arq/src/test/java/org/apache/jena/riot/writer/TestJenaWriters.java b/jena-arq/src/test/java/org/apache/jena/riot/writer/TestJenaWriters.java index da2ea08..153e0c1 100644 --- a/jena-arq/src/test/java/org/apache/jena/riot/writer/TestJenaWriters.java +++ b/jena-arq/src/test/java/org/apache/jena/riot/writer/TestJenaWriters.java @@ -58,24 +58,6 @@ public class TestJenaWriters extends AbstractWriterTest // We are not testing the correctness of the writers, // only the wiring up of the writers to model.write. -// @Test public void jwrite_01() { test("writer-rt-00.ttl") ; } -// @Test public void jwrite_01() { test("writer-rt-01.ttl") ; } -// @Test public void jwrite_02() { test("writer-rt-02.ttl") ; } -// @Test public void jwrite_03() { test("writer-rt-03.ttl") ; } -// @Test public void jwrite_04() { test("writer-rt-04.ttl") ; } -// @Test public void jwrite_05() { test("writer-rt-05.ttl") ; } -// @Test public void jwrite_06() { test("writer-rt-06.ttl") ; } -// @Test public void jwrite_07() { test("writer-rt-07.ttl") ; } -// @Test public void jwrite_08() { test("writer-rt-08.ttl") ; } -// @Test public void jwrite_09() { test("writer-rt-09.ttl") ; } -// @Test public void jwrite_10() { test("writer-rt-10.ttl") ; } -// @Test public void jwrite_11() { test("writer-rt-11.ttl") ; } -// @Test public void jwrite_12() { test("writer-rt-12.ttl") ; } -// @Test public void jwrite_13() { test("writer-rt-13.ttl") ; } -// @Test public void jwrite_14() { test("writer-rt-14.ttl") ; } -// @Test public void jwrite_15() { test("writer-rt-15.ttl") ; } -// @Test public void jwrite_16() { test("writer-rt-16.ttl") ; } - private void test(String filename) { Model m = readModel(filename) ; ByteArrayOutputStream out2 = new ByteArrayOutputStream() ; http://git-wip-us.apache.org/repos/asf/jena/blob/76d77cc6/jena-arq/src/test/java/org/apache/jena/riot/writer/TestRiotWriterGraph.java ---------------------------------------------------------------------- diff --git a/jena-arq/src/test/java/org/apache/jena/riot/writer/TestRiotWriterGraph.java b/jena-arq/src/test/java/org/apache/jena/riot/writer/TestRiotWriterGraph.java index c179f8d..880d7fa 100644 --- a/jena-arq/src/test/java/org/apache/jena/riot/writer/TestRiotWriterGraph.java +++ b/jena-arq/src/test/java/org/apache/jena/riot/writer/TestRiotWriterGraph.java @@ -106,6 +106,7 @@ public class TestRiotWriterGraph extends AbstractWriterTest @Test public void writer15() { test("writer-rt-15.ttl") ; } @Test public void writer16() { test("writer-rt-16.ttl") ; } @Test public void writer17() { test("writer-rt-17.ttl") ; } + @Test public void writer18() { test("writer-rt-18.ttl") ; } private void test(String filename) { http://git-wip-us.apache.org/repos/asf/jena/blob/76d77cc6/jena-arq/testing/RIOT/Writer/writer-rt-18.ttl ---------------------------------------------------------------------- diff --git a/jena-arq/testing/RIOT/Writer/writer-rt-18.ttl b/jena-arq/testing/RIOT/Writer/writer-rt-18.ttl new file mode 100644 index 0000000..dbf4c3e --- /dev/null +++ b/jena-arq/testing/RIOT/Writer/writer-rt-18.ttl @@ -0,0 +1,12 @@ +@prefix : <http://example/> . +@prefix ns: <http://example/ns#> . +@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . + +# Blank node cycle. + +_:aaa :p _:bbb . +_:bbb :q _:aaa . + +_:b1 :p _:b2 . +_:b2 :q _:b3 . +_:b3 :r _:b1 . http://git-wip-us.apache.org/repos/asf/jena/blob/76d77cc6/jena-arq/testing/RIOT/Writer/writer-rt-19.ttl ---------------------------------------------------------------------- diff --git a/jena-arq/testing/RIOT/Writer/writer-rt-19.ttl b/jena-arq/testing/RIOT/Writer/writer-rt-19.ttl new file mode 100644 index 0000000..4eb690f --- /dev/null +++ b/jena-arq/testing/RIOT/Writer/writer-rt-19.ttl @@ -0,0 +1,18 @@ +@prefix : <http://example/> . +@prefix ns: <http://example/ns#> . +@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . + +# Blank node cycles and other one-connected objects together. + +:s :pp [] . +:s :pp [] . + +_:aaa :p _:bbb . +_:bbb :q _:aaa . + +_:b1 :p _:b2 . +_:b2 :q _:b3 . +_:b3 :r _:b1 . + +# +:s rdf:rest ( 1 ) .
