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 returned for SPARQL SELECT and ASK query responses.
42 * @copyright Copyright (c) 2009-2013 Nicholas J Humfrey
43 * @license http://www.opensource.org/licenses/bsd-license.php
45 class EasyRdf_Sparql_Result extends ArrayIterator
48 private $boolean = null;
50 private $ordered = null;
51 private $distinct = null;
52 private $fields = array();
54 /** A constant for the SPARQL Query Results XML Format namespace */
55 const SPARQL_XML_RESULTS_NS = 'http://www.w3.org/2005/sparql-results#';
57 /** Create a new SPARQL Result object
59 * You should not normally need to create a SPARQL result
60 * object directly - it will be constructed automatically
61 * for you by EasyRdf_Sparql_Client.
63 * @param string $data The SPARQL result body
64 * @param string $mimeType The MIME type of the result
66 public function __construct($data, $mimeType)
68 if ($mimeType == 'application/sparql-results+xml') {
69 return $this->parseXml($data);
70 } elseif ($mimeType == 'application/sparql-results+json') {
71 return $this->parseJson($data);
73 throw new EasyRdf_Exception(
74 "Unsupported SPARQL Query Results format: $mimeType"
79 /** Get the query result type (boolean/bindings)
81 * ASK queries return a result of type 'boolean'.
82 * SELECT query return a result of type 'bindings'.
84 * @return string The query result type.
86 public function getType()
91 /** Return the boolean value of the query result
93 * If the query was of type boolean then this method will
94 * return either true or false. If the query was of some other
95 * type then this method will return null.
97 * @return boolean The result of the query.
99 public function getBoolean()
101 return $this->boolean;
104 /** Return true if the result of the query was true.
106 * @return boolean True if the query result was true.
108 public function isTrue()
110 return $this->boolean == true;
113 /** Return false if the result of the query was false.
115 * @return boolean True if the query result was false.
117 public function isFalse()
119 return $this->boolean == false;
122 /** Return the number of fields in a query result of type bindings.
124 * @return integer The number of fields.
126 public function numFields()
128 return count($this->fields);
131 /** Return the number of rows in a query result of type bindings.
133 * @return integer The number of rows.
135 public function numRows()
140 /** Get the field names in a query result of type bindings.
142 * @return array The names of the fields in the result.
144 public function getFields()
146 return $this->fields;
149 /** Return a human readable view of the query result.
151 * This method is intended to be a debugging aid and will
152 * return a pretty-print view of the query result.
154 * @param string $format Either 'text' or 'html'
156 public function dump($format = 'html')
158 if ($this->type == 'bindings') {
160 if ($format == 'html') {
161 $result .= "<table class='sparql-results' style='border-collapse:collapse'>";
163 foreach ($this->fields as $field) {
164 $result .= "<th style='border:solid 1px #000;padding:4px;".
165 "vertical-align:top;background-color:#eee;'>".
169 foreach ($this as $row) {
171 foreach ($this->fields as $field) {
172 if (isset($row->$field)) {
173 $result .= "<td style='border:solid 1px #000;padding:4px;".
174 "vertical-align:top'>".
175 $row->$field->dumpValue($format)."</td>";
177 $result .= "<td> </td>";
182 $result .= "</table>";
184 // First calculate the width of each comment
185 $colWidths = array();
186 foreach ($this->fields as $field) {
187 $colWidths[$field] = strlen($field);
191 foreach ($this as $row) {
193 foreach ($row as $k => $v) {
194 $textRow[$k] = $v->dumpValue('text');
195 $width = strlen($textRow[$k]);
196 if ($colWidths[$k] < $width) {
197 $colWidths[$k] = $width;
200 $textData[] = $textRow;
203 // Create a horizontal rule
205 foreach ($colWidths as $k => $v) {
206 $hr .= "-".str_repeat('-', $v).'-+';
209 // Output the field names
211 foreach ($this->fields as $field) {
212 $result .= ' '.str_pad("?$field", $colWidths[$field]).' |';
215 // Output each of the rows
216 $result .= "\n$hr\n";
217 foreach ($textData as $textRow) {
219 foreach ($textRow as $k => $v) {
220 $result .= ' '.str_pad($v, $colWidths[$k]).' |';
228 } elseif ($this->type == 'boolean') {
229 $str = ($this->boolean ? 'true' : 'false');
230 if ($format == 'html') {
231 return "<p>Result: <span style='font-weight:bold'>$str</span></p>";
233 return "Result: $str";
236 throw new EasyRdf_Exception(
237 "Failed to dump SPARQL Query Results format, unknown type: ". $this->type
242 /** Create a new EasyRdf_Resource or EasyRdf_Literal depending
243 * on the type of data passed in.
247 protected function newTerm($data)
249 switch($data['type']) {
251 return new EasyRdf_Resource('_:'.$data['value']);
253 return new EasyRdf_Resource($data['value']);
255 case 'typed-literal':
256 return EasyRdf_Literal::create($data);
258 throw new EasyRdf_Exception(
259 "Failed to parse SPARQL Query Results format, unknown term type: ".
265 /** Parse a SPARQL result in the XML format into the object.
269 protected function parseXml($data)
271 $doc = new DOMDocument();
272 $doc->loadXML($data);
274 # Check for valid root node.
275 if ($doc->hasChildNodes() == false or
276 $doc->childNodes->length != 1 or
277 $doc->firstChild->nodeName != 'sparql' or
278 $doc->firstChild->namespaceURI != self::SPARQL_XML_RESULTS_NS) {
279 throw new EasyRdf_Exception(
280 "Incorrect root node in SPARQL XML Query Results format"
284 # Is it the result of an ASK query?
285 $boolean = $doc->getElementsByTagName('boolean');
286 if ($boolean->length) {
287 $this->type = 'boolean';
288 $value = $boolean->item(0)->nodeValue;
289 $this->boolean = $value == 'true' ? true : false;
293 # Get a list of variables from the header
294 $head = $doc->getElementsByTagName('head');
296 $variables = $head->item(0)->getElementsByTagName('variable');
297 foreach ($variables as $variable) {
298 $this->fields[] = $variable->getAttribute('name');
302 # Is it the result of a SELECT query?
303 $resultstag = $doc->getElementsByTagName('results');
304 if ($resultstag->length) {
305 $this->type = 'bindings';
306 $results = $resultstag->item(0)->getElementsByTagName('result');
307 foreach ($results as $result) {
308 $bindings = $result->getElementsByTagName('binding');
310 foreach ($bindings as $binding) {
311 $key = $binding->getAttribute('name');
312 foreach ($binding->childNodes as $node) {
313 if ($node->nodeType != XML_ELEMENT_NODE) {
316 $t->$key = $this->newTerm(
318 'type' => $node->nodeName,
319 'value' => $node->nodeValue,
320 'lang' => $node->getAttribute('xml:lang'),
321 'datatype' => $node->getAttribute('datatype')
332 throw new EasyRdf_Exception(
333 "Failed to parse SPARQL XML Query Results format"
337 /** Parse a SPARQL result in the JSON format into the object.
341 protected function parseJson($data)
343 // Decode JSON to an array
344 $data = json_decode($data, true);
346 if (isset($data['boolean'])) {
347 $this->type = 'boolean';
348 $this->boolean = $data['boolean'];
349 } elseif (isset($data['results'])) {
350 $this->type = 'bindings';
351 if (isset($data['head']['vars'])) {
352 $this->fields = $data['head']['vars'];
355 foreach ($data['results']['bindings'] as $row) {
357 foreach ($row as $key => $value) {
358 $t->$key = $this->newTerm($value);
363 throw new EasyRdf_Exception(
364 "Failed to parse SPARQL JSON Query Results format"
369 /** Magic method to return value of the result to string
371 * If this is a boolean result then it will return 'true' or 'false'.
372 * If it is a bindings type, then it will dump as a text based table.
374 * @return string A string representation of the result.
376 public function __toString()
378 if ($this->type == 'boolean') {
379 return $this->boolean ? 'true' : 'false';
381 return $this->dump('text');