/*
* 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 org.apache.jena.riot.writer;
import java.io.OutputStream ;
import java.io.Writer ;
import java.util.HashMap ;
import java.util.HashSet ;
import java.util.Map ;
import java.util.Set ;
import org.apache.jena.atlas.io.IndentedWriter ;
import org.apache.jena.atlas.json.io.JSWriter ;
import org.apache.jena.atlas.lib.Pair ;
import org.apache.jena.graph.Graph ;
import org.apache.jena.graph.GraphUtil ;
import org.apache.jena.graph.Node ;
import org.apache.jena.graph.Triple ;
import org.apache.jena.riot.Lang ;
import org.apache.jena.riot.RiotException ;
import org.apache.jena.riot.system.PrefixMap ;
import org.apache.jena.sparql.util.Context ;
import org.apache.jena.sparql.util.NodeUtils ;
import org.apache.jena.util.iterator.ExtendedIterator ;
public class RDFJSONWriter extends WriterGraphRIOTBase
{
public RDFJSONWriter() {}
public static void output(OutputStream out, Graph graph) {
output(new JSWriter(out), graph ) ;
}
public static void output(Writer out, Graph graph) {
output(new JSWriter(new IndentedWriterEx(out)), graph ) ;
}
@Override
public Lang getLang()
{
return Lang.RDFJSON ;
}
@Override
public void write(Writer out, Graph graph, PrefixMap prefixMap, String baseURI, Context context)
{
output(out, graph) ;
}
@Override
public void write(OutputStream out, Graph graph, PrefixMap prefixMap, String baseURI, Context context)
{
output(out, graph) ;
}
private static void output(JSWriter out, Graph graph) {
out.startOutput() ;
out.startObject();
ExtendedIterator<Node> subjects = GraphUtil.listSubjects(graph, Node.ANY, Node.ANY) ;
try {
Map<Node, Set<Node>> predicates = new HashMap<>() ;
while ( subjects.hasNext() ) {
Node subject = subjects.next() ;
ExtendedIterator<Triple> triples = graph.find(subject, Node.ANY, Node.ANY) ;
try {
while ( triples.hasNext() ) {
Triple triple = triples.next() ;
Node p = triple.getPredicate() ;
if ( predicates.containsKey(p) ) {
predicates.get(p).add(triple.getObject()) ;
} else {
Set<Node> objects = new HashSet<>() ;
objects.add(triple.getObject()) ;
predicates.put(p, objects) ;
}
}
} finally {
if ( triples != null ) triples.close() ;
}
send(out, new Pair<>(subject, predicates)) ;
predicates.clear() ;
}
} finally {
if ( subjects != null ) subjects.close() ;
out.finishObject();
out.finishOutput() ;
}
}
private static void send(JSWriter out, Pair<Node, Map<Node, Set<Node>>> item) {
Node s = item.getLeft() ;
if ( s.isBlank() ) {
out.key("_:" + s.getBlankNodeLabel()) ;
} else if ( s.isURI() ) {
out.key(s.getURI()) ;
} else {
throw new RiotException ("Only URIs or blank nodes are legal subjects.") ;
}
out.startObject() ;
// out.pair(key, value) ;
Map<Node, Set<Node>> predicates = item.getRight() ;
for (Node p : predicates.keySet() ) {
out.key(p.getURI()) ;
out.startArray() ;
Set<Node> objects = predicates.get(p) ;
int i = 0;
for ( Node o : objects ) {
out.startObject() ;
if ( o.isBlank() ) {
out.pair("type", "bnode") ;
out.pair("value", "_:" + o.getBlankNodeLabel()) ;
} else if ( o.isURI() ) {
out.pair("type", "uri") ;
out.pair("value", o.getURI()) ;
} else if ( o.isLiteral() ) {
String lex = o.getLiteralLexicalForm() ;
out.pair("type", "literal") ;
out.pair("value", lex) ;
if ( NodeUtils.isSimpleString(o) ) {
// No-op.
} else if ( NodeUtils.isLangString(o) ) {
String lang = o.getLiteralLanguage() ;
out.pair("lang", lang) ;
} else {
// Datatype, nothing special.
String dt = o.getLiteralDatatypeURI() ;
out.pair("datatype", dt) ;
}
}
out.finishObject() ;
if (i < objects.size() - 1)
{
out.arraySep();
}
i++;
}
out.finishArray() ;
}
out.finishObject() ;
}
private static class IndentedWriterEx extends IndentedWriter {
public IndentedWriterEx(Writer writer) {
super(writer);
}
}
}