8 * Copyright (c) 2009-2013 Nicholas J Humfrey. All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
18 * promote products derived from this software without specific prior
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
34 * @copyright Copyright (c) 2009-2013 Nicholas J Humfrey
35 * @license http://www.opensource.org/licenses/bsd-license.php
39 * Class for making SPARQL queries using the SPARQL 1.1 Protocol
42 * @copyright Copyright (c) 2009-2013 Nicholas J Humfrey
43 * @license http://www.opensource.org/licenses/bsd-license.php
45 class EasyRdf_Sparql_Client
47 /** The query/read address of the SPARQL Endpoint */
48 private $queryUri = null;
50 private $queryUri_has_params = false;
52 /** The update/write address of the SPARQL Endpoint */
53 private $updateUri = null;
55 /** Create a new SPARQL endpoint client
57 * If the query and update endpoints are the same, then you
58 * only need to give a single URI.
60 * @param string $queryUri The address of the SPARQL Query Endpoint
61 * @param string $updateUri Optional address of the SPARQL Update Endpoint
63 public function __construct($queryUri, $updateUri = null)
65 $this->queryUri = $queryUri;
67 if (strlen(parse_url($queryUri, PHP_URL_QUERY)) > 0) {
68 $this->queryUri_has_params = true;
70 $this->queryUri_has_params = false;
74 $this->updateUri = $updateUri;
76 $this->updateUri = $queryUri;
80 /** Get the URI of the SPARQL query endpoint
82 * @return string The query URI of the SPARQL endpoint
84 public function getQueryUri()
86 return $this->queryUri;
89 /** Get the URI of the SPARQL update endpoint
91 * @return string The query URI of the SPARQL endpoint
93 public function getUpdateUri()
95 return $this->updateUri;
102 public function getUri()
104 return $this->queryUri;
107 /** Make a query to the SPARQL endpoint
109 * SELECT and ASK queries will return an object of type
110 * EasyRdf_Sparql_Result.
112 * CONSTRUCT and DESCRIBE queries will return an object
113 * of type EasyRdf_Graph.
115 * @param string $query The query string to be executed
116 * @return object EasyRdf_Sparql_Result|EasyRdf_Graph Result of the query.
118 public function query($query)
120 return $this->request('query', $query);
123 /** Count the number of triples in a SPARQL 1.1 endpoint
125 * Performs a SELECT query to estriblish the total number of triples.
127 * Counts total number of triples by default but a conditional triple pattern
128 * can be given to count of a subset of all triples.
130 * @param string $condition Triple-pattern condition for the count query
131 * @return integer The number of triples
133 public function countTriples($condition = '?s ?p ?o')
135 // SELECT (COUNT(*) AS ?count)
139 // {GRAPH ?g {?s ?p ?o}}
141 $result = $this->query('SELECT (COUNT(*) AS ?count) {'.$condition.'}');
142 return $result[0]->count->getValue();
145 /** Get a list of named graphs from a SPARQL 1.1 endpoint
147 * Performs a SELECT query to get a list of the named graphs
149 * @param string $limit Optional limit to the number of results
150 * @return array Array of EasyRdf_Resource objects for each named graph
152 public function listNamedGraphs($limit = null)
154 $query = "SELECT DISTINCT ?g WHERE {GRAPH ?g {?s ?p ?o}}";
155 if (!is_null($limit)) {
156 $query .= " LIMIT ".(int)$limit;
158 $result = $this->query($query);
160 // Convert the result object into an array of resources
162 foreach ($result as $row) {
163 array_push($graphs, $row->g);
168 /** Make an update request to the SPARQL endpoint
170 * Successful responses will return the HTTP response object
172 * Unsuccessful responses will throw an exception
174 * @param string $query The update query string to be executed
175 * @return object EasyRdf_Http_Response HTTP response
177 public function update($query)
179 return $this->request('update', $query);
182 public function insert($data, $graphUri = null)
184 #$this->updateData('INSET',
185 $query = 'INSERT DATA {';
187 $query .= "GRAPH <$graphUri> {";
189 $query .= $this->convertToTriples($data);
194 return $this->update($query);
197 protected function updateData($operation, $data, $graphUri = null)
199 $query = "$operation DATA {";
201 $query .= "GRAPH <$graphUri> {";
203 $query .= $this->convertToTriples($data);
208 return $this->update($query);
211 public function clear($graphUri, $silent = false)
217 if (preg_match('/^all|named|default$/i', $graphUri)) {
218 $query .= " $graphUri";
220 $query .= " GRAPH <$graphUri>";
222 return $this->update($query);
226 * Internal function to make an HTTP request to SPARQL endpoint
230 protected function request($type, $query)
232 // Check for undefined prefixes
234 foreach (EasyRdf_Namespace::namespaces() as $prefix => $uri) {
235 if (strpos($query, "$prefix:") !== false and
236 strpos($query, "PREFIX $prefix:") === false) {
237 $prefixes .= "PREFIX $prefix: <$uri>\n";
241 $client = EasyRdf_Http::getDefaultHttpClient();
242 $client->resetParameters();
244 // Tell the server which response formats we can parse
245 $accept = EasyRdf_Format::getHttpAcceptHeader(
247 'application/sparql-results+json' => 1.0,
248 'application/sparql-results+xml' => 0.8
251 $client->setHeaders('Accept', $accept);
253 if ($type == 'update') {
254 $client->setMethod('POST');
255 $client->setUri($this->updateUri);
256 $client->setRawData($prefixes . $query);
257 $client->setHeaders('Content-Type', 'application/sparql-update');
258 } elseif ($type == 'query') {
259 // Use GET if the query is less than 2kB
260 // 2046 = 2kB minus 1 for '?' and 1 for NULL-terminated string on server
261 $encodedQuery = 'query='.urlencode($prefixes . $query);
262 if (strlen($encodedQuery) + strlen($this->queryUri) <= 2046) {
263 $delimiter = $this->queryUri_has_params ? '&' : '?';
265 $client->setMethod('GET');
266 $client->setUri($this->queryUri.$delimiter.$encodedQuery);
268 // Fall back to POST instead (which is un-cacheable)
269 $client->setMethod('POST');
270 $client->setUri($this->queryUri);
271 $client->setRawData($encodedQuery);
272 $client->setHeaders('Content-Type', 'application/x-www-form-urlencoded');
276 $response = $client->request();
277 if ($response->getStatus() == 204) {
280 } elseif ($response->isSuccessful()) {
281 list($type, $params) = EasyRdf_Utils::parseMimeType(
282 $response->getHeader('Content-Type')
284 if (strpos($type, 'application/sparql-results') === 0) {
285 return new EasyRdf_Sparql_Result($response->getBody(), $type);
287 return new EasyRdf_Graph($this->queryUri, $response->getBody(), $type);
290 throw new EasyRdf_Exception(
291 "HTTP request for SPARQL query failed: ".$response->getBody()
296 protected function convertToTriples($data)
298 if (is_string($data)) {
300 } elseif (is_object($data) and $data instanceof EasyRdf_Graph) {
301 # FIXME: insert Turtle when there is a way of seperateing out the prefixes
302 return $data->serialise('ntriples');
304 throw new EasyRdf_Exception(
305 "Don't know how to convert to triples for SPARQL query: ".$response->getBody()