sparql-client 0.0.0.pre → 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +99 -0
- data/VERSION +1 -1
- data/lib/sparql/client.rb +194 -1
- data/lib/sparql/version.rb +2 -2
- metadata +6 -9
data/README
CHANGED
@@ -0,0 +1,99 @@
|
|
1
|
+
SPARQL Client for RDF.rb
|
2
|
+
========================
|
3
|
+
|
4
|
+
This is a pure-Ruby implementation of a [SPARQL][] client for [RDF.rb][].
|
5
|
+
|
6
|
+
* <http://github.com/bendiken/sparql-client>
|
7
|
+
|
8
|
+
Features
|
9
|
+
--------
|
10
|
+
|
11
|
+
* Queries SPARQL HTTP endpoints.
|
12
|
+
|
13
|
+
Examples
|
14
|
+
--------
|
15
|
+
|
16
|
+
require 'sparql/client'
|
17
|
+
|
18
|
+
sparql = SPARQL::Client.new('http://dbpedia.org/sparql')
|
19
|
+
|
20
|
+
### Executing a boolean query
|
21
|
+
|
22
|
+
result = sparql.query('ASK WHERE { ?s ?p ?o }')
|
23
|
+
|
24
|
+
puts result.inspect #=> true or false
|
25
|
+
|
26
|
+
### Executing a tuple query
|
27
|
+
|
28
|
+
result = sparql.query('SELECT * WHERE { ?s ?p ?o } LIMIT 10')
|
29
|
+
|
30
|
+
result.each do |bindings|
|
31
|
+
puts bindings.inspect
|
32
|
+
end
|
33
|
+
|
34
|
+
### Executing a graph query
|
35
|
+
|
36
|
+
result = sparql.query('CONSTRUCT { ?s ?p ?o } WHERE { ?s ?p ?o } LIMIT 10')
|
37
|
+
|
38
|
+
result.each_statement do |statement|
|
39
|
+
puts statement.inspect
|
40
|
+
end
|
41
|
+
|
42
|
+
Documentation
|
43
|
+
-------------
|
44
|
+
|
45
|
+
<http://sparql.rubyforge.org/>
|
46
|
+
|
47
|
+
* {SPARQL::Client}
|
48
|
+
|
49
|
+
Dependencies
|
50
|
+
------------
|
51
|
+
|
52
|
+
* [RDF.rb](http://rubygems.org/gems/rdf) (>= 0.1.5)
|
53
|
+
* [JSON](http://rubygems.org/gems/json_pure) (>= 1.2.3)
|
54
|
+
|
55
|
+
Installation
|
56
|
+
------------
|
57
|
+
|
58
|
+
The recommended installation method is via [RubyGems](http://rubygems.org/).
|
59
|
+
To install the latest official release of the `SPARQL::Client` gem, do:
|
60
|
+
|
61
|
+
% [sudo] gem install sparql-client
|
62
|
+
|
63
|
+
Download
|
64
|
+
--------
|
65
|
+
|
66
|
+
To get a local working copy of the development repository, do:
|
67
|
+
|
68
|
+
% git clone git://github.com/bendiken/sparql-client.git
|
69
|
+
|
70
|
+
Alternatively, you can download the latest development version as a tarball
|
71
|
+
as follows:
|
72
|
+
|
73
|
+
% wget http://github.com/bendiken/sparql-client/tarball/master
|
74
|
+
|
75
|
+
Resources
|
76
|
+
---------
|
77
|
+
|
78
|
+
* <http://sparql.rubyforge.org/>
|
79
|
+
* <http://github.com/bendiken/sparql-client>
|
80
|
+
* <http://rubygems.org/gems/sparql-client>
|
81
|
+
* <http://rubyforge.org/projects/sparql/>
|
82
|
+
* <http://raa.ruby-lang.org/project/sparql-client/>
|
83
|
+
* <http://www.ohloh.net/p/rdf>
|
84
|
+
|
85
|
+
Authors
|
86
|
+
-------
|
87
|
+
|
88
|
+
* [Arto Bendiken](mailto:arto.bendiken@gmail.com) - <http://ar.to/>
|
89
|
+
* [Ben Lavender](mailto:blavender@gmail.com) - <http://bhuga.net/>
|
90
|
+
|
91
|
+
License
|
92
|
+
-------
|
93
|
+
|
94
|
+
`SPARQL::Client` is free and unencumbered public domain software. For more
|
95
|
+
information, see <http://unlicense.org/> or the accompanying UNLICENSE file.
|
96
|
+
|
97
|
+
[RDF]: http://www.w3.org/RDF/
|
98
|
+
[SPARQL]: http://en.wikipedia.org/wiki/SPARQL
|
99
|
+
[RDF.rb]: http://rdf.rubyforge.org/
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.1
|
data/lib/sparql/client.rb
CHANGED
@@ -1,8 +1,201 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'rdf'
|
3
|
+
require 'rdf/ntriples'
|
1
4
|
require 'sparql/version'
|
2
5
|
|
3
6
|
module SPARQL
|
4
7
|
##
|
8
|
+
# A SPARQL client for RDF.rb.
|
5
9
|
class Client
|
6
|
-
#
|
10
|
+
RESULT_BOOL = 'text/boolean'.freeze # Sesame-specific
|
11
|
+
RESULT_JSON = 'application/sparql-results+json'.freeze
|
12
|
+
RESULT_XML = 'application/sparql-results+xml'.freeze
|
13
|
+
ACCEPT_JSON = {'Accept' => RESULT_JSON}.freeze
|
14
|
+
ACCEPT_XML = {'Accept' => RESULT_XML}.freeze
|
15
|
+
|
16
|
+
attr_reader :url
|
17
|
+
attr_reader :options
|
18
|
+
|
19
|
+
##
|
20
|
+
# @param [String, #to_s] url
|
21
|
+
# @param [Hash{Symbol => Object}] options
|
22
|
+
def initialize(url, options = {}, &block)
|
23
|
+
@url, @options = RDF::URI.new(url.to_s), options
|
24
|
+
@headers = {'Accept' => "#{RESULT_XML}, #{RESULT_JSON}, text/plain"}
|
25
|
+
|
26
|
+
if block_given?
|
27
|
+
case block.arity
|
28
|
+
when 1 then block.call(self)
|
29
|
+
else instance_eval(&block)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
##
|
35
|
+
# Executes a SPARQL query.
|
36
|
+
#
|
37
|
+
# @param [String, #to_s] url
|
38
|
+
# @param [Hash{Symbol => Object}] options
|
39
|
+
def query(query, options = {})
|
40
|
+
get(query.to_s) do |response|
|
41
|
+
case response
|
42
|
+
when Net::HTTPClientError
|
43
|
+
abort response.inspect # FIXME
|
44
|
+
when Net::HTTPServerError
|
45
|
+
abort response.inspect # FIXME
|
46
|
+
when Net::HTTPSuccess
|
47
|
+
parse_response(response)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
##
|
53
|
+
# @param [Net::HTTPSuccess] response
|
54
|
+
# @return [Object]
|
55
|
+
def parse_response(response)
|
56
|
+
case content_type = response.content_type
|
57
|
+
when RESULT_BOOL # Sesame-specific
|
58
|
+
response.body == 'true'
|
59
|
+
when RESULT_JSON
|
60
|
+
parse_json_bindings(response.body)
|
61
|
+
when RESULT_XML
|
62
|
+
parse_xml_bindings(response.body)
|
63
|
+
else
|
64
|
+
parse_rdf_serialization(response)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
##
|
69
|
+
# @param [String, Hash] json
|
70
|
+
# @return [Enumerable<RDF::Query::Solution>]
|
71
|
+
# @see http://www.w3.org/TR/rdf-sparql-json-res/#results
|
72
|
+
def parse_json_bindings(json)
|
73
|
+
require 'json' unless defined?(::JSON)
|
74
|
+
json = JSON.parse(json.to_s) unless json.is_a?(Hash)
|
75
|
+
|
76
|
+
case
|
77
|
+
when json['boolean']
|
78
|
+
json['boolean']
|
79
|
+
when json['results']
|
80
|
+
json['results']['bindings'].map do |row|
|
81
|
+
row = row.inject({}) do |cols, (name, value)|
|
82
|
+
cols.merge(name => parse_json_value(value))
|
83
|
+
end
|
84
|
+
RDF::Query::Solution.new(row)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
##
|
90
|
+
# @param [Hash{String => String}] value
|
91
|
+
# @return [RDF::Value]
|
92
|
+
# @see http://www.w3.org/TR/rdf-sparql-json-res/#variable-binding-results
|
93
|
+
def parse_json_value(value)
|
94
|
+
case value['type'].to_sym
|
95
|
+
when :bnode
|
96
|
+
@nodes ||= {}
|
97
|
+
@nodes[id = value['value']] ||= RDF::Node.new(id)
|
98
|
+
when :uri
|
99
|
+
RDF::URI.new(value['value'])
|
100
|
+
when :literal
|
101
|
+
RDF::Literal.new(value['value'], :language => value['xml:lang'])
|
102
|
+
when :'typed-literal'
|
103
|
+
RDF::Literal.new(value['value'], :datatype => value['datatype'])
|
104
|
+
else nil
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
##
|
109
|
+
# @param [String, REXML::Element] xml
|
110
|
+
# @return [Enumerable<RDF::Query::Solution>]
|
111
|
+
# @see http://www.w3.org/TR/rdf-sparql-json-res/#results
|
112
|
+
def parse_xml_bindings(xml)
|
113
|
+
require 'rexml/document' unless defined?(::REXML::Document)
|
114
|
+
xml = REXML::Document.new(xml).root unless xml.is_a?(REXML::Element)
|
115
|
+
|
116
|
+
case
|
117
|
+
when boolean = xml.elements['boolean']
|
118
|
+
boolean.text == 'true'
|
119
|
+
when results = xml.elements['results']
|
120
|
+
results.elements.map do |result|
|
121
|
+
row = {}
|
122
|
+
result.elements.each do |binding|
|
123
|
+
name = binding.attributes['name'].to_sym
|
124
|
+
value = binding.select { |node| node.kind_of?(::REXML::Element) }.first
|
125
|
+
row[name] = parse_xml_value(value)
|
126
|
+
end
|
127
|
+
RDF::Query::Solution.new(row)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
##
|
133
|
+
# @param [REXML::Element] value
|
134
|
+
# @return [RDF::Value]
|
135
|
+
# @see http://www.w3.org/TR/rdf-sparql-json-res/#variable-binding-results
|
136
|
+
def parse_xml_value(value)
|
137
|
+
case value.name.to_sym
|
138
|
+
when :bnode
|
139
|
+
@nodes ||= {}
|
140
|
+
@nodes[id = value.text] ||= RDF::Node.new(id)
|
141
|
+
when :uri
|
142
|
+
RDF::URI.new(value.text)
|
143
|
+
when :literal
|
144
|
+
RDF::Literal.new(value.text, {
|
145
|
+
:language => value.attributes['xml:lang'],
|
146
|
+
:datatype => value.attributes['datatype'],
|
147
|
+
})
|
148
|
+
else nil
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
##
|
153
|
+
# @param [Net::HTTPSuccess] response
|
154
|
+
# @return [RDF::Enumerable]
|
155
|
+
def parse_rdf_serialization(response)
|
156
|
+
if reader = RDF::Reader.for(:content_type => response.content_type)
|
157
|
+
reader.new(response.body)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
##
|
162
|
+
# Outputs a developer-friendly representation of this object to `stderr`.
|
163
|
+
#
|
164
|
+
# @return [void]
|
165
|
+
def inspect!
|
166
|
+
warn(inspect)
|
167
|
+
end
|
168
|
+
|
169
|
+
##
|
170
|
+
# Returns a developer-friendly representation of this object.
|
171
|
+
#
|
172
|
+
# @return [String]
|
173
|
+
def inspect
|
174
|
+
sprintf("#<%s:%#0x(%s)>", self.class.name, __id__, url.to_s)
|
175
|
+
end
|
176
|
+
|
177
|
+
protected
|
178
|
+
|
179
|
+
##
|
180
|
+
# Performs an HTTP GET request against the SPARQL endpoint.
|
181
|
+
#
|
182
|
+
# @param [String, #to_s] query
|
183
|
+
# @param [Hash{String => String}] headers
|
184
|
+
# @yield [response]
|
185
|
+
# @yieldparam [Net::HTTPResponse] response
|
186
|
+
# @return [Net::HTTPResponse]
|
187
|
+
def get(query, headers = {}, &block)
|
188
|
+
url = self.url.dup
|
189
|
+
url.query_values = {:query => query.to_s}
|
190
|
+
|
191
|
+
Net::HTTP.start(url.host, url.port) do |http|
|
192
|
+
response = http.get(url.path + "?#{url.query}", @headers.merge(headers))
|
193
|
+
if block_given?
|
194
|
+
block.call(response)
|
195
|
+
else
|
196
|
+
response
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
7
200
|
end
|
8
201
|
end
|
data/lib/sparql/version.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sparql-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
4
|
+
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
|
10
|
-
version: 0.0.0.pre
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
11
10
|
platform: ruby
|
12
11
|
authors:
|
13
12
|
- Arto Bendiken
|
@@ -125,13 +124,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
125
124
|
version: 1.8.2
|
126
125
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
127
126
|
requirements:
|
128
|
-
- - "
|
127
|
+
- - ">="
|
129
128
|
- !ruby/object:Gem::Version
|
130
129
|
segments:
|
131
|
-
-
|
132
|
-
|
133
|
-
- 1
|
134
|
-
version: 1.3.1
|
130
|
+
- 0
|
131
|
+
version: "0"
|
135
132
|
requirements: []
|
136
133
|
|
137
134
|
rubyforge_project: sparql
|