You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jena.apache.org by an...@apache.org on 2011/12/26 21:57:13 UTC

svn commit: r1224807 - in /incubator/jena/Scratch/AFS/Dev/trunk: ./ src/main/java/riot/

Author: andy
Date: Mon Dec 26 20:57:13 2011
New Revision: 1224807

URL: http://svn.apache.org/viewvc?rev=1224807&view=rev
Log:
Turtle writer rewrite (work-in-progress)

Added:
    incubator/jena/Scratch/AFS/Dev/trunk/D.trig
    incubator/jena/Scratch/AFS/Dev/trunk/D.ttl
    incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/TW2.java
    incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/TriGWriter.java
    incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/TurtleWriter2.java
    incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/TurtleWriterBlocks.java
    incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/TurtleWriterFlat.java

Added: incubator/jena/Scratch/AFS/Dev/trunk/D.trig
URL: http://svn.apache.org/viewvc/incubator/jena/Scratch/AFS/Dev/trunk/D.trig?rev=1224807&view=auto
==============================================================================
--- incubator/jena/Scratch/AFS/Dev/trunk/D.trig (added)
+++ incubator/jena/Scratch/AFS/Dev/trunk/D.trig Mon Dec 26 20:57:13 2011
@@ -0,0 +1,31 @@
+@prefix : <http://example/> .
+@prefix ns: <http://example/ns#> .
+@prefix rdf:     <http://www.w3.org/1999/02/22-rdf-syntax-ns#>  .
+
+{
+:s ns:p1 <http://other/planet> .
+:s ns:p2 123 .
+:s ns:p3 [] .
+:s a :T .
+}
+
+:g1 {
+:z :p1 _:a .
+:z :p2 _:a .
+
+<http://example2/LONGSUBJECT_URI> :p "foo" .
+:s1 <http://example2/LONGPREDICATE_URI>  "foo" .
+:s1 <http://example2/VERYVERY_VERY_VERY_LONGPREDICATE_URI>  "foo" .
+}
+
+:g2 {
+#:r ns:p4 (1 2 ) .
+
+:r ns:p5 [ ns:p "str" ] .
+
+:r ns:p5 [ ns:p [ ns:p 1 ] ] .
+:r ns:p5 [ ns:p [ ns:p 1 ; ns:p 2 ] ] .
+
+:r ns:p6 [ ns:q1 "str1" ; ns:q2 "str2" ] .
+:r ns:p7 [ ns:q1 "str1" ; ns:q2 "str2" ] .
+}
\ No newline at end of file

Added: incubator/jena/Scratch/AFS/Dev/trunk/D.ttl
URL: http://svn.apache.org/viewvc/incubator/jena/Scratch/AFS/Dev/trunk/D.ttl?rev=1224807&view=auto
==============================================================================
--- incubator/jena/Scratch/AFS/Dev/trunk/D.ttl (added)
+++ incubator/jena/Scratch/AFS/Dev/trunk/D.ttl Mon Dec 26 20:57:13 2011
@@ -0,0 +1,25 @@
+@prefix : <http://example/> .
+@prefix ns: <http://example/ns#> .
+@prefix rdf:     <http://www.w3.org/1999/02/22-rdf-syntax-ns#>  .
+
+:s ns:p1 <http://other/planet> .
+:s ns:p2 123 .
+:s ns:p3 [] .
+:s a :T .
+
+:z :p1 _:a .
+:z :p2 _:a .
+
+<http://example2/LONGSUBJECT_URI> :p "foo" .
+:s1 <http://example2/LONGPREDICATE_URI>  "foo" .
+:s1 <http://example2/VERYVERY_VERY_VERY_LONGPREDICATE_URI>  "foo" .
+
+#:r ns:p4 (1 2 ) .
+
+:r ns:p5 [ ns:p "str" ] .
+
+:r ns:p5 [ ns:p [ ns:p 1 ] ] .
+:r ns:p5 [ ns:p [ ns:p 1 ; ns:p 2 ] ] .
+
+:r ns:p6 [ ns:q1 "str1" ; ns:q2 "str2" ] .
+:r ns:p7 [ ns:q1 "str1" ; ns:q2 "str2" ] .

Added: incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/TW2.java
URL: http://svn.apache.org/viewvc/incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/TW2.java?rev=1224807&view=auto
==============================================================================
--- incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/TW2.java (added)
+++ incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/TW2.java Mon Dec 26 20:57:13 2011
@@ -0,0 +1,120 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package riot;
+
+import java.util.Collection ;
+import java.util.HashSet ;
+import java.util.Iterator ;
+import java.util.Set ;
+
+import org.openjena.atlas.iterator.Iter ;
+import org.openjena.atlas.iterator.Transform ;
+import org.openjena.atlas.lib.Pair ;
+
+import com.hp.hpl.jena.graph.Graph ;
+import com.hp.hpl.jena.graph.Node ;
+import com.hp.hpl.jena.graph.Triple ;
+import com.hp.hpl.jena.util.iterator.ExtendedIterator ;
+
+/** Support code for the RIOT TurtleWriter */ 
+public class TW2
+{
+    static final boolean recordObjectMisses = true ; 
+    
+    // Single, multi-function, pass over the graph 
+    
+    /** Find all embeddable objects */  
+    @SuppressWarnings("null")
+    static Pair<Set<Node>, Set<Triple>> findOneConnectedBNodeObjects(Graph graph)
+    {
+        ExtendedIterator<Triple> iter = graph.find(Node.ANY, Node.ANY, Node.ANY) ;
+
+        Set<Node> bNodesObj1 = new HashSet<Node>()  ;        // The subject of exactly one triple.
+        Set<Triple> triplesObj1 = new HashSet<Triple>()  ;   // The triples of such a thing. 
+        
+        Set<Node> rejects = recordObjectMisses ? new HashSet<Node>() : null ;      // Nodes known not to meet the requirement.
+        
+        for ( ; iter.hasNext() ; )
+        {
+            Triple t = iter.next() ;
+            Node obj = t.getObject() ;
+            if ( ! obj.isBlank() )
+                continue ;
+            if ( rejects != null && rejects.contains(obj) )
+                continue ;
+            // No point checking bNodesObj1.
+            Node n = connectedOnce(graph, obj) ;
+            if ( n != null )
+            {
+                bNodesObj1.add(n) ;
+                // find triples to skip.
+                accTriplesOfSubject(triplesObj1, graph, obj) ;
+            }
+        }
+        iter.close() ;
+        return Pair.create(bNodesObj1, triplesObj1) ;
+    }
+
+    // CALCULATE FOR LISTS
+    
+    static Transform<Triple, Node> subjects = new Transform<Triple, Node>() {
+
+        @Override
+        public Node convert(Triple item)
+        {
+            return item.getSubject() ;
+        }} ;
+    
+    // Combine into a single pass.
+    // DISTINCT means it's space using.
+    static Iterator<Node> subjects(Graph graph)
+    {
+        // Later: 
+        ExtendedIterator<Triple> iter = graph.find(Node.ANY, Node.ANY, Node.ANY) ;
+        return Iter.iter(iter).map(subjects).distinct() ;
+    }
+    
+    static Node connectedOnce(Graph graph, Node obj)
+    {
+        ExtendedIterator<Triple> iter = graph.find(Node.ANY, Node.ANY, obj) ;
+        int count = 0 ;
+        try {
+            if ( ! iter.hasNext() ) return null ;
+            iter.next() ;
+            if ( ! iter.hasNext() ) return obj ;
+            return null ;
+        } finally { iter.close() ; }
+    }
+    
+    static Collection<Triple> triplesOfSubject(Graph graph, Node subj)
+    {
+        Collection<Triple> x = new HashSet<Triple>() ;
+        accTriplesOfSubject(x, graph, subj) ;
+        return x ;
+    }
+
+    static void accTriplesOfSubject(Collection<Triple> acc, Graph graph, Node subj)
+    {
+        ExtendedIterator<Triple> iter = graph.find(subj, Node.ANY, Node.ANY) ;
+        for ( ; iter.hasNext() ; )
+            acc.add(iter.next()) ;
+        iter.close() ;
+    }
+}
+

Added: incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/TriGWriter.java
URL: http://svn.apache.org/viewvc/incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/TriGWriter.java?rev=1224807&view=auto
==============================================================================
--- incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/TriGWriter.java (added)
+++ incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/TriGWriter.java Mon Dec 26 20:57:13 2011
@@ -0,0 +1,98 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package riot;
+
+import java.io.FileInputStream ;
+import java.io.FileNotFoundException ;
+import java.io.OutputStream ;
+import java.util.Iterator ;
+import java.util.Map ;
+
+import org.openjena.atlas.io.IndentedWriter ;
+import org.openjena.atlas.lib.Sink ;
+import org.openjena.riot.Lang ;
+import org.openjena.riot.RiotReader ;
+import org.openjena.riot.lang.SinkQuadsToDataset ;
+import org.openjena.riot.tokens.Tokenizer ;
+import org.openjena.riot.tokens.TokenizerFactory ;
+
+import com.hp.hpl.jena.graph.Graph ;
+import com.hp.hpl.jena.graph.Node ;
+import com.hp.hpl.jena.query.Dataset ;
+import com.hp.hpl.jena.query.DatasetFactory ;
+import com.hp.hpl.jena.sparql.core.DatasetGraph ;
+import com.hp.hpl.jena.sparql.core.DatasetGraphFactory ;
+import com.hp.hpl.jena.sparql.core.Quad ;
+
+public class TriGWriter
+{
+    public static void main(String ... argv) throws FileNotFoundException
+    {
+        DatasetGraph dsg = DatasetGraphFactory.createMem() ; 
+        
+        Tokenizer tokenizer = TokenizerFactory.makeTokenizerUTF8(new FileInputStream("D.trig")) ;
+        
+        Sink<Quad> sink = new SinkQuadsToDataset(dsg) ;
+        RiotReader.createParserQuads(tokenizer,  Lang.TRIG, null, sink).parse() ;
+        sink.flush() ;
+        write(System.out, DatasetFactory.create(dsg)) ;
+    }
+    
+    public static final int GRAPH_INDENT = 4 ;
+    
+    public static void write(OutputStream out, Dataset dataset)
+    {
+        write(out, dataset.asDatasetGraph(), dataset.getDefaultModel().getNsPrefixMap()) ;
+    }
+    
+    public static void write(OutputStream out, DatasetGraph dsg,  Map<String, String> prefixMap)
+    {
+        IndentedWriter iOut = new IndentedWriter(out, false) ;
+        Iterator<Node> graphNames = dsg.listGraphNodes() ;
+        
+        writeGraph(iOut, null, dsg.getDefaultGraph(),  prefixMap) ;
+        
+        for ( ; graphNames.hasNext() ; )
+        {
+            iOut.println() ;
+            Node gn = graphNames.next() ;
+            writeGraph(iOut, gn, dsg.getGraph(gn),  prefixMap) ;
+        }
+        iOut.flush() ;
+        
+    }
+    
+    public static void writeGraph(IndentedWriter out, Node name, Graph graph,  Map<String, String> prefixMap)
+    {
+        if ( name != null )
+        {
+            TurtleWriter2.writeNode(out, name, prefixMap) ;
+            out.print("  ") ;
+        }
+        out.println("{") ;
+        out.incIndent(GRAPH_INDENT) ;
+        TurtleWriter2.write(out, graph, prefixMap) ;
+        
+        out.decIndent(GRAPH_INDENT) ;
+        out.ensureStartOfLine() ;
+        out.println("}") ;
+    }
+
+}
+

Added: incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/TurtleWriter2.java
URL: http://svn.apache.org/viewvc/incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/TurtleWriter2.java?rev=1224807&view=auto
==============================================================================
--- incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/TurtleWriter2.java (added)
+++ incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/TurtleWriter2.java Mon Dec 26 20:57:13 2011
@@ -0,0 +1,392 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package riot;
+
+import java.io.ByteArrayInputStream ;
+import java.io.ByteArrayOutputStream ;
+import java.io.OutputStream ;
+import java.util.* ;
+import java.util.Map.Entry ;
+
+import org.openjena.atlas.io.IndentedWriter ;
+import org.openjena.atlas.lib.Pair ;
+import org.openjena.atlas.lib.StrUtils ;
+import org.openjena.riot.SysRIOT ;
+
+import com.hp.hpl.jena.graph.Graph ;
+import com.hp.hpl.jena.graph.Node ;
+import com.hp.hpl.jena.graph.Triple ;
+import com.hp.hpl.jena.rdf.model.Model ;
+import com.hp.hpl.jena.rdf.model.ModelFactory ;
+import com.hp.hpl.jena.sparql.util.FmtUtils ;
+import com.hp.hpl.jena.util.FileManager ;
+import com.hp.hpl.jena.vocabulary.RDF ;
+
+public class TurtleWriter2
+{
+    public static void main(String ... args)
+    {
+        SysRIOT.wireIntoJena() ;
+        Model m = FileManager.get().loadModel("D.ttl") ;
+        
+        write(System.out, m) ;
+        System.out.println("----------------------------------") ;
+        
+        
+        ByteArrayOutputStream out = new ByteArrayOutputStream() ;
+        write(out, m) ;
+        ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()) ;
+        String s = StrUtils.fromUTF8bytes(out.toByteArray()) ;
+        Model m2 = ModelFactory.createDefaultModel() ;
+        m2.read(in, null, "TTL") ;
+        if ( ! m.isIsomorphicWith(m2) )
+            System.out.println("**** DIFFERENT") ;
+        
+        m.write(System.out, "TTL") ;
+        
+    }
+    
+    // TODO
+    // Order subjects to write
+    //   ==> scan by subject, not triples
+
+    // Single pass analysis
+    
+    // Lists
+    //   Do before embeddable objects because list take precedence.
+    
+    // Subjects \ one-connected objects
+    
+    // PredicateObjectLists
+    //   type to front.
+            // Property order is:
+            // 1 - rdf:type (as "a")
+            // 2 - other rdf: rdfs: namespace items (sorted)
+            // 3 - all other properties, sorted by URI (not qname)  
+            //     same properties together.
+    //   use object lists
+    // Configuration.
+    
+    // Check old code for special cases.
+    // Use better output(Node) code.
+    
+    // Check legality of prefix names generated.
+    // use stream node output (??)
+    
+    // Generally, all padding should level dependent.
+    
+    // Width of property before wrapping.
+    // This is not necessarily a control of total width
+    // e.g. the pretty writer may be writing properties inside indented one ref bNodes 
+//    protected int widePropertyLen = getIntValue("widePropertyLen", 20) ;
+//    
+//    // Column for property when an object follows a property on the same line
+//    protected int propertyCol = getIntValue("propertyColumn", 8) ;
+//    
+//    // Minimum gap from property to object when object on a new line.
+//    protected int indentObject = propertyCol ;
+//    
+//    // If a subject is shorter than this, the first property may go on same line.
+//    protected int subjectColumn = getIntValue("subjectColumn", indentProperty) ; 
+//    // Require shortSubject < subjectCol (strict less than)
+    
+    
+    
+    // TODO For TriG all these are relative.
+    private static final int LONG_SUBJECT = 20 ;
+    private static final int LONG_PREDICATE = 40 ;  // Inc subject lentgh
+    private static final int PREFIX_IRI = 15;
+    
+    // Column widths.
+    private static int COLW_SUBJECT = 6 ;
+    private static int COLW_PREDICATE = 8 ;
+    
+    
+    // Column for start of predicate  
+    private static final int INDENT_PREDICATE = 8 ;
+    
+    // Column for start of object  
+    // Usually this is exceeded and predicate, objects are print with min gap. 
+    private static final int INDENT_OBJECT = 8 ;
+    
+    
+    private static final String iriType = RDF.type.getURI() ;
+    
+    private static final int MIN_GAP = 2 ;
+    
+    private static final String rdfNS = RDF.getURI() ;
+
+    // Prepare prefixes.
+    // Need fast String=>prefix.
+    
+    public static void write(OutputStream out, Model model)
+    {
+        write(out, model.getGraph(), model.getNsPrefixMap()) ;
+    }
+    
+    public static void write(OutputStream out, Graph graph,  Map<String, String> prefixMap)
+    {
+        IndentedWriter iOut = new IndentedWriter(out, false) ;
+        write(iOut, graph, prefixMap) ;
+    }
+    
+    // Call from TriG as well.
+    static void write(IndentedWriter out, Graph graph, Map<String, String> prefixMap)
+    {
+        // Configuration.
+        Pair<Set<Node>, Set<Triple>> p = TW2.findOneConnectedBNodeObjects(graph) ;
+        Set<Node> bNodesObj1 = p.getLeft() ;
+        Set<Triple> triplesObj1 = p.getRight() ;
+        
+        // Lists
+        writePrefixes(out, prefixMap) ;
+
+        // Or - listSubjects and sort.
+        Iterator<Node> subjects = TW2.subjects(graph) ;
+        writeBySubject(out, graph, subjects, bNodesObj1, triplesObj1, new HashSet<Object>(), prefixMap) ;
+        out.flush() ;
+    }
+    
+    static void writePrefixes(IndentedWriter out, Map<String, String> prefixMap)
+    {
+        if ( ! prefixMap.isEmpty() )
+        {
+            // prepare?
+            for ( Map.Entry <String, String> e : prefixMap.entrySet() )
+            {
+                print(out, "@prefix ") ;
+                print(out, e.getKey()) ;
+                print(out, ": ") ;
+                pad(out, PREFIX_IRI) ;
+                print(out, "<") ;
+                print(out, e.getValue()) ;   // Check?
+                print(out, ">") ;
+                print(out, " .") ;
+                println(out) ;
+            }
+            // Blank line.
+            println(out) ;
+        }
+    }
+
+    static void writeBySubject(IndentedWriter out, Graph graph, 
+                               Iterator<Node> subjects, 
+                               Collection<Node> nestedObjects, Collection<Triple> skip, 
+                               Collection<Object> lists, 
+                               Map<String, String> prefixMap)
+    {
+        for ( ; subjects.hasNext() ; )
+        {
+            Node subj = subjects.next() ;
+            if ( nestedObjects.contains(subj) )
+                continue ;
+            
+            Collection<Triple> cluster = TW2.triplesOfSubject(graph, subj) ;
+            writeCluster(out, graph, subj, cluster, nestedObjects, prefixMap) ;
+        }
+    }
+    
+    
+    // Common subject
+    // Used by the blocks writer as well.
+    static void writeCluster(IndentedWriter out, Graph graph, Node subject, Collection<Triple> cluster, 
+                                     Collection<Node> nestedObjects, Map<String, String> prefixMap)
+    {
+        //int OFFSET = out.getIndent() ;
+        
+        if ( cluster.isEmpty() ) return ;
+        writeNode(out, subject, prefixMap) ;
+        
+        if ( out.getCol() > LONG_SUBJECT )
+            println(out) ;
+        else
+            gap(out) ;
+        out.incIndent(INDENT_PREDICATE) ;
+        out.pad() ;
+        writePredicateObjectList(out, graph, cluster, nestedObjects, prefixMap) ;
+        out.decIndent(INDENT_PREDICATE) ;
+        print(out, " .") ;  // Not perfect
+        println(out) ; 
+        println(out) ;
+    }
+    
+    // need to skip the triples nested.
+    
+    private static void writePredicateObjectList(IndentedWriter out, Graph graph, Collection<Triple> cluster, 
+                                                 Collection<Node> nestedObjects, Map<String, String> prefixMap)
+    {
+        boolean first = true ;
+        // Calc columns
+        
+        // Sort triples.
+        //  rdf:type
+        //  other rdf and rdfs
+        //  properties together
+        //  object lists?
+        // Find the colject pad column.
+        
+        
+        for ( Triple triple : cluster )
+        {
+            if ( first )
+                first = false ;
+            else
+            {
+                print(out, " ;") ;
+                println(out) ;
+            }
+            
+            // Write predicate.
+            int colPredicateStart = out.getCol() ;
+            
+            if ( ! prefixMap.containsValue(rdfNS) &&
+                triple.getPredicate().getURI().equals(iriType) )
+                // I prefer rdf:type when available.
+                print(out, "a") ;
+            else
+                writeNode(out, triple.getPredicate(), prefixMap) ;
+            int colPredicateFinish = out.getCol() ;
+            int wPredicate = (colPredicateFinish-colPredicateStart) ;
+            
+            // Needs to be relative?
+            if ( wPredicate > LONG_PREDICATE )
+                out.println() ;
+            else
+                gap(out) ;
+            
+            // Secondary one should be less
+            out.incIndent(INDENT_OBJECT) ;
+            out.pad() ;
+            Node obj = triple.getObject() ;
+            if ( nestedObjects.contains(obj) )
+                nestedObject(out, graph, obj, nestedObjects, prefixMap) ;
+            else
+                writeNode(out, triple.getObject(), prefixMap) ;
+            out.decIndent(INDENT_OBJECT) ;
+        }
+    }
+    
+    private static void nestedObject(IndentedWriter out, Graph graph, Node obj,
+                                     Collection<Node> nestedObjects, Map<String, String> prefixMap)
+    {
+        Collection<Triple> x = TW2.triplesOfSubject(graph, obj) ;
+        
+        if ( x.isEmpty() )
+        {
+            print(out, "[] ") ;
+            return ;
+        }
+
+        if ( x.size() == 1 )
+        {
+            print(out, "[ ") ;
+            // Includes nested object in triple.
+            writePredicateObjectList(out, graph, x, nestedObjects, prefixMap) ;
+            print(out, " ]") ;
+            return ;
+        }
+
+        // Two or more.
+        int here = out.getCol() ; // before "["
+        print(out, "[") ;
+        int i1 = out.getIndent() ;
+        out.setAbsoluteIndent(here) ;
+        // Inline: println(out) ;
+        out.incIndent(2) ;
+        writePredicateObjectList(out, graph, x, nestedObjects, prefixMap) ;
+        out.decIndent(2) ;
+        if ( true )
+        {
+            println(out) ; // Newline for "]"
+            print(out, "]") ;
+        }
+        else
+        {   // Compact
+            print(out, " ]") ;
+        }
+        out.setAbsoluteIndent(i1) ;
+    }
+    
+    static void writeNode(IndentedWriter out, Node node, Map<String, String> prefixMap)
+    {
+        // See RIOT NodeFormatter
+        if ( node.isURI() )
+        {
+            String iri = node.getURI() ;
+            // Crude.
+            String x = abbreviate(iri, prefixMap) ;
+            if ( x != null )
+            {
+                print(out, x) ;
+                return ;
+            }
+        }
+        
+        print(out, FmtUtils.stringForNode(node)) ;
+    }
+    
+    /** Abbreviate an IRI or return null */
+    private static String abbreviate(String uriStr, Map<String, String> prefixMap)
+    {
+        for ( Entry<String, String> e : prefixMap.entrySet())
+        {
+            String prefix = e.getValue().toString() ;
+            
+            if ( uriStr.startsWith(prefix) )
+            {
+                String ln = uriStr.substring(prefix.length()) ;
+                if ( strSafeFor(ln, '/') && strSafeFor(ln, '#') && strSafeFor(ln, ':') )
+                    return e.getKey()+":"+ln ;
+            }
+        }
+        return null ;
+    }
+    
+    private static boolean strSafeFor(String str, char ch) { return str.indexOf(ch) == -1 ; } 
+    
+    // flush aggressively (debugging)
+    
+    private static void flush(IndentedWriter out) { out.flush() ; } 
+    
+    private static void print(IndentedWriter out, String string)
+    {
+        out.print(string) ;
+        flush(out) ;
+    }
+    
+    private static void gap(IndentedWriter out)
+    {
+        out.print(' ', MIN_GAP) ;
+    }
+    
+    private static void pad(IndentedWriter out, int col)
+    {
+        out.pad(col, true) ;
+    }
+    
+    private static void println(IndentedWriter out)
+    {
+        out.println() ;
+        flush(out) ;
+        //System.err.println(out.getIndent()) ;
+    }
+
+    
+}
+

Added: incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/TurtleWriterBlocks.java
URL: http://svn.apache.org/viewvc/incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/TurtleWriterBlocks.java?rev=1224807&view=auto
==============================================================================
--- incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/TurtleWriterBlocks.java (added)
+++ incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/TurtleWriterBlocks.java Mon Dec 26 20:57:13 2011
@@ -0,0 +1,101 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package riot;
+
+import java.io.OutputStream ;
+import java.util.* ;
+
+import org.openjena.atlas.io.IndentedWriter ;
+import org.openjena.atlas.iterator.PeekIterator ;
+
+import com.hp.hpl.jena.graph.Graph ;
+import com.hp.hpl.jena.graph.Node ;
+import com.hp.hpl.jena.graph.Triple ;
+import com.hp.hpl.jena.rdf.model.Model ;
+import com.hp.hpl.jena.util.iterator.ExtendedIterator ;
+
+public class TurtleWriterBlocks
+{
+    public static void write(OutputStream out, Model model)
+    {
+        write(out, model.getGraph(), model.getNsPrefixMap()) ;
+    }
+    
+    public static void write(OutputStream out, Graph graph,  Map<String, String> prefixMap)
+    {
+        IndentedWriter iOut = new IndentedWriter(out, false) ;
+        write(iOut, graph, prefixMap) ;
+    }
+    
+    static void write(IndentedWriter out, Graph graph, Map<String, String> prefixMap)
+    {
+        // Lists
+        TurtleWriter2.writePrefixes(out, prefixMap) ;
+        writeTriples(out, graph, graph.find(Node.ANY, Node.ANY, Node.ANY), prefixMap) ;
+    }
+    
+    
+    // Top level writer.
+    // Write blocks of same-subject triples, skipping anything we are going to process specially inline.
+    // If the collections are empty, this is about as good as streaming writing gets for Turtle.
+    
+    // Change this to be a pure streaming, nested writer.
+    static void writeTriples(IndentedWriter out, Graph graph, 
+                             ExtendedIterator<Triple> triples, 
+                             Map<String, String> prefixMap) 
+    {
+        Collection<Node> nestedObjects = Collections.emptyList() ; 
+        Collection<Triple> skip = Collections.emptyList() ;
+        Collection<Object> lists = Collections.emptyList() ;
+            
+        PeekIterator<Triple> stream = PeekIterator.create(triples) ;
+        List<Triple> cluster = new ArrayList<Triple>() ;
+        Node subject = null ;
+        for ( ; ; )
+        {
+            cluster.clear() ;
+            for ( ; stream.hasNext() ; )
+            {
+                Triple t = stream.peek() ;
+                if ( skip != null && skip.contains(t) )
+                {
+                    stream.next() ;
+                    continue ;
+                }
+                
+                if ( subject == null )
+                    subject = t.getSubject() ;
+                else if ( ! subject.equals(t.getSubject()) )
+                    break ;
+                cluster.add(t) ;
+                stream.next() ;
+            }
+            if ( subject != null )
+            {
+                TurtleWriter2.writeCluster(out, graph, subject, cluster, nestedObjects, prefixMap) ;
+                subject = null ;
+            }
+            else 
+                break ;
+        }
+        triples.close() ;
+    }
+    
+}
+

Added: incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/TurtleWriterFlat.java
URL: http://svn.apache.org/viewvc/incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/TurtleWriterFlat.java?rev=1224807&view=auto
==============================================================================
--- incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/TurtleWriterFlat.java (added)
+++ incubator/jena/Scratch/AFS/Dev/trunk/src/main/java/riot/TurtleWriterFlat.java Mon Dec 26 20:57:13 2011
@@ -0,0 +1,58 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package riot;
+
+import java.util.Iterator ;
+
+import org.openjena.atlas.io.IndentedWriter ;
+
+import com.hp.hpl.jena.graph.Graph ;
+import com.hp.hpl.jena.graph.Node ;
+import com.hp.hpl.jena.graph.Triple ;
+
+/** Write Turtle as one line of prefixed names */   
+public class TurtleWriterFlat
+{
+    static public final int colWidth = 8 ; 
+    static public final int predCol = 8 ;
+    static public final int objCol = 8+predCol ;
+    
+    public static void write(IndentedWriter out, Graph graph) 
+    {
+        Iterator<Triple> iter = graph.find(Node.ANY, Node.ANY, Node.ANY) ;
+        
+        for ( ; iter.hasNext() ; )
+        {
+            Triple triple = iter.next() ;
+            
+            triple.getSubject() ;
+            out.pad(predCol-1) ;
+            out.print(" ") ;
+            
+            
+            triple.getPredicate() ;
+            out.pad(objCol-1) ;
+            out.print(" ") ;
+            
+            triple.getObject() ;
+
+            out.println(" .") ; 
+        }
+    }
+}