module SPARQL
A SPARQL
for RDF.rb.
Constants
- ERROR_MESSAGE
Public Class Methods
Parse and execute the given SPARQL
`query` string against `queriable`.
Requires a queryable object (such as an RDF::Repository), into which the dataset will be loaded.
Optionally takes a list of URIs to load as default or named graphs into `queryable`.
Note, if default or named graphs are specified as options (protocol elements), or the query references specific default or named graphs the graphs are either presumed to be existant in `queryable` or are loaded into `queryable` depending on the presense and value of the :load_datasets option.
Attempting to load into an immutable `queryable` will result in a TypeError.
@example
repository = RDF::Repository.new results = SPARQL.execute("SELECT * WHERE { ?s ?p ?o }", repository)
@param [IO, StringIO, String, to_s] query @param [RDF::Queryable] queryable @param [Hash{Symbol => Object}] options @option options [Boolean] :optimize
Optimize query before execution.
@option options [RDF::URI, String, Array
<RDF::URI, String>] :default_graph_uri @option options [RDF::URI, String, Array
<RDF::URI, String>] :load_datasets
One or more URIs used to initialize a new instance of `queryable` in the default graph. One or more URIs used to initialize a new instance of `queryable` in the default graph.
@option options [RDF::URI, String, Array
<RDF::URI, String>] :named_graph_uri
One or more URIs used to initialize the `queryable` as a named graph.
@yield [solution]
each matching solution, statement or boolean
@yieldparam [RDF::Statement, RDF::Query::Solution
, Boolean] solution @yieldreturn [void] ignored @return [RDF::Graph, Boolean, RDF::Query::Solutions::Enumerator]
Note, results may be used with {SPARQL.serialize_results} to obtain appropriate output encoding.
@raise [SPARQL::MalformedQuery] on invalid input
# File lib/sparql.rb, line 73 def self.execute(query, queryable, **options, &block) query = self.parse(query, **options) query = query.optimize(**options) if options[:optimize] queryable = queryable || RDF::Repository.new if options[:logger] options[:logger].debug("SPARQL.execute") {SXP::Generator.string query.to_sxp_bin} end if options.has_key?(:load_datasets) queryable = queryable.class.new [options[:default_graph_uri]].flatten.each do |uri| queryable.load(uri) end [options[:named_graph_uri]].flatten.each do |uri| queryable.load(uri, graph_name: uri) end end query.execute(queryable, &block) rescue SPARQL::Grammar::Parser::Error => e raise MalformedQuery, e.message rescue TypeError => e raise QueryRequestRefused, e.message end
Find a content_type from a list using an ordered list of acceptable content types using wildcard matching
@param [Array<String>] acceptable @param [Array<String>] available @return [String]
@see www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
# File lib/sparql/results.rb, line 311 def first_content_type(acceptable, available) return acceptable.first if available.empty? available.flatten! acceptable.each do |pattern| type = available.detect { |t| File.fnmatch(pattern, t) } return type if type end nil end
Parse the given SPARQL
`query` string.
@example
query = SPARQL.parse("SELECT * WHERE { ?s ?p ?o }")
@param [IO, StringIO, String, to_s] query @param [Hash{Symbol => Object}] options @option options [Boolean] :update (false)
Parse starting with UpdateUnit production, QueryUnit otherwise.
@return [SPARQL::Query]
The resulting query may be executed against a `queryable` object such as an RDF::Graph or RDF::Repository.
@raise [Parser::Error] on invalid input
# File lib/sparql.rb, line 33 def self.parse(query, **options) query = Grammar::Parser.new(query, **options).parse(options[:update] ? :UpdateUnit : :QueryUnit) end
Serialize error results
Returns appropriate content based upon an execution exception @param [Exception] exception @param [Hash{Symbol => Object}] options @option options [:format]
Format of results, one of :html, :json or :xml. May also be an RDF::Writer format to serialize DESCRIBE or CONSTRUCT results
@option options [:content_type]
Format of results, one of 'application/sparql-results+json' or 'application/sparql-results+xml' May also be an RDF::Writer content_type to serialize DESCRIBE or CONSTRUCT results
@return [String]
String with serialized results and #content_type
# File lib/sparql/results.rb, line 336 def serialize_exception(exception, **options) format = options[:format] content_type = options[:content_type] content_type ||= SPARQL::Results::MIME_TYPES[format] serialization = case content_type when 'text/html' title = exception.respond_to?(:title) ? exception.title : exception.class.to_s ERROR_MESSAGE % [title, title, exception.message] else content_type = "text/plain" exception.message end serialization.instance_eval do define_singleton_method(:content_type) { content_type } end serialization end
Serialize solutions using the determined format
@param [RDF::Query::Solutions, RDF::Queryable
, Boolean] solutions
Solutions as either a solution set, a Queryable object (such as a graph) or a Boolean value
@param [Hash{Symbol => Object}] options @option options [#to_sym] :format
Format of results, one of :html, :json or :xml. May also be an RDF::Writer format to serialize DESCRIBE or CONSTRUCT results
@option options [String] :content_type
Format of results, one of 'application/sparql-results+json' or 'application/sparql-results+xml' May also be an RDF::Writer content_type to serialize DESCRIBE or CONSTRUCT results
@option options [Array<String>] :content_types
Similar to :content_type, but takes an ordered array of appropriate content types, and serializes using the first appropriate type, including wild-cards.
@return [String]
String with serialized results and `#content_type`
@raise [RDF::WriterError] when inappropriate formatting options are used
# File lib/sparql/results.rb, line 215 def serialize_results(solutions, **options) format = options[:format].to_sym if options[:format] content_type = options[:content_type].to_s.split(';').first content_types = Array(options[:content_types] || '*/*') if !format && !content_type case solutions when RDF::Queryable content_type = first_content_type(content_types, RDF::Format.content_types.keys) || 'text/plain' format = RDF::Writer.for(content_type: content_type).to_sym else content_type = first_content_type(content_types, SPARQL::Results::MIME_TYPES.values) || 'application/sparql-results+xml' format = SPARQL::Results::MIME_TYPES.invert[content_type] end end serialization = case solutions when TrueClass, FalseClass, RDF::Literal::TRUE, RDF::Literal::FALSE solutions = solutions.object if solutions.is_a?(RDF::Literal) case format when :json require 'json' unless defined?(::JSON) {boolean: solutions}.to_json when :xml require 'builder' unless defined?(::Builder) xml = ::Builder::XmlMarkup.new(indent: 2) xml.instruct! xml.sparql(xmlns: "http://www.w3.org/2005/sparql-results#") do xml.boolean(solutions.to_s) end when :html require 'builder' unless defined?(::Builder) content_type = "text/html" xml = ::Builder::XmlMarkup.new(indent: 2) xml.div(solutions.to_s, class: "sparql") else raise RDF::WriterError, "Unknown format #{(format || content_type).inspect} for #{solutions.class}" end when RDF::Queryable begin require 'linkeddata' rescue LoadError require 'rdf/ntriples' end fmt = RDF::Format.for(format ? format.to_sym : {content_type: content_type}) unless fmt fmt = RDF::Format.for(file_extension: format.to_sym) || RDF::NTriples::Format format = fmt.to_sym end format ||= fmt.to_sym content_type ||= fmt.content_type.first results = solutions.dump(format, **options) raise RDF::WriterError, "Unknown format #{fmt.inspect} for #{solutions.class}" unless results results when RDF::Query::Solutions case format when :json then solutions.to_json when :xml then solutions.to_xml when :html then solutions.to_html when :csv then solutions.to_csv when :tsv then solutions.to_tsv else raise RDF::WriterError, "Unknown format #{(format || content_type).inspect} for #{solutions.class}" end end content_type ||= SPARQL::Results::MIME_TYPES[format] if format serialization.instance_eval do define_singleton_method(:content_type) { content_type } end serialization end
Private Instance Methods
Find a content_type from a list using an ordered list of acceptable content types using wildcard matching
@param [Array<String>] acceptable @param [Array<String>] available @return [String]
@see www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
# File lib/sparql/results.rb, line 311 def first_content_type(acceptable, available) return acceptable.first if available.empty? available.flatten! acceptable.each do |pattern| type = available.detect { |t| File.fnmatch(pattern, t) } return type if type end nil end
Serialize error results
Returns appropriate content based upon an execution exception @param [Exception] exception @param [Hash{Symbol => Object}] options @option options [:format]
Format of results, one of :html, :json or :xml. May also be an RDF::Writer format to serialize DESCRIBE or CONSTRUCT results
@option options [:content_type]
Format of results, one of 'application/sparql-results+json' or 'application/sparql-results+xml' May also be an RDF::Writer content_type to serialize DESCRIBE or CONSTRUCT results
@return [String]
String with serialized results and #content_type
# File lib/sparql/results.rb, line 336 def serialize_exception(exception, **options) format = options[:format] content_type = options[:content_type] content_type ||= SPARQL::Results::MIME_TYPES[format] serialization = case content_type when 'text/html' title = exception.respond_to?(:title) ? exception.title : exception.class.to_s ERROR_MESSAGE % [title, title, exception.message] else content_type = "text/plain" exception.message end serialization.instance_eval do define_singleton_method(:content_type) { content_type } end serialization end
Serialize solutions using the determined format
@param [RDF::Query::Solutions, RDF::Queryable
, Boolean] solutions
Solutions as either a solution set, a Queryable object (such as a graph) or a Boolean value
@param [Hash{Symbol => Object}] options @option options [#to_sym] :format
Format of results, one of :html, :json or :xml. May also be an RDF::Writer format to serialize DESCRIBE or CONSTRUCT results
@option options [String] :content_type
Format of results, one of 'application/sparql-results+json' or 'application/sparql-results+xml' May also be an RDF::Writer content_type to serialize DESCRIBE or CONSTRUCT results
@option options [Array<String>] :content_types
Similar to :content_type, but takes an ordered array of appropriate content types, and serializes using the first appropriate type, including wild-cards.
@return [String]
String with serialized results and `#content_type`
@raise [RDF::WriterError] when inappropriate formatting options are used
# File lib/sparql/results.rb, line 215 def serialize_results(solutions, **options) format = options[:format].to_sym if options[:format] content_type = options[:content_type].to_s.split(';').first content_types = Array(options[:content_types] || '*/*') if !format && !content_type case solutions when RDF::Queryable content_type = first_content_type(content_types, RDF::Format.content_types.keys) || 'text/plain' format = RDF::Writer.for(content_type: content_type).to_sym else content_type = first_content_type(content_types, SPARQL::Results::MIME_TYPES.values) || 'application/sparql-results+xml' format = SPARQL::Results::MIME_TYPES.invert[content_type] end end serialization = case solutions when TrueClass, FalseClass, RDF::Literal::TRUE, RDF::Literal::FALSE solutions = solutions.object if solutions.is_a?(RDF::Literal) case format when :json require 'json' unless defined?(::JSON) {boolean: solutions}.to_json when :xml require 'builder' unless defined?(::Builder) xml = ::Builder::XmlMarkup.new(indent: 2) xml.instruct! xml.sparql(xmlns: "http://www.w3.org/2005/sparql-results#") do xml.boolean(solutions.to_s) end when :html require 'builder' unless defined?(::Builder) content_type = "text/html" xml = ::Builder::XmlMarkup.new(indent: 2) xml.div(solutions.to_s, class: "sparql") else raise RDF::WriterError, "Unknown format #{(format || content_type).inspect} for #{solutions.class}" end when RDF::Queryable begin require 'linkeddata' rescue LoadError require 'rdf/ntriples' end fmt = RDF::Format.for(format ? format.to_sym : {content_type: content_type}) unless fmt fmt = RDF::Format.for(file_extension: format.to_sym) || RDF::NTriples::Format format = fmt.to_sym end format ||= fmt.to_sym content_type ||= fmt.content_type.first results = solutions.dump(format, **options) raise RDF::WriterError, "Unknown format #{fmt.inspect} for #{solutions.class}" unless results results when RDF::Query::Solutions case format when :json then solutions.to_json when :xml then solutions.to_xml when :html then solutions.to_html when :csv then solutions.to_csv when :tsv then solutions.to_tsv else raise RDF::WriterError, "Unknown format #{(format || content_type).inspect} for #{solutions.class}" end end content_type ||= SPARQL::Results::MIME_TYPES[format] if format serialization.instance_eval do define_singleton_method(:content_type) { content_type } end serialization end