sparql-client 0.0.0.pre → 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|