/* * Copyright Aduna (http://www.aduna-software.com/) (c) 1997-2007. * * Licensed under the Aduna BSD-style license. */ package org.openrdf.query.resultio.sparqljson; import java.io.BufferedWriter; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.nio.charset.Charset; import java.util.Iterator; import java.util.List; import info.aduna.io.IndentingWriter; import info.aduna.text.StringUtil; import org.openrdf.model.BNode; import org.openrdf.model.Literal; import org.openrdf.model.URI; import org.openrdf.model.Value; import org.openrdf.query.Binding; import org.openrdf.query.BindingSet; import org.openrdf.query.TupleQueryResultHandlerException; import org.openrdf.query.resultio.TupleQueryResultFormat; import org.openrdf.query.resultio.TupleQueryResultWriter; /** * A TupleQueryResultWriter that writes query results in the <a * href="http://www.w3.org/TR/rdf-sparql-json-res/">SPARQL Query Results JSON * Format</a>. */ public class SPARQLResultsJSONWriter implements TupleQueryResultWriter { /*-----------* * Variables * *-----------*/ private IndentingWriter writer; private boolean firstTupleWritten; /*--------------* * Constructors * *--------------*/ public SPARQLResultsJSONWriter(OutputStream out) { Writer w = new OutputStreamWriter(out, Charset.forName("UTF-8")); w = new BufferedWriter(w, 1024); writer = new IndentingWriter(w); } /*---------* * Methods * *---------*/ public final TupleQueryResultFormat getTupleQueryResultFormat() { return TupleQueryResultFormat.JSON; } public void startQueryResult(List<String> columnHeaders) throws TupleQueryResultHandlerException { try { openBraces(); // Write header writeKey("head"); openBraces(); writeKeyValue("vars", columnHeaders); closeBraces(); writeComma(); // Write results writeKey("results"); openBraces(); writeKey("bindings"); openArray(); firstTupleWritten = false; } catch (IOException e) { throw new TupleQueryResultHandlerException(e); } } public void endQueryResult() throws TupleQueryResultHandlerException { try { closeArray(); // bindings array closeBraces(); // results braces closeBraces(); // root braces writer.flush(); } catch (IOException e) { throw new TupleQueryResultHandlerException(e); } } public void handleSolution(BindingSet bindingSet) throws TupleQueryResultHandlerException { try { if (firstTupleWritten) { writeComma(); } else { firstTupleWritten = true; } openBraces(); // start of new solution Iterator<Binding> bindingIter = bindingSet.iterator(); while (bindingIter.hasNext()) { Binding binding = bindingIter.next(); writeKeyValue(binding.getName(), binding.getValue()); if (bindingIter.hasNext()) { writeComma(); } } closeBraces(); // end solution writer.flush(); } catch (IOException e) { throw new TupleQueryResultHandlerException(e); } } private void writeKeyValue(String key, String value) throws IOException { writeKey(key); writeString(value); } private void writeKeyValue(String key, Value value) throws IOException, TupleQueryResultHandlerException { writeKey(key); writeValue(value); } private void writeKeyValue(String key, Iterable<String> array) throws IOException { writeKey(key); writeArray(array); } private void writeKey(String key) throws IOException { writeString(key); writer.write(": "); } private void writeValue(Value value) throws IOException, TupleQueryResultHandlerException { writer.write("{ "); if (value instanceof URI) { writeKeyValue("type", "uri"); writer.write(", "); writeKeyValue("value", ((URI)value).toString()); } else if (value instanceof BNode) { writeKeyValue("type", "bnode"); writer.write(", "); writeKeyValue("value", ((BNode)value).getID()); } else if (value instanceof Literal) { Literal lit = (Literal)value; if (lit.getDatatype() != null) { writeKeyValue("type", "typed-literal"); writer.write(", "); writeKeyValue("datatype", lit.getDatatype().toString()); } else { writeKeyValue("type", "literal"); if (lit.getLanguage() != null) { writer.write(", "); writeKeyValue("xml:lang", lit.getLanguage()); } } writer.write(", "); writeKeyValue("value", lit.getLabel()); } else { throw new TupleQueryResultHandlerException("Unknown Value object type: " + value.getClass()); } writer.write(" }"); } private void writeString(String value) throws IOException { // Escape special characters value = StringUtil.gsub("\\", "\\\\", value); value = StringUtil.gsub("\"", "\\\"", value); value = StringUtil.gsub("/", "\\/", value); value = StringUtil.gsub("\b", "\\b", value); value = StringUtil.gsub("\f", "\\f", value); value = StringUtil.gsub("\n", "\\n", value); value = StringUtil.gsub("\r", "\\r", value); value = StringUtil.gsub("\t", "\\t", value); writer.write("\""); writer.write(value); writer.write("\""); } private void writeArray(Iterable<String> array) throws IOException { writer.write("[ "); Iterator<String> iter = array.iterator(); while (iter.hasNext()) { String value = iter.next(); writeString(value); if (iter.hasNext()) { writer.write(", "); } } writer.write(" ]"); } private void openArray() throws IOException { writer.write("["); writer.writeEOL(); writer.increaseIndentation(); } private void closeArray() throws IOException { writer.writeEOL(); writer.decreaseIndentation(); writer.write("]"); } private void openBraces() throws IOException { writer.write("{"); writer.writeEOL(); writer.increaseIndentation(); } private void closeBraces() throws IOException { writer.writeEOL(); writer.decreaseIndentation(); writer.write("}"); } private void writeComma() throws IOException { writer.write(", "); writer.writeEOL(); } }