sparql 3.1.8 → 3.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +88 -60
- data/VERSION +1 -1
- data/bin/sparql +15 -35
- data/lib/rack/sparql/conneg.rb +22 -1
- data/lib/sinatra/sparql/extensions.rb +1 -1
- data/lib/sinatra/sparql.rb +57 -12
- data/lib/sparql/algebra/expression.rb +63 -10
- data/lib/sparql/algebra/extensions.rb +110 -46
- data/lib/sparql/algebra/operator/abs.rb +22 -2
- data/lib/sparql/algebra/operator/add.rb +21 -2
- data/lib/sparql/algebra/operator/adjust.rb +69 -0
- data/lib/sparql/algebra/operator/alt.rb +26 -2
- data/lib/sparql/algebra/operator/and.rb +25 -3
- data/lib/sparql/algebra/operator/asc.rb +20 -1
- data/lib/sparql/algebra/operator/ask.rb +17 -1
- data/lib/sparql/algebra/operator/avg.rb +19 -1
- data/lib/sparql/algebra/operator/base.rb +18 -1
- data/lib/sparql/algebra/operator/bgp.rb +13 -1
- data/lib/sparql/algebra/operator/bnode.rb +33 -10
- data/lib/sparql/algebra/operator/bound.rb +22 -1
- data/lib/sparql/algebra/operator/ceil.rb +25 -2
- data/lib/sparql/algebra/operator/clear.rb +26 -2
- data/lib/sparql/algebra/operator/coalesce.rb +33 -11
- data/lib/sparql/algebra/operator/compare.rb +9 -0
- data/lib/sparql/algebra/operator/concat.rb +26 -2
- data/lib/sparql/algebra/operator/construct.rb +29 -6
- data/lib/sparql/algebra/operator/contains.rb +24 -2
- data/lib/sparql/algebra/operator/copy.rb +19 -2
- data/lib/sparql/algebra/operator/count.rb +52 -6
- data/lib/sparql/algebra/operator/create.rb +20 -2
- data/lib/sparql/algebra/operator/dataset.rb +37 -2
- data/lib/sparql/algebra/operator/datatype.rb +25 -6
- data/lib/sparql/algebra/operator/day.rb +25 -7
- data/lib/sparql/algebra/operator/delete.rb +29 -2
- data/lib/sparql/algebra/operator/delete_data.rb +23 -2
- data/lib/sparql/algebra/operator/delete_where.rb +24 -2
- data/lib/sparql/algebra/operator/desc.rb +20 -1
- data/lib/sparql/algebra/operator/describe.rb +27 -4
- data/lib/sparql/algebra/operator/distinct.rb +20 -3
- data/lib/sparql/algebra/operator/divide.rb +26 -2
- data/lib/sparql/algebra/operator/drop.rb +27 -3
- data/lib/sparql/algebra/operator/encode_for_uri.rb +22 -2
- data/lib/sparql/algebra/operator/equal.rb +12 -2
- data/lib/sparql/algebra/operator/exists.rb +28 -4
- data/lib/sparql/algebra/operator/exprlist.rb +15 -2
- data/lib/sparql/algebra/operator/extend.rb +95 -7
- data/lib/sparql/algebra/operator/filter.rb +27 -5
- data/lib/sparql/algebra/operator/floor.rb +25 -2
- data/lib/sparql/algebra/operator/function_call.rb +64 -0
- data/lib/sparql/algebra/operator/graph.rb +69 -6
- data/lib/sparql/algebra/operator/greater_than.rb +12 -3
- data/lib/sparql/algebra/operator/greater_than_or_equal.rb +12 -2
- data/lib/sparql/algebra/operator/group.rb +133 -8
- data/lib/sparql/algebra/operator/group_concat.rb +43 -7
- data/lib/sparql/algebra/operator/hours.rb +25 -7
- data/lib/sparql/algebra/operator/if.rb +20 -3
- data/lib/sparql/algebra/operator/in.rb +18 -1
- data/lib/sparql/algebra/operator/insert.rb +24 -2
- data/lib/sparql/algebra/operator/insert_data.rb +23 -2
- data/lib/sparql/algebra/operator/iri.rb +21 -4
- data/lib/sparql/algebra/operator/is_blank.rb +20 -3
- data/lib/sparql/algebra/operator/is_iri.rb +20 -3
- data/lib/sparql/algebra/operator/is_literal.rb +20 -3
- data/lib/sparql/algebra/operator/is_numeric.rb +22 -5
- data/lib/sparql/algebra/operator/is_triple.rb +32 -0
- data/lib/sparql/algebra/operator/join.rb +58 -3
- data/lib/sparql/algebra/operator/lang.rb +25 -0
- data/lib/sparql/algebra/operator/lang_matches.rb +22 -1
- data/lib/sparql/algebra/operator/lcase.rb +22 -2
- data/lib/sparql/algebra/operator/left_join.rb +44 -3
- data/lib/sparql/algebra/operator/less_than.rb +12 -3
- data/lib/sparql/algebra/operator/less_than_or_equal.rb +12 -2
- data/lib/sparql/algebra/operator/load.rb +25 -2
- data/lib/sparql/algebra/operator/max.rb +19 -1
- data/lib/sparql/algebra/operator/md5.rb +22 -5
- data/lib/sparql/algebra/operator/min.rb +21 -3
- data/lib/sparql/algebra/operator/minus.rb +65 -7
- data/lib/sparql/algebra/operator/minutes.rb +25 -7
- data/lib/sparql/algebra/operator/modify.rb +62 -5
- data/lib/sparql/algebra/operator/month.rb +25 -7
- data/lib/sparql/algebra/operator/move.rb +20 -2
- data/lib/sparql/algebra/operator/multiply.rb +26 -3
- data/lib/sparql/algebra/operator/negate.rb +23 -3
- data/lib/sparql/algebra/operator/not.rb +24 -3
- data/lib/sparql/algebra/operator/not_equal.rb +13 -0
- data/lib/sparql/algebra/operator/notexists.rb +30 -6
- data/lib/sparql/algebra/operator/notin.rb +20 -3
- data/lib/sparql/algebra/operator/notoneof.rb +21 -2
- data/lib/sparql/algebra/operator/now.rb +24 -5
- data/lib/sparql/algebra/operator/object.rb +32 -0
- data/lib/sparql/algebra/operator/or.rb +26 -3
- data/lib/sparql/algebra/operator/order.rb +64 -1
- data/lib/sparql/algebra/operator/path.rb +29 -2
- data/lib/sparql/algebra/operator/path_opt.rb +28 -65
- data/lib/sparql/algebra/operator/path_plus.rb +37 -10
- data/lib/sparql/algebra/operator/path_range.rb +178 -0
- data/lib/sparql/algebra/operator/path_star.rb +25 -4
- data/lib/sparql/algebra/operator/path_zero.rb +110 -0
- data/lib/sparql/algebra/operator/plus.rb +49 -8
- data/lib/sparql/algebra/operator/predicate.rb +32 -0
- data/lib/sparql/algebra/operator/prefix.rb +24 -3
- data/lib/sparql/algebra/operator/project.rb +111 -6
- data/lib/sparql/algebra/operator/rand.rb +30 -2
- data/lib/sparql/algebra/operator/reduced.rb +20 -3
- data/lib/sparql/algebra/operator/regex.rb +26 -18
- data/lib/sparql/algebra/operator/replace.rb +26 -6
- data/lib/sparql/algebra/operator/reverse.rb +31 -2
- data/lib/sparql/algebra/operator/round.rb +25 -2
- data/lib/sparql/algebra/operator/same_term.rb +24 -6
- data/lib/sparql/algebra/operator/sample.rb +32 -8
- data/lib/sparql/algebra/operator/seconds.rb +25 -7
- data/lib/sparql/algebra/operator/seq.rb +23 -5
- data/lib/sparql/algebra/operator/sequence.rb +14 -11
- data/lib/sparql/algebra/operator/sha1.rb +18 -1
- data/lib/sparql/algebra/operator/sha256.rb +18 -1
- data/lib/sparql/algebra/operator/sha384.rb +18 -1
- data/lib/sparql/algebra/operator/sha512.rb +18 -1
- data/lib/sparql/algebra/operator/slice.rb +27 -5
- data/lib/sparql/algebra/operator/str.rb +21 -1
- data/lib/sparql/algebra/operator/strafter.rb +25 -2
- data/lib/sparql/algebra/operator/strbefore.rb +25 -2
- data/lib/sparql/algebra/operator/strdt.rb +22 -1
- data/lib/sparql/algebra/operator/strends.rb +25 -3
- data/lib/sparql/algebra/operator/strlang.rb +24 -6
- data/lib/sparql/algebra/operator/strlen.rb +23 -2
- data/lib/sparql/algebra/operator/strstarts.rb +25 -2
- data/lib/sparql/algebra/operator/struuid.rb +29 -9
- data/lib/sparql/algebra/operator/subject.rb +32 -0
- data/lib/sparql/algebra/operator/substr.rb +23 -2
- data/lib/sparql/algebra/operator/subtract.rb +37 -7
- data/lib/sparql/algebra/operator/sum.rb +24 -6
- data/lib/sparql/algebra/operator/table.rb +85 -4
- data/lib/sparql/algebra/operator/timezone.rb +25 -7
- data/lib/sparql/algebra/operator/triple.rb +24 -0
- data/lib/sparql/algebra/operator/tz.rb +24 -7
- data/lib/sparql/algebra/operator/ucase.rb +23 -2
- data/lib/sparql/algebra/operator/union.rb +29 -6
- data/lib/sparql/algebra/operator/update.rb +46 -4
- data/lib/sparql/algebra/operator/using.rb +49 -2
- data/lib/sparql/algebra/operator/uuid.rb +27 -8
- data/lib/sparql/algebra/operator/with.rb +38 -4
- data/lib/sparql/algebra/operator/year.rb +25 -7
- data/lib/sparql/algebra/operator.rb +150 -12
- data/lib/sparql/algebra/query.rb +5 -3
- data/lib/sparql/algebra/sxp_extensions.rb +3 -3
- data/lib/sparql/algebra.rb +42 -6
- data/lib/sparql/grammar/meta.rb +1367 -267
- data/lib/sparql/grammar/parser11.rb +829 -331
- data/lib/sparql/grammar/terminals11.rb +2 -2
- data/lib/sparql/grammar.rb +6 -4
- data/lib/sparql/results.rb +3 -2
- data/lib/sparql/server.rb +93 -0
- data/lib/sparql.rb +8 -5
- metadata +57 -35
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 853c52b99bab0b9455b25a81c8c946e5bcb1429dddadf010b66315f1dbafda51
|
4
|
+
data.tar.gz: 90d89877c031476efdaa1d0b119b2a2404925186b4e0b3de99818d75ead76bff
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 98816c81664147aa0fa4ccd90ed14461eb51b652b011395f38f044934c2ff335197fbc3d2d7f447771a5b1e46fa24042aef45fd1f95356b91f52bafee48d1a72
|
7
|
+
data.tar.gz: 5545d7ddd245d73382229ed6f9996b24bd66a4285ee18d6295f697202ad5901eb4221cbf2533ef1539b98ccc0c095519e531b541db3e1c4757d813ab888cb9fd
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
# SPARQL for
|
1
|
+
# SPARQL Query and Update library for Ruby
|
2
2
|
|
3
|
-
|
3
|
+
An implementation of [SPARQL][] for [RDF.rb][].
|
4
4
|
|
5
5
|
[![Gem Version](https://badge.fury.io/rb/sparql.png)](https://badge.fury.io/rb/sparql)
|
6
6
|
[![Build Status](https://github.com/ruby-rdf/sparql/workflows/CI/badge.svg?branch=develop)](https://github.com/ruby-rdf/sparql/actions?query=workflow%3ACI)
|
@@ -17,24 +17,26 @@ This is a [Ruby][] implementation of [SPARQL][] for [RDF.rb][].
|
|
17
17
|
or HTML.
|
18
18
|
* SPARQL CONSTRUCT or DESCRIBE serialized based on Format, Extension of Mime Type
|
19
19
|
using available RDF Writers (see [Linked Data][])
|
20
|
-
* SPARQL Client for accessing remote SPARQL endpoints.
|
21
|
-
* SPARQL
|
20
|
+
* SPARQL Client for accessing remote SPARQL endpoints (via [sparql-client](https://github.com/ruby-rdf/sparql-client)).
|
21
|
+
* [SPARQL 1.1 Protocol][] (via {SPARQL::Server}).
|
22
|
+
* [SPARQL 1.1 Update][]
|
22
23
|
* [Rack][] and [Sinatra][] middleware to perform [HTTP content negotiation][conneg] for result formats
|
23
24
|
* Compatible with any [Rack][] or [Sinatra][] application and any Rack-based framework.
|
24
25
|
* Helper method for describing [SPARQL Service Description][SSD]
|
26
|
+
* Helper method for setting up datasets as part of the [SPARQL 1.1 Protocol][].
|
25
27
|
* Implementation Report: {file:etc/earl.html EARL}
|
26
|
-
* Compatible with Ruby >= 2.
|
27
|
-
* Compatible with older Ruby versions with the help of the [Backports][] gem.
|
28
|
+
* Compatible with Ruby >= 2.6.
|
28
29
|
* Supports Unicode query strings both on all versions of Ruby.
|
29
30
|
* Provisional support for [SPARQL-star][].
|
30
31
|
|
31
32
|
## Description
|
32
33
|
|
33
|
-
The {SPARQL} gem implements [SPARQL 1.1 Query][], and [SPARQL 1.1 Update][], and provides [Rack][] and [Sinatra][] middleware to provide results using [HTTP Content Negotiation][conneg].
|
34
|
+
The {SPARQL} gem implements [SPARQL 1.1 Query][], and [SPARQL 1.1 Update][], and provides [Rack][] and [Sinatra][] middleware to provide results using [HTTP Content Negotiation][conneg] and to support [SPARQL 1.1 Protocol][].
|
34
35
|
|
35
36
|
* {SPARQL::Grammar} implements a [SPARQL 1.1 Query][] and [SPARQL 1.1 Update][] parser generating [SPARQL S-Expressions (SSE)][SSE].
|
36
37
|
* {SPARQL::Algebra} executes SSE against Any `RDF::Graph` or `RDF::Repository`, including compliant [RDF.rb][] repository adaptors such as [RDF::DO][] and [RDF::Mongo][].
|
37
38
|
* {Rack::SPARQL} and {Sinatra::SPARQL} provide middleware components to format results using an appropriate format based on [HTTP content negotiation][conneg].
|
39
|
+
* {SPARQL::Server} implements the [SPARQL 1.1 Protocol][] using {Sinatra::SPARQL}.
|
38
40
|
|
39
41
|
### [SPARQL 1.1 Query][] Extensions and Limitations
|
40
42
|
The {SPARQL} gem uses the [SPARQL 1.1 Query][] {file:etc/sparql11.html EBNF grammar}, which provides much more capability than [SPARQL 1.0][], but has a few limitations:
|
@@ -63,17 +65,22 @@ The gem also includes the following [SPARQL 1.1 Update][] operations:
|
|
63
65
|
Not supported:
|
64
66
|
|
65
67
|
* [Federated Query][SPARQL 1.1 Federated Query],
|
66
|
-
* [Entailment Regimes][SPARQL 1.1 Entailment Regimes],
|
67
|
-
* [Protocol][SPARQL 1.1 Protocol]
|
68
|
-
* [Graph Store HTTP Protocol][SPARQL 1.1 Graph Store HTTP Protocol]
|
69
|
-
|
70
|
-
either in this, or related gems.
|
68
|
+
* [Entailment Regimes][SPARQL 1.1 Entailment Regimes], and
|
69
|
+
* [Graph Store HTTP Protocol][SPARQL 1.1 Graph Store HTTP Protocol] but the closely related [Linked Data Platform][] implemented in [rdf-ldp](https://github.com/ruby-rdf/rdf-ldp) supports these use cases.
|
71
70
|
|
72
71
|
### Updates for RDF 1.1
|
73
72
|
Starting with version 1.1.2, the SPARQL gem uses the 1.1 version of the [RDF.rb][], which adheres to [RDF 1.1 Concepts](https://www.w3.org/TR/rdf11-concepts/) rather than [RDF 1.0](https://www.w3.org/TR/rdf-concepts/). The main difference is that there is now no difference between a _Simple Literal_ (a literal with no datatype or language) and a Literal with datatype _xsd:string_; this causes some minor differences in the way in which queries are understood, and when expecting different results.
|
74
73
|
|
75
74
|
Additionally, queries now take a block, or return an `Enumerator`; this is in keeping with much of the behavior of [RDF.rb][] methods, including `Queryable#query`, and with version 1.1 or [RDF.rb][], Query#execute. As a consequence, all queries which used to be of the form `query.execute(repository)` may equally be called as `repository.query(query)`. Previously, results were returned as a concrete class implementing `RDF::Queryable` or `RDF::Query::Solutions`, these are now `Enumerators`.
|
76
75
|
|
76
|
+
### SPARQL 1.2
|
77
|
+
The gem supports some of the extensions proposed by the [SPARQL 1.2 Community Group](https://github.com/w3c/sparql-12). In particular, the following extensions are now implemented:
|
78
|
+
|
79
|
+
* [SEP-0002: better support for Durations, Dates, and Times](https://github.com/w3c/sparql-12/blob/main/SEP/SEP-0002/sep-0002.md)
|
80
|
+
* This includes full support for `xsd:date`, `xsd:time`, `xsd:duration`, `xsd:dayTimeDuration`, and `xsd:yearMonthDuration` along with associated XPath/XQuery functions including a new `ADJUST` builtin. (**Note: This feature is subject to change or elimination as the standards process progresses.**)
|
81
|
+
* [SEP-0003: Property paths with a min/max hop](https://github.com/w3c/sparql-12/blob/main/SEP/SEP-0003/sep-0003.md)
|
82
|
+
* This includes support for non-counting path forms such as `rdf:rest{1,3}` to match the union of paths `rdf:rest`, `rdf:rest/rdf:rest`, and `rdf:rest/rdf:rest/rdf:rest`. (**Note: This feature is subject to change or elimination as the standards process progresses.**)
|
83
|
+
|
77
84
|
### SPARQL Extension Functions
|
78
85
|
Extension functions may be defined, which will be invoked during query evaluation. For example:
|
79
86
|
|
@@ -96,6 +103,10 @@ Then, use the function in a query:
|
|
96
103
|
|
97
104
|
See {SPARQL::Algebra::Expression.register_extension} for details.
|
98
105
|
|
106
|
+
### Variable Pre-binding
|
107
|
+
|
108
|
+
A call to execute a parsed query can include pre-bound variables, which cause queries to be executed with matching variables bound as defined. Variable pre-binding can be done using a Hash structure, or a Query Solution. See [Query with Binding example](#query-with-binding) and {SPARQL::Algebra::Query#execute}.
|
109
|
+
|
99
110
|
### SPARQLStar (SPARQL-star)
|
100
111
|
|
101
112
|
The gem supports [SPARQL-star][] where patterns may include sub-patterns recursively, for a kind of Reification.
|
@@ -163,44 +174,31 @@ Note that results can be serialized only when the format supports [RDF-star][].
|
|
163
174
|
|
164
175
|
#### SPARQL results
|
165
176
|
|
166
|
-
The SPARQL results formats are extended to serialize
|
177
|
+
The SPARQL results formats are extended to serialize quoted triples as described for [RDF4J](https://rdf4j.org/documentation/programming/rdfstar/):
|
167
178
|
|
168
179
|
{
|
169
180
|
"head" : {
|
170
|
-
"vars" : [
|
171
|
-
"a",
|
172
|
-
"b",
|
173
|
-
"c"
|
174
|
-
]
|
181
|
+
"vars" : ["a", "b", "c"]
|
175
182
|
},
|
176
183
|
"results" : {
|
177
184
|
"bindings": [
|
178
185
|
{ "a" : {
|
179
186
|
"type" : "triple",
|
180
187
|
"value" : {
|
181
|
-
"s" : {
|
182
|
-
|
183
|
-
"value" : "http://example.org/bob"
|
184
|
-
},
|
185
|
-
"p" : {
|
186
|
-
"type" : "uri",
|
187
|
-
"value" : "http://xmlns.com/foaf/0.1/name"
|
188
|
-
},
|
188
|
+
"s" : {"value" : "http://example.org/bob", "type": "uri"},
|
189
|
+
"p" : {"value" : "http://xmlns.com/foaf/0.1/name", "type": "uri"},
|
189
190
|
"o" : {
|
190
|
-
"
|
191
|
+
"value" : "23",
|
191
192
|
"type" : "literal",
|
192
|
-
"
|
193
|
+
"datatype" : "http://www.w3.org/2001/XMLSchema#integer"
|
193
194
|
}
|
194
195
|
}
|
195
196
|
},
|
196
|
-
"b": {
|
197
|
-
"type": "uri",
|
198
|
-
"value": "http://example.org/certainty"
|
199
|
-
},
|
197
|
+
"b": {"value": "http://example.org/certainty", "type": "uri"},
|
200
198
|
"c" : {
|
201
|
-
"
|
199
|
+
"value" : "0.9",
|
202
200
|
"type" : "literal",
|
203
|
-
"
|
201
|
+
"datatype" : "http://www.w3.org/2001/XMLSchema#decimal"
|
204
202
|
}
|
205
203
|
}
|
206
204
|
]
|
@@ -215,17 +213,23 @@ You would typically return an instance of `RDF::Graph`, `RDF::Repository` or an
|
|
215
213
|
from your Rack application, and let the `Rack::SPARQL::ContentNegotiation` middleware
|
216
214
|
take care of serializing your response into whatever format the HTTP
|
217
215
|
client requested and understands.
|
216
|
+
Content negotiation also transforms `application/x-www-form-urlencoded` to either `application/sparql-query`
|
217
|
+
or `application/sparql-update` as appropriate for [SPARQL 1.1 Protocol][].
|
218
218
|
|
219
219
|
{Sinatra::SPARQL} is a thin Sinatra-specific wrapper around the
|
220
220
|
{Rack::SPARQL} middleware, which implements SPARQL
|
221
221
|
content negotiation for Rack applications. {Sinatra::SPARQL} also supports
|
222
|
-
[SPARQL 1.1 Service Description][].
|
222
|
+
[SPARQL 1.1 Service Description][] (via {Sinatra::SPARQL::Helpers.service_description} and protocol-based dataset mangement via {Sinatra::SPARQL::Helpers.dataset} for `default-graph-uri` and `named-graph-uri` The `using-graph-uri` and `using-named-graph-uri` query parameters are managed through {SPARQL::Algebra::Operator::Modify#execute}.
|
223
223
|
|
224
224
|
The middleware queries [RDF.rb][] for the MIME content types of known RDF
|
225
225
|
serialization formats, so it will work with whatever serialization extensions
|
226
226
|
that are currently available for RDF.rb. (At present, this includes support
|
227
227
|
for N-Triples, N-Quads, Turtle, RDF/XML, RDF/JSON, JSON-LD, RDFa, TriG and TriX.)
|
228
228
|
|
229
|
+
### Server
|
230
|
+
|
231
|
+
A simple [Sinatra][]-based server is implemented in {SPARQL::Server.application} using {Rack::SPARQL} and {Sinatra::SPARQL} completes the implementation of [SPARQL 1.1 Protocol][] and can be used to compose a server including other capabilities.
|
232
|
+
|
229
233
|
### Remote datasets
|
230
234
|
|
231
235
|
A SPARQL query containing `FROM` or `FROM NAMED` (also `UPDATE` or `UPDATE NAMED`) will load the referenced IRI unless the repository already contains a graph with that same IRI. This is performed using [RDF.rb][] `RDF::Util::File.open_file` passing HTTP Accept headers for various available RDF formats. For best results, require [Linked Data][] to enable a full set of RDF formats in the `GET` request. Also, consider overriding `RDF::Util::File.open_file` with an implementation with support for HTTP Get headers (such as `Net::HTTP`).
|
@@ -248,27 +252,27 @@ a full set of RDF formats.
|
|
248
252
|
### Querying a repository with a SPARQL query
|
249
253
|
|
250
254
|
queryable = RDF::Repository.load("etc/doap.ttl")
|
251
|
-
|
252
|
-
queryable.query(
|
255
|
+
query = SPARQL.parse("SELECT * WHERE { ?s ?p ?o }")
|
256
|
+
queryable.query(query) do |result|
|
253
257
|
result.inspect
|
254
258
|
end
|
255
259
|
|
256
260
|
### Executing a SPARQL query against a repository
|
257
261
|
|
258
262
|
queryable = RDF::Repository.load("etc/doap.ttl")
|
259
|
-
|
260
|
-
|
263
|
+
query = SPARQL.parse("SELECT * WHERE { ?s ?p ?o }")
|
264
|
+
query.execute(queryable) do |result|
|
261
265
|
result.inspect
|
262
266
|
end
|
263
267
|
|
264
268
|
### Updating a repository
|
265
269
|
|
266
270
|
queryable = RDF::Repository.load("etc/doap.ttl")
|
267
|
-
|
271
|
+
update = SPARQL.parse(%(
|
268
272
|
PREFIX doap: <http://usefulinc.com/ns/doap#>
|
269
273
|
INSERT DATA { <https://rubygems> doap:implements <http://www.w3.org/TR/sparql11-update/>}
|
270
274
|
), update: true)
|
271
|
-
|
275
|
+
update.execute(queryable)
|
272
276
|
|
273
277
|
### Rendering solutions as JSON, XML, CSV, TSV or HTML
|
274
278
|
queryable = RDF::Repository.load("etc/doap.ttl")
|
@@ -277,8 +281,29 @@ a full set of RDF formats.
|
|
277
281
|
|
278
282
|
### Parsing a SPARQL query string to SSE
|
279
283
|
|
280
|
-
|
281
|
-
|
284
|
+
query = SPARQL.parse("SELECT * WHERE { ?s ?p ?o }")
|
285
|
+
query.to_sxp #=> (bgp (triple ?s ?p ?o))
|
286
|
+
|
287
|
+
### Parsing a SSE to SPARQL query or update string to SPARQL
|
288
|
+
|
289
|
+
# Note: if the SSE uses extension functions, they either must be XSD casting functions, or custom functions which are registered extensions. (See [SPARQL Extension Functions](#sparql-extension-functions))
|
290
|
+
|
291
|
+
query = SPARQL::Algebra.parse(%{(bgp (triple ?s ?p ?o))})
|
292
|
+
sparql = query.to_sparql #=> "SELECT * WHERE { ?s ?p ?o }"
|
293
|
+
|
294
|
+
### Query with Binding
|
295
|
+
|
296
|
+
bindings = {page: RDF::URI("https://greggkellogg.net/")}
|
297
|
+
queryable = RDF::Repository.load("etc/doap.ttl")
|
298
|
+
query = SPARQL.parse(%(
|
299
|
+
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
|
300
|
+
SELECT ?person
|
301
|
+
WHERE {
|
302
|
+
?person foaf:homepage ?page .
|
303
|
+
}
|
304
|
+
))
|
305
|
+
solutions = query.execute(queryable, bindings: bindings)
|
306
|
+
solutions.to_sxp #=> (((person <https://greggkellogg.net/foaf#me>)))
|
282
307
|
|
283
308
|
### Command line processing
|
284
309
|
|
@@ -289,6 +314,10 @@ a full set of RDF formats.
|
|
289
314
|
sparql parse etc/input.rq
|
290
315
|
sparql parse -e "SELECT * WHERE { ?s ?p ?o }"
|
291
316
|
|
317
|
+
# Generate SPARQL Query from SSE
|
318
|
+
sparql parse --sse etc/input.sse --format sparql
|
319
|
+
sparql parse --sse --format sparql -e "(dataset (<http://usefulinc.com/ns/doap>) (bgp (triple ?s ?p ?o))))"
|
320
|
+
|
292
321
|
# Run query using SSE input
|
293
322
|
sparql execute --dataset etc/doap.ttl --sse etc/input.sse
|
294
323
|
sparql execute --sse -e "(dataset (<etc/doap.ttl>) (bgp (triple ?s ?p ?o))))"
|
@@ -368,19 +397,19 @@ Full documentation available on [Rubydoc.info][SPARQL doc]
|
|
368
397
|
|
369
398
|
## Dependencies
|
370
399
|
|
371
|
-
* [Ruby](https://ruby-lang.org/) (>= 2.
|
372
|
-
* [RDF.rb](https://rubygems.org/gems/rdf) (~> 3.
|
373
|
-
* [SPARQL::Client](https://rubygems.org/gems/sparql-client) (~> 3.
|
374
|
-
* [SXP](https://rubygems.org/gems/sxp) (~> 1.
|
375
|
-
* [Builder](https://rubygems.org/gems/builder) (
|
376
|
-
* [JSON](https://rubygems.org/gems/json) (
|
377
|
-
* Soft dependency on [Linked Data][] (>= 3.
|
378
|
-
* Soft dependency on [Nokogiri](https://rubygems.org/gems/nokogiri) (
|
400
|
+
* [Ruby](https://ruby-lang.org/) (>= 2.6)
|
401
|
+
* [RDF.rb](https://rubygems.org/gems/rdf) (~> 3.2)
|
402
|
+
* [SPARQL::Client](https://rubygems.org/gems/sparql-client) (~> 3.1)
|
403
|
+
* [SXP](https://rubygems.org/gems/sxp) (~> 1.2)
|
404
|
+
* [Builder](https://rubygems.org/gems/builder) (~> 3.2)
|
405
|
+
* [JSON](https://rubygems.org/gems/json) (~> 2.6)
|
406
|
+
* Soft dependency on [Linked Data][] (>= 3.1)
|
407
|
+
* Soft dependency on [Nokogiri](https://rubygems.org/gems/nokogiri) (~> 1.12)
|
379
408
|
Falls back to REXML for XML parsing Builder for XML serializing. Nokogiri is much more efficient
|
380
|
-
* Soft dependency on [Equivalent XML](https://rubygems.org/gems/equivalent-xml) (>= 0.
|
409
|
+
* Soft dependency on [Equivalent XML](https://rubygems.org/gems/equivalent-xml) (>= 0.6)
|
381
410
|
Equivalent XML performs more efficient comparisons of XML Literals when Nokogiri is included
|
382
|
-
* Soft dependency on [Rack][] (
|
383
|
-
* Soft dependency on [Sinatra][] (
|
411
|
+
* Soft dependency on [Rack][] (~> 2.2)
|
412
|
+
* Soft dependency on [Sinatra][] (~> 2.1)
|
384
413
|
|
385
414
|
## Installation
|
386
415
|
|
@@ -425,7 +454,7 @@ This repository uses [Git Flow](https://github.com/nvie/gitflow) to mange develo
|
|
425
454
|
## License
|
426
455
|
|
427
456
|
This is free and unencumbered public domain software. For more information,
|
428
|
-
see <https://unlicense.org/> or the accompanying {file:UNLICENSE}
|
457
|
+
see <https://unlicense.org/> or the accompanying {file:UNLICENSE}.
|
429
458
|
|
430
459
|
A copy of the [SPARQL EBNF][] and derived parser files are included in the repository, which are not covered under the UNLICENSE. These files are covered via the [W3C Document License](https://www.w3.org/Consortium/Legal/2002/copyright-documents-20021231).
|
431
460
|
|
@@ -444,15 +473,14 @@ A copy of the [SPARQL 1.0 tests][] and [SPARQL 1.1 tests][] are also included in
|
|
444
473
|
[SPARQL 1.0 tests]:https://www.w3.org/2001/sw/DataAccess/tests/
|
445
474
|
[SPARQL 1.1 tests]: https://www.w3.org/2009/sparql/docs/tests/
|
446
475
|
[SSE]: https://jena.apache.org/documentation/notes/sse.html
|
447
|
-
[SXP]: https://
|
476
|
+
[SXP]: https://dryruby.github.io/sxp
|
448
477
|
[grammar]: https://www.w3.org/TR/sparql11-query/#grammar
|
449
478
|
[RDF 1.1]: https://www.w3.org/TR/rdf11-concepts
|
450
|
-
[RDF.rb]: https://
|
479
|
+
[RDF.rb]: https://ruby-rdf.github.io/rdf
|
451
480
|
[RDF-star]: https://w3c.github.io/rdf-star/rdf-star-cg-spec.html
|
452
481
|
[SPARQL-star]: https://w3c.github.io/rdf-star/rdf-star-cg-spec.html#sparql-query-language
|
453
|
-
[Backports]: https://rubygems.org/gems/backports
|
454
482
|
[Linked Data]: https://rubygems.org/gems/linkeddata
|
455
|
-
[SPARQL doc]: https://
|
483
|
+
[SPARQL doc]: https://ruby-rdf.github.io/sparql/frames
|
456
484
|
[SPARQL XML]: https://www.w3.org/TR/rdf-sparql-XMLres/
|
457
485
|
[SPARQL JSON]: https://www.w3.org/TR/rdf-sparql-json-res/
|
458
486
|
[SPARQL EBNF]: https://www.w3.org/TR/sparql11-query/#sparqlGrammar
|
@@ -472,4 +500,4 @@ A copy of the [SPARQL 1.0 tests][] and [SPARQL 1.1 tests][] are also included in
|
|
472
500
|
[SPARQL 1.1 Entailment Regimes]: https://www.w3.org/TR/sparql11-entailment/
|
473
501
|
[SPARQL 1.1 Protocol]: https://www.w3.org/TR/sparql11-protocol/
|
474
502
|
[SPARQL 1.1 Graph Store HTTP Protocol]: https://www.w3.org/TR/sparql11-http-rdf-update/
|
475
|
-
|
503
|
+
[Linked Data Platform]: https://www.w3.org/TR/ldp/
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.
|
1
|
+
3.2.3
|
data/bin/sparql
CHANGED
@@ -45,48 +45,28 @@ def run(input, **options)
|
|
45
45
|
SPARQL::Grammar.parse(input, **options)
|
46
46
|
end
|
47
47
|
|
48
|
-
puts ("\nSSE:\n" + query.to_sse) if options[:debug]
|
48
|
+
puts ("\nSSE:\n" + query.to_sse) if options[:debug]
|
49
49
|
|
50
|
-
|
50
|
+
if options[:parse_only]
|
51
|
+
case options[:format]
|
52
|
+
when :sparql
|
53
|
+
puts ("\nSPARQL:\n" + query.to_sparql)
|
54
|
+
when nil, :sse
|
55
|
+
puts ("\nSSE:\n" + query.to_sse)
|
56
|
+
else
|
57
|
+
$stderr.puts "Unknown output format for parsing: #{options[:format]}. Use 'sse' or 'sparql'"
|
58
|
+
end
|
59
|
+
else
|
51
60
|
res = query.execute(options[:dataset], logger: options[:logger])
|
52
61
|
display_results(res, **options)
|
53
62
|
end
|
54
63
|
end
|
55
64
|
|
56
65
|
def server(options)
|
57
|
-
|
58
|
-
repository = options.fetch(:dataset, RDF::Repository.new)
|
59
|
-
|
60
|
-
app = Sinatra.new do
|
61
|
-
register Sinatra::SPARQL
|
62
|
-
set :repository, repository
|
63
|
-
|
64
|
-
before do
|
65
|
-
options[:logger].info "#{request.request_method} [#{request.path_info}], " +
|
66
|
-
params.merge(Accept: request.accept.map(&:to_s)).map {|k,v| "#{k}=#{v}" unless k.to_s == "content"}.join(" ")
|
67
|
-
end
|
68
|
-
|
69
|
-
get '/' do
|
70
|
-
if params["query"]
|
71
|
-
query = params["query"].to_s.match(/^http:/) ? RDF::Util::File.open_file(params["query"]) : ::CGI.unescape(params["query"].to_s)
|
72
|
-
SPARQL.execute(query, settings.repository)
|
73
|
-
else
|
74
|
-
settings.sparql_options.replace(standard_prefixes: true)
|
75
|
-
settings.sparql_options.merge!(:prefixes => {
|
76
|
-
ssd: "http://www.w3.org/ns/sparql-service-description#",
|
77
|
-
void: "http://rdfs.org/ns/void#"
|
78
|
-
})
|
79
|
-
service_description(repo: settings.repository, endpoint: url)
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
post '/' do
|
84
|
-
SPARQL.execute(params['query'], settings.repository)
|
85
|
-
end
|
86
|
-
end
|
66
|
+
app = SPARQL::Server.application(**options)
|
87
67
|
Rack::Server.start(app: app, Port: options.fetch(:port, 9292))
|
88
68
|
rescue LoadError
|
89
|
-
$stderr.puts "Running SPARQL server requires Rack to be in environment: #{$!.message}"
|
69
|
+
$stderr.puts "Running SPARQL server requires Rack and Sinatra to be in environment: #{$!.message}"
|
90
70
|
end
|
91
71
|
|
92
72
|
def usage
|
@@ -98,7 +78,7 @@ def usage
|
|
98
78
|
puts " --dataset: File containing RDF graph or dataset"
|
99
79
|
puts " --debug: Display detailed debug output"
|
100
80
|
puts " --execute,-e: Use option argument as the SPARQL input if no query-file given"
|
101
|
-
puts " --format: Output format for results"
|
81
|
+
puts " --format: Output format for results (json, xml, csv, tsv, html, sparql, sse, or another RDF format)"
|
102
82
|
puts " --port,-p Port on which to run server; defaults to 9292"
|
103
83
|
puts " --sse: Query input is in SSE format"
|
104
84
|
puts " --update: Process query as a SPARQL Update"
|
@@ -151,7 +131,7 @@ end
|
|
151
131
|
|
152
132
|
case cmd
|
153
133
|
when 'execute', 'parse'
|
154
|
-
options[:
|
134
|
+
options[:parse_only] = true if cmd == 'parse'
|
155
135
|
input ||= ARGV.empty? ? $stdin.read : RDF::Util::File.open_file(ARGV.first).read
|
156
136
|
run(input, **options)
|
157
137
|
when 'query'
|
data/lib/rack/sparql/conneg.rb
CHANGED
@@ -39,15 +39,36 @@ module Rack; module SPARQL
|
|
39
39
|
# If result is `RDF::Literal::Boolean`, `RDF::Query::Results`, or `RDF::Enumerable`
|
40
40
|
# The result is serialized using {SPARQL::Results}
|
41
41
|
#
|
42
|
-
# Inserts ordered content types into the environment as `ORDERED_CONTENT_TYPES` if an Accept header is present
|
42
|
+
# Inserts ordered content types into the environment as `ORDERED_CONTENT_TYPES` if an Accept header is present.
|
43
|
+
#
|
44
|
+
# Normalizes `application/x-www-form-urlencoded` to either `application/sparql-query` or `application/sparql-update` forms.
|
43
45
|
#
|
44
46
|
# @param [Hash{String => String}] env
|
45
47
|
# @return [Array(Integer, Hash, #each)]
|
46
48
|
# @see https://www.rubydoc.info/github/rack/rack/Rack/Runtime#call-instance_method
|
47
49
|
def call(env)
|
48
50
|
env['ORDERED_CONTENT_TYPES'] = parse_accept_header(env['HTTP_ACCEPT']) if env.has_key?('HTTP_ACCEPT')
|
51
|
+
# Normalize application/x-www-form-urlencoded to application/sparql-query or application/sparql-update
|
52
|
+
if env['REQUEST_METHOD'] == 'POST' && env.fetch('CONTENT_TYPE', 'application/x-www-form-urlencoded').to_s.start_with?('application/x-www-form-urlencoded')
|
53
|
+
content = env['rack.input'].read
|
54
|
+
params = Rack::Utils.parse_query(content)
|
55
|
+
if query = params.delete('query')
|
56
|
+
return [406, {"Content-Type" => "text/plain"}, ["Multiple query parameters"]] unless query.is_a?(String)
|
57
|
+
env['rack.input'] = StringIO.new(query)
|
58
|
+
env['CONTENT_TYPE'] = 'application/sparql-query'
|
59
|
+
env['QUERY_STRING'] = Rack::Utils.build_query(params)
|
60
|
+
elsif update = params.delete('update')
|
61
|
+
return [406, {"Content-Type" => "text/plain"}, ["Multiple update parameters"]] unless update.is_a?(String)
|
62
|
+
env['rack.input'] = StringIO.new(update)
|
63
|
+
env['CONTENT_TYPE'] = 'application/sparql-update'
|
64
|
+
env['QUERY_STRING'] = Rack::Utils.build_query(params)
|
65
|
+
else
|
66
|
+
env['rack.input'].rewind # never mind
|
67
|
+
end
|
68
|
+
end
|
49
69
|
response = app.call(env)
|
50
70
|
body = response[2].respond_to?(:body) ? response[2].body : response[2]
|
71
|
+
body = body.first if body.is_a?(Array) && body.length == 1 && body.first.is_a?(RDF::Literal::Boolean)
|
51
72
|
case body
|
52
73
|
when RDF::Enumerable, RDF::Query::Solutions, RDF::Literal::Boolean
|
53
74
|
response[2] = body # Put it back in the response, it might have been a proxy
|
@@ -11,7 +11,7 @@ class Sinatra::Response
|
|
11
11
|
|
12
12
|
# Rack::Response#finish sometimes returns self as response body. We don't want that.
|
13
13
|
status, headers, result = super
|
14
|
-
result = body if
|
14
|
+
result = body if self == result
|
15
15
|
[status, headers, result]
|
16
16
|
end
|
17
17
|
end
|
data/lib/sinatra/sparql.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'sinatra/base'
|
2
2
|
require 'sinatra/sparql/extensions'
|
3
3
|
require 'rack/sparql'
|
4
|
+
require 'rdf/aggregate_repo'
|
4
5
|
|
5
6
|
module Sinatra
|
6
7
|
##
|
@@ -13,6 +14,7 @@ module Sinatra
|
|
13
14
|
##
|
14
15
|
# Helper methods.
|
15
16
|
module Helpers
|
17
|
+
|
16
18
|
##
|
17
19
|
# This is useful when a GET request is performed against a SPARQL endpoint and no query is performed. Provide a set of datasets, including a default dataset along with optional triple count, dump location, and description of the dataset.
|
18
20
|
#
|
@@ -36,23 +38,36 @@ module Sinatra
|
|
36
38
|
|
37
39
|
node = RDF::Node.new
|
38
40
|
g << [node, RDF.type, sd.join("#Service")]
|
39
|
-
g << [node, sd.join("#endpoint"), options
|
41
|
+
g << [node, sd.join("#endpoint"), RDF::URI(url(options.fetch(:endpoint, "/sparql")))]
|
42
|
+
g << [node, sd.join("#supportedLanguage"), sd.join("#SPARQL10Query")]
|
40
43
|
g << [node, sd.join("#supportedLanguage"), sd.join("#SPARQL11Query")]
|
44
|
+
g << [node, sd.join("#supportedLanguage"), sd.join("#SPARQL11Update")]
|
45
|
+
g << [node, sd.join("#supportedLanguage"), RDF::URI('http://www.w3.org/ns/rdf-star#SPARQLStarQuery')]
|
46
|
+
g << [node, sd.join("#supportedLanguage"), RDF::URI('http://www.w3.org/ns/rdf-star#SPARQLStarUpdate')]
|
41
47
|
|
48
|
+
# Input formats
|
49
|
+
RDF::Reader.map(&:format).select(&:to_uri).each do |format|
|
50
|
+
g << [node, sd.join("#inputFormat"), format.to_uri]
|
51
|
+
end
|
52
|
+
|
42
53
|
# Result formats, both RDF and SPARQL Results.
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
54
|
+
%w(
|
55
|
+
http://www.w3.org/ns/formats/SPARQL_Results_XML
|
56
|
+
http://www.w3.org/ns/formats/SPARQL_Results_JSON
|
57
|
+
http://www.w3.org/ns/formats/SPARQL_Results_CSV
|
58
|
+
http://www.w3.org/ns/formats/SPARQL_Results_TSV
|
59
|
+
).each do |uri|
|
60
|
+
g << [node, sd.join("#resultFormat"), uri]
|
61
|
+
end
|
62
|
+
|
63
|
+
RDF::Writer.map(&:format).select(&:to_uri).each do |format|
|
64
|
+
g << [node, sd.join("#resultFormat"), format.to_uri]
|
65
|
+
end
|
66
|
+
|
53
67
|
# Features
|
54
68
|
g << [node, sd.join("#feature"), sd.join("#DereferencesURIs")]
|
55
|
-
|
69
|
+
#g << [node, sd.join("#feature"), sd.join("#BasicFederatedQuery")]
|
70
|
+
|
56
71
|
# Datasets
|
57
72
|
ds = RDF::Node.new
|
58
73
|
g << [node, sd.join("#defaultDataset"), ds]
|
@@ -86,6 +101,36 @@ module Sinatra
|
|
86
101
|
end
|
87
102
|
g
|
88
103
|
end
|
104
|
+
|
105
|
+
##
|
106
|
+
# This either creates a merge repo, or uses the standard repository for performing the query, based on the parameters passed (`default-graph-uri` and `named-graph-uri`).
|
107
|
+
# Loads from the datasource, unless a graph named by
|
108
|
+
# the datasource URI already exists in the repository.
|
109
|
+
#
|
110
|
+
# @return [RDF::Dataset]
|
111
|
+
# @see Algebra::Operator::Dataset
|
112
|
+
def dataset(**options)
|
113
|
+
logger = options.fetch(:logger, ::Logger.new(false))
|
114
|
+
repo = settings.repository
|
115
|
+
if %i(default-graph-uri named-graph-uri).any? {|k| options.key?(k)}
|
116
|
+
default_datasets = Array(options[:"default-graph-uri"]).map {|u| RDF::URI(u)}
|
117
|
+
named_datasets = Array(options[:"named-graph-uri"]).map {|u| RDF::URI(u)}
|
118
|
+
|
119
|
+
(default_datasets + named_datasets).each do |uri|
|
120
|
+
load_opts = {logger: logger, graph_name: uri, base_uri: uri}
|
121
|
+
unless repo.has_graph?(uri)
|
122
|
+
logger.debug(options) {"=> load #{uri}"}
|
123
|
+
repo.load(uri.to_s, **load_opts)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# Create an aggregate based on queryable having just the bits we want
|
128
|
+
aggregate = RDF::AggregateRepo.new(repo)
|
129
|
+
named_datasets.each {|name| aggregate.named(name) if repo.has_graph?(name)}
|
130
|
+
aggregate.default(*default_datasets.select {|name| repo.has_graph?(name)})
|
131
|
+
aggregate
|
132
|
+
end || settings.repository
|
133
|
+
end
|
89
134
|
end
|
90
135
|
|
91
136
|
##
|