blob: 8c0fb0559f227b4ab44be7c8530f296e857fe83a [file] [log] [blame]
/*
* 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.sparql.resultset;
import java.util.ArrayList;
import org.apache.jena.atlas.logging.Log;
import org.apache.jena.datatypes.xsd.XSDDatatype;
import org.apache.jena.query.ResultSet;
import org.apache.jena.rdf.model.*;
import org.apache.jena.shared.JenaException;
import org.apache.jena.shared.PropertyNotFoundException;
import org.apache.jena.sparql.core.Var;
import org.apache.jena.sparql.engine.binding.Binding;
import org.apache.jena.sparql.engine.binding.BindingFactory;
import org.apache.jena.sparql.engine.binding.BindingMap;
import org.apache.jena.sparql.vocabulary.ResultSetGraphVocab;
import org.apache.jena.vocabulary.RDF;
public class RDFInput extends ResultSetMem {
/**
* Process a result set encoded in RDF according to
* <code>@link{http://www.w3.org/2001/sw/DataAccess/tests/result-set}#</code>
*
* @param model
*/
public RDFInput(Model model) {
buildFromDumpFormat(model);
}
// Convert from RDF model to in-memory result set
private void buildFromDumpFormat(Model resultsModel) {
varNames = new ArrayList<>();
StmtIterator sIter = resultsModel.listStatements(null, RDF.type, ResultSetGraphVocab.ResultSet);
for ( ; sIter.hasNext() ; ) {
// For each root
Statement s = sIter.nextStatement();
Resource root = s.getSubject();
buildOneResource(root);
}
sIter.close();
reset();
}
private void buildOneResource(Resource root) {
buildVariables(root);
int count = buildPreprocess(root);
if ( root.getModel().contains(null, ResultSetGraphVocab.index, (RDFNode)null) )
buildRowsOrdered(root, count);
else
buildRows(root);
}
private void buildVariables(Resource root) {
// Variables
StmtIterator rVarsIter = root.listProperties(ResultSetGraphVocab.resultVariable);
for ( ; rVarsIter.hasNext() ; ) {
String varName = rVarsIter.nextStatement().getString();
varNames.add(varName);
}
rVarsIter.close();
}
private int buildPreprocess(Resource root) {
StmtIterator solnIter = root.listProperties(ResultSetGraphVocab.solution);
int rows = 0;
int indexed = 0;
for ( ; solnIter.hasNext() ; ) {
Resource soln = solnIter.nextStatement().getResource();
rows++;
if ( soln.hasProperty(ResultSetGraphVocab.index) )
indexed++;
}
solnIter.close();
if ( indexed > 0 && rows != indexed ) {
Log.warn(this, "Rows = " + rows + " but only " + indexed + " indexes");
return rows;
}
return rows;
}
private void buildRowsOrdered(Resource root, int count) {
Model m = root.getModel();
// Assume one result set per file.
for ( int index = 1 ;; index++ ) {
Literal ind = m.createTypedLiteral(index, XSDDatatype.XSDinteger);
StmtIterator sIter = m.listStatements(null, ResultSetGraphVocab.index, ind);
if ( !sIter.hasNext() )
break;
Statement s = sIter.nextStatement();
if ( sIter.hasNext() )
Log.warn(this, "More than one solution: index = " + index);
Resource soln = s.getSubject();
Binding rb = buildBinding(soln);
rows.add(rb);
sIter.close();
}
if ( rows.size() != count )
Log.warn(this, "Found " + rows.size() + ": expected " + count);
}
private void buildRows(Resource root) {
// Now the results themselves
int count = 0;
StmtIterator solnIter = root.listProperties(ResultSetGraphVocab.solution);
for ( ; solnIter.hasNext() ; ) {
Resource soln = solnIter.nextStatement().getResource();
count++;
Binding rb = buildBinding(soln);
rows.add(rb);
}
solnIter.close();
if ( root.hasProperty(ResultSetGraphVocab.size) ) {
try {
int size = root.getRequiredProperty(ResultSetGraphVocab.size).getInt();
if ( size != count )
Log.warn(this, "Warning: Declared size = " + size + " : Count = " + count);
}
catch (JenaException rdfEx) {}
}
}
private Binding buildBinding(Resource soln) {
// foreach row
BindingMap rb = BindingFactory.create();
StmtIterator bindingIter = soln.listProperties(ResultSetGraphVocab.binding);
for ( ; bindingIter.hasNext() ; ) {
Resource binding = bindingIter.nextStatement().getResource();
String var = binding.getRequiredProperty(ResultSetGraphVocab.variable).getString();
try {
RDFNode val = binding.getRequiredProperty(ResultSetGraphVocab.value).getObject();
rb.add(Var.alloc(var), val.asNode());
}
catch (PropertyNotFoundException ex) {
Log.warn(this, "Failed to get value for ?" + var);
}
// We include the value even if it is the marker term "rs:undefined"
// if ( val.equals(ResultSetVocab.undefined))
// continue ;
// The ResultSetFormatter code equates null (not found) with
// rs:undefined. When Jena JUnit testing, it does not matter if the
// recorded result has the term absent or explicitly undefined.
}
bindingIter.close();
return rb;
}
/**
* Turns an RDF model, with properties and classes from the result set
* vocabulary, into a SPARQL result set. The result set formed is a copy in
* memory.
*
* @param model
* @return ResultSet
*/
public static ResultSet fromRDF(Model model) {
return new RDFInput(model);
}
}