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 2020/04/10 13:13:23 UTC
[jena] branch master updated: JENA-1880: ResultSetWriterJSON using
Nodes
This is an automated email from the ASF dual-hosted git repository.
andy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jena.git
The following commit(s) were added to refs/heads/master by this push:
new 8399c6b JENA-1880: ResultSetWriterJSON using Nodes
new cbdba5e Merge pull request #724 from afs/jena1880-resultset-writer-json
8399c6b is described below
commit 8399c6b1b83892a43c6e0ed04393dae684c1b7e9
Author: Andy Seaborne <an...@apache.org>
AuthorDate: Wed Apr 8 13:46:55 2020 +0100
JENA-1880: ResultSetWriterJSON using Nodes
---
.../riot/resultset/rw/ResultSetWriterJSON.java | 376 ++++++++++++---------
...etWriterJSON.java => ResultSetWriterJSON1.java} | 6 +-
2 files changed, 216 insertions(+), 166 deletions(-)
diff --git a/jena-arq/src/main/java/org/apache/jena/riot/resultset/rw/ResultSetWriterJSON.java b/jena-arq/src/main/java/org/apache/jena/riot/resultset/rw/ResultSetWriterJSON.java
index 8291b03..985fc8c 100644
--- a/jena-arq/src/main/java/org/apache/jena/riot/resultset/rw/ResultSetWriterJSON.java
+++ b/jena-arq/src/main/java/org/apache/jena/riot/resultset/rw/ResultSetWriterJSON.java
@@ -29,33 +29,34 @@ import org.apache.jena.atlas.io.IO;
import org.apache.jena.atlas.io.IndentedWriter;
import org.apache.jena.atlas.json.io.JSWriter;
import org.apache.jena.atlas.logging.Log;
+import org.apache.jena.graph.Node;
import org.apache.jena.query.ARQ;
-import org.apache.jena.query.QuerySolution;
import org.apache.jena.query.ResultSet;
-import org.apache.jena.rdf.model.Literal;
-import org.apache.jena.rdf.model.RDFNode;
-import org.apache.jena.rdf.model.Resource;
import org.apache.jena.rdf.model.impl.Util;
import org.apache.jena.riot.out.NodeToLabel;
import org.apache.jena.riot.resultset.ResultSetLang;
import org.apache.jena.riot.resultset.ResultSetWriter;
import org.apache.jena.riot.resultset.ResultSetWriterFactory;
import org.apache.jena.riot.system.SyntaxLabels;
-import org.apache.jena.sparql.resultset.ResultSetApply;
+import org.apache.jena.sparql.core.Var;
+import org.apache.jena.sparql.engine.binding.Binding;
import org.apache.jena.sparql.resultset.ResultSetException;
-import org.apache.jena.sparql.resultset.ResultSetProcessor;
import org.apache.jena.sparql.util.Context;
+/** Write results in {@code application/sparql-results+json} format. */
public class ResultSetWriterJSON implements ResultSetWriter {
public static ResultSetWriterFactory factory = lang->{
if (!Objects.equals(lang, ResultSetLang.SPARQLResultSetJSON ) )
- throw new ResultSetException("ResultSetWriter for JSON asked for a "+lang);
- return new ResultSetWriterJSON();
+ throw new ResultSetException("ResultSetWriter for JSON asked for a "+lang);
+ return new ResultSetWriterJSON();
};
-
- private ResultSetWriterJSON() {}
-
+
+ private ResultSetWriterJSON() { }
+
+ // We use an inner object for writing of one result set so that the
+ // ResultSetWriter has no per-write state variables.
+
@Override
public void write(Writer out, ResultSet resultSet, Context context) {
throw new UnsupportedOperationException("Writing JSON results to a java.io.Writer. Use an OutputStream.") ;
@@ -63,226 +64,255 @@ public class ResultSetWriterJSON implements ResultSetWriter {
@Override
public void write(OutputStream outStream, boolean result, Context context) {
- JSWriter out = new JSWriter(outStream);
- out.startOutput();
- out.startObject();
- out.key(kHead);
- out.startObject();
- out.finishObject();
- out.pair(kBoolean, result);
- out.finishObject();
- out.finishOutput();
- IO.flush(outStream);
+ try {
+ JSWriter out = new JSWriter(outStream);
+ out.startOutput();
+ out.startObject();
+ out.key(kHead);
+ out.startObject();
+ out.finishObject();
+ out.pair(kBoolean, result);
+ out.finishObject();
+ out.finishOutput();
+ } finally {
+ IO.flush(outStream);
+ }
}
-
+
@Override
- public void write(OutputStream out, ResultSet resultSet, Context context) {
- JSONOutputResultSet jsonOut = new JSONOutputResultSet(out, context);
- ResultSetApply a = new ResultSetApply(resultSet, jsonOut);
- a.apply();
+ public void write(OutputStream outStream, ResultSet resultSet, Context context) {
+ IndentedWriter out = new IndentedWriter(outStream);
+ try {
+ ResultSetWriterTableJSON x = new ResultSetWriterTableJSON(out, context);
+ x.write(resultSet);
+ }
+ finally {
+ IO.flush(out);
+ }
}
- private static class JSONOutputResultSet implements ResultSetProcessor {
+ // Create once per write call.
+ // This holds the state of the writing of one ResultSet.
+ static class ResultSetWriterTableJSON {
+ private final NodeToLabel labels;
+ private final IndentedWriter out;
+ /** Control whether the type/literal/fileds all go on one line. */
private static final boolean multiLineValues = false;
+ /** Control whether variables in header are one per line (minor). */
private static final boolean multiLineVarNames = false;
- private final IndentedWriter out;
- private final NodeToLabel labels;
-
- private JSONOutputResultSet(OutputStream outStream, Context context) {
+ private ResultSetWriterTableJSON(OutputStream outStream, Context context) {
this(new IndentedWriter(outStream), context);
}
- private JSONOutputResultSet(IndentedWriter indentedOut, Context context) {
+ private ResultSetWriterTableJSON(IndentedWriter indentedOut, Context context) {
out = indentedOut;
boolean outputGraphBNodeLabels = (context != null) && context.isTrue(ARQ.outputGraphBNodeLabels);
labels = outputGraphBNodeLabels
? SyntaxLabels.createNodeToLabelAsGiven()
- : SyntaxLabels.createNodeToLabel();
- }
-
- @Override
- public void start(ResultSet rs) {
- println("{");
- out.incIndent();
- doHead(rs);
- println(quoteName(kResults), ": {");
- out.incIndent();
- println(quoteName(kBindings), ": [");
- out.incIndent();
- firstSolution = true;
- }
-
- @Override
- public void finish(ResultSet rs) {
- // Close last binding.
- out.println();
-
- out.decIndent(); // bindings
- println("]");
- out.decIndent();
- println("}"); // results
- out.decIndent();
- println("}"); // top level {}
- out.flush();
+ : SyntaxLabels.createNodeToLabel();
}
- private void doHead(ResultSet rs) {
- println(quoteName(kHead),": {");
- out.incIndent();
- doLink(rs);
- doVars(rs);
- out.decIndent();
- println("} ,");
+ private void writeHeader(ResultSet rs) {
+ println(out, quoteName(kHead),": {");
+ incIndent(out);
+ writeHeaderLink(out, rs);
+ writeHeaderVars(out, rs);
+ decIndent(out);
+ println(out, "} ,");
}
- private void doLink(ResultSet rs) {
+ private static void writeHeaderLink(IndentedWriter out, ResultSet rs) {
// ---- link
// out.println("\"link\": []") ;
}
- private void doVars(ResultSet rs) {
+ // "var": [ ... ]
+ private static void writeHeaderVars(IndentedWriter out, ResultSet rs) {
// On one line.
- print(quoteName(kVars), ": [ ");
+ print(out, quoteName(kVars), ": [ ");
if ( multiLineVarNames )
- out.println();
- out.incIndent();
+ println(out);
+ incIndent(out);
for ( Iterator<String> iter = rs.getResultVars().iterator() ; iter.hasNext() ; ) {
String varname = iter.next();
- print("\"", varname, "\"");
- if ( multiLineVarNames )
- println();
+ print(out, "\"", varname, "\"");
if ( iter.hasNext() )
- print(" , ");
+ print(out, " , ");
+ if ( multiLineVarNames )
+ println(out);
}
- println(" ]");
- out.decIndent();
+ decIndent(out);
+ println(out, " ]");
}
- boolean firstSolution = true;
- boolean firstBindingInSolution = true;
-
- // NB assumes are on end of previous line.
- @Override
- public void start(QuerySolution qs) {
- if ( !firstSolution )
- println(" ,");
- firstSolution = false;
- println("{");
- out.incIndent();
- firstBindingInSolution = true;
+ private void write(ResultSet resultSet) {
+ print(out, "{");
+ incIndent(out);
+
+ writeHeader(resultSet);
+ println(out, quoteName(kResults), ": {");
+ incIndent(out);
+ println(out, quoteName(kBindings), ": [");
+ incIndent(out);
+
+ boolean firstRow = true;
+ for ( ; resultSet.hasNext() ; ) {
+ Binding binding = resultSet.nextBinding();
+ writeRow(out, resultSet, binding, firstRow);
+ firstRow = false;
+ }
+ println(out);
+ decIndent(out); // bindings
+ println(out, "]");
+ decIndent(out);
+ println(out, "}"); // results
+ decIndent(out);
+ println(out, "}"); // top level {}
}
- @Override
- public void finish(QuerySolution qs) {
- println(); // Finish last binding
- out.decIndent();
- print("}"); // NB No newline
+ private void writeRow(IndentedWriter out, ResultSet resultSet, Binding binding, boolean firstRow) {
+ if ( !firstRow )
+ println(out, " ,");
+ println(out, "{");
+ incIndent(out);
+ boolean firstInRow = true;
+ // Print in the order seen in the header.
+ for ( Iterator<String> iter = resultSet.getResultVars().iterator() ; iter.hasNext() ; ) {
+ Var var = Var.alloc(iter.next());
+ Node value = binding.get(var);
+ if ( value == null )
+ continue;
+ if ( ! firstInRow )
+ println(out, " ,");
+ writeVarValue(out, var, value, firstInRow );
+ firstInRow = false;
+ }
+
+ if ( false ) {
+ // Print "missing" variables.
+ // If the header is right, this should not be necessary.
+ for ( Iterator<Var> vars = binding.vars() ; vars.hasNext() ; ) {
+ Var var = vars.next();
+ if ( ! resultSet.getResultVars().contains(var.getName()) ) {
+ Node value = binding.get(var);
+ if ( ! firstInRow )
+ println(out, " ,");
+ writeVarValue(out, var, value, firstInRow );
+ firstInRow = false;
+ }
+ }
+ }
+ println(out);
+ decIndent(out);
+ print(out, "}"); // NB No newline
}
- @Override
- public void binding(String varName, RDFNode value) {
+ /** Write one { "var": { ... term ... } } */
+ private void writeVarValue(IndentedWriter out, Var var, Node value, boolean firstInRow) {
if ( value == null )
+ // Skip if no value.
return;
-
- if ( !firstBindingInSolution )
- println(" ,");
- firstBindingInSolution = false;
-
// Do not use quoteName - varName may not be JSON-safe as a bare name.
- print(quote(varName), ": { ");
+ print(out, quote(var.getVarName()), ": { ");
if ( multiLineValues )
- out.println();
+ println(out);
- out.incIndent();
- // Old, explicit unbound
+ incIndent(out);
+ writeValue(out, value);
+ decIndent(out);
+
+ if ( !multiLineValues )
+ print(out, " ");
+ print(out, "}");
+ // No newline - allow for " ,"
+ }
+
+ private void writeValue(IndentedWriter out, Node value) {
+ // Explicit unbound
// if ( value == null )
- // printUnbound() ;
+ // writeValueUnbound(out) ;
// else
+
if ( value.isLiteral() )
- printLiteral((Literal)value);
- else if ( value.isResource() )
- printResource((Resource)value);
+ writeValueLiteral(out, value);
+ else if ( value.isURI() )
+ writeValueURI(out, value);
+ else if ( value.isBlank() )
+ writeValueBlankNode(out, value);
+ // For RDF*
+// else if ( value.isNodeTriple() )
+// writeValueNodeTriple(out, value);
else
- Log.warn(this, "Unknown RDFNode type in result set: " + value.getClass());
- out.decIndent();
-
- if ( !multiLineValues )
- print(" ");
- print("}"); // NB No newline
+ Log.warn(ResultSetWriterJSON.class, "Unknown RDFNode type in result set: " + value.getClass());
}
- private void printUnbound() {
- print(quoteName(kType), ": ", quote(kUnbound), " , ") ;
- if ( multiLineValues )
- println() ;
- print(quoteName(kValue), ": null") ;
- if ( multiLineValues )
- println() ;
- }
+ private void writeValueUnbound(IndentedWriter out) {
+ print(out, quoteName(kType), ": ", quote(kUnbound), " , ") ;
+ if ( multiLineValues )
+ println(out) ;
+ print(out, quoteName(kValue), ": null") ;
+ if ( multiLineValues )
+ println(out) ;
+ }
- private void printLiteral(Literal literal) {
- String datatype = literal.getDatatypeURI();
- String lang = literal.getLanguage();
+ private void writeValueLiteral(IndentedWriter out, Node literal) {
+ String datatype = literal.getLiteralDatatypeURI();
+ String lang = literal.getLiteralLanguage();
if ( Util.isSimpleString(literal) || Util.isLangString(literal) ) {
- print(quoteName(kType), ": ", quote(kLiteral), " , ");
+ print(out, quoteName(kType), ": ", quote(kLiteral), " , ");
if ( multiLineValues )
- println();
+ println(out);
if ( lang != null && !lang.equals("") ) {
- print(quoteName(kXmlLang), ": ", quote(lang), " , ");
+ print(out, quoteName(kXmlLang), ": ", quote(lang), " , ");
if ( multiLineValues )
- println();
+ println(out);
}
} else {
- print(quoteName(kType), ": ", quote(kLiteral), " , ");
+ print(out, quoteName(kType), ": ", quote(kLiteral), " , ");
if ( multiLineValues )
- println();
+ println(out);
- print(quoteName(kDatatype), ": ", quote(datatype), " , ");
+ print(out, quoteName(kDatatype), ": ", quote(datatype), " , ");
if ( multiLineValues )
- println();
+ println(out);
}
- print(quoteName(kValue), ": ", quote(literal.getLexicalForm()));
+ print(out, quoteName(kValue), ": ", quote(literal.getLiteralLexicalForm()));
if ( multiLineValues )
- println();
+ println(out);
}
- private void printResource(Resource resource) {
- if ( resource.isAnon() ) {
- String label = labels.get(null, resource.asNode());
- // Comes with leading "_:"
- label = label.substring(2);
+ private void writeValueBlankNode(IndentedWriter out, Node resource) {
+ String label = labels.get(null, resource);
+ // Comes with leading "_:"
+ label = label.substring(2);
- print(quoteName(kType), ": ", quote(kBnode), " , ");
- if ( multiLineValues )
- out.println();
+ print(out, quoteName(kType), ": ", quote(kBnode), " , ");
+ if ( multiLineValues )
+ println(out);
- print(quoteName(kValue), ": ", quote(label));
+ print(out, quoteName(kValue), ": ", quote(label));
+
+ if ( multiLineValues )
+ println(out);
- if ( multiLineValues )
- println();
- } else {
- print(quoteName(kType), ": ", quote(kUri), " , ");
- if ( multiLineValues )
- println();
- print(quoteName(kValue), ": ", quote(resource.getURI()));
- if ( multiLineValues )
- println();
- return;
- }
}
-
- private void print(String... strings) {
- for ( String s : strings )
- out.print(s);
+
+ private void writeValueURI(IndentedWriter out, Node resource) {
+ print(out, quoteName(kType), ": ", quote(kUri), " , ");
+ if ( multiLineValues )
+ println(out);
+ print(out, quoteName(kValue), ": ", quote(resource.getURI()));
+ if ( multiLineValues )
+ println(out);
+ return;
}
- private void println(String... strings) {
- print(strings);
- out.println();
+ private void writeValueNodeTriple(IndentedWriter out, Node value) {
+ print(out, "** NodeTriple **");
}
private static String quote(String string) {
@@ -301,5 +331,25 @@ public class ResultSetWriterJSON implements ResultSetWriter {
//return "\""+string+"\"";
return quote(string);
}
+
+ // Intercept all operations - development assistance.
+
+ private static void incIndent(IndentedWriter out) {
+ out.incIndent();
+ }
+
+ private static void decIndent(IndentedWriter out) {
+ out.decIndent();
+ }
+
+ private static void print(IndentedWriter out, String... strings) {
+ for ( String s : strings )
+ out.print(s);
+ }
+
+ private static void println(IndentedWriter out, String... strings) {
+ print(out, strings);
+ out.println();
+ }
}
}
diff --git a/jena-arq/src/main/java/org/apache/jena/riot/resultset/rw/ResultSetWriterJSON.java b/jena-arq/src/main/java/org/apache/jena/riot/resultset/rw/ResultSetWriterJSON1.java
similarity index 98%
copy from jena-arq/src/main/java/org/apache/jena/riot/resultset/rw/ResultSetWriterJSON.java
copy to jena-arq/src/main/java/org/apache/jena/riot/resultset/rw/ResultSetWriterJSON1.java
index 8291b03..4ed13c0 100644
--- a/jena-arq/src/main/java/org/apache/jena/riot/resultset/rw/ResultSetWriterJSON.java
+++ b/jena-arq/src/main/java/org/apache/jena/riot/resultset/rw/ResultSetWriterJSON1.java
@@ -46,15 +46,15 @@ import org.apache.jena.sparql.resultset.ResultSetException;
import org.apache.jena.sparql.resultset.ResultSetProcessor;
import org.apache.jena.sparql.util.Context;
-public class ResultSetWriterJSON implements ResultSetWriter {
+public class ResultSetWriterJSON1 implements ResultSetWriter {
public static ResultSetWriterFactory factory = lang->{
if (!Objects.equals(lang, ResultSetLang.SPARQLResultSetJSON ) )
throw new ResultSetException("ResultSetWriter for JSON asked for a "+lang);
- return new ResultSetWriterJSON();
+ return new ResultSetWriterJSON1();
};
- private ResultSetWriterJSON() {}
+ private ResultSetWriterJSON1() {}
@Override
public void write(Writer out, ResultSet resultSet, Context context) {