Sometimes, an application will be making a SPARQL query, using the results from a previous query or using some RDF term found through the other Jena APIs.
SQL has prepared statements - they allow an SQL statement to take a number of parameters. The application fills in the parameters and executes the statement.
One way is to resort to doing this in SPARQL by building
a complete, new query string, parsing it and executing it.
But it takes a little care to handle all cases like
quoting special characters; you can at least use some of the
many utilities in ARQ for producing strings such as
FmtUtils.stringForResource
(it's
not in the application API but in the util
package currently).
Queries in ARQ can be built programmatically but it is tedious, especially when the documentation hasn't been written yet.
Another way is to use query variables and bind them to initial values that apply to all query solutions. Consider the query:
PREFIX dc <http://purl.org/dc/elements/1.1/> SELECT ?doc { ?doc dc:title ?title }
It gets documents and their titles.
Executing a query in program might look like:
import com.hp.hpl.jena.query.* ; Model model = ... ;
String queryString = StringUtils.join("\n", new String[]{ "PREFIX dc <http://purl.org/dc/elements/1.1/>", "SELECT ?doc { ?doc dc:title ?title }" }) ; Query query = QueryFactory.create(queryString) ; QueryExecution qexec = QueryExecutionFactory.create(query, model) ; try { ResultSet results = qexec.execSelect() ; for ( ; results.hasNext() ; ) { QuerySolution soln = results.nextSolution() ; Literal l = soln.getLiteral("doc") ; } } finally { qexec.close() ; }
Suppose the application knows the title it's interesting in - can it use this to get the document?
The value of ?title
made a parameter to the query
and fixed by an initial binding. All query solutions will
be restricted to patterns matches where ?title
is that RDF term.
QuerySolutionMap initialSettings = new QuerySolutionMap() ; initialSettings.add("title", node) ;
and this is passed to the factory that creates QueryExecution's:
QueryExecution qexec = QueryExecutionFactory.create(query, model, initialSettings) ;
It doesn't matter if the node is a literal, a resource with URI or a blank node. It becomes a fixed value in the query, even a blank node, because it's not part of the SPARQL syntax, it's a fixed part of every solution.
This gives named parameters to queries enabling something like SQL prepared statements except with named parameters not positional ones.
This can make a complex application easier to structure and clearer to read. It's better than bashing strings together, which is error prone, inflexible, and does not lead to clear code.
3 comments:
See also leigh's blog
A try/catch/finally without catch-clause is very stupid... :-D See you...
The code block after finally gets executed for any runtime exceptions and also if the code exist normally. Using finally guarantees that the clean up is done even if an unexpected exception (from another subsystem maybe) happens.
Post a Comment