annotate examples/browser/web/js/sparql.js @ 770:c54bc2ffbf92 tip

update tags
author convert-repo
date Fri, 16 Dec 2011 11:34:01 +0000
parents 901803e1305f
children
rev   line source
mas01mj@640 1 /**********************************************************
mas01mj@640 2 Copyright (c) 2006, 2007
mas01mj@640 3 Lee Feigenbaum ( lee AT thefigtrees DOT net )
mas01mj@640 4 Elias Torres ( elias AT torrez DOT us )
mas01mj@640 5 Wing Yung ( wingerz AT gmail DOT com )
mas01mj@640 6 All rights reserved.
mas01mj@640 7
mas01mj@640 8 Permission is hereby granted, free of charge, to any person obtaining a copy of
mas01mj@640 9 this software and associated documentation files (the "Software"), to deal in
mas01mj@640 10 the Software without restriction, including without limitation the rights to
mas01mj@640 11 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
mas01mj@640 12 of the Software, and to permit persons to whom the Software is furnished to do
mas01mj@640 13 so, subject to the following conditions:
mas01mj@640 14
mas01mj@640 15 The above copyright notice and this permission notice shall be included in all
mas01mj@640 16 copies or substantial portions of the Software.
mas01mj@640 17
mas01mj@640 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
mas01mj@640 19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
mas01mj@640 20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
mas01mj@640 21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
mas01mj@640 22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
mas01mj@640 23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
mas01mj@640 24 SOFTWARE.
mas01mj@640 25 **********************************************************/
mas01mj@640 26
mas01mj@640 27 /**
mas01mj@640 28 * Example client interactions
mas01mj@640 29 *
mas01mj@640 30
mas01mj@640 31 var sparqler = new SPARQL.Service("http://sparql.org/sparql");
mas01mj@640 32 sparqler.addDefaultGraph("http://thefigtrees.net/lee/ldf-card"); // inherited by all (future) queries
mas01mj@640 33 sparqler.addNamedGraph("http://torrez.us/elias/foaf.rdf");
mas01mj@640 34 sparqler.setPrefix("foaf", "http://xmlns.com/foaf/0.1/"); // inherited by all (future) queries
mas01mj@640 35 sparqler.setPrefix("rdf", "http://xmlns.com/foaf/0.1/");
mas01mj@640 36
mas01mj@640 37 sparqler.setRequestHeader("Authentication", "Basic: " + basicAuthString);
mas01mj@640 38
mas01mj@640 39 //sparqler.wantOutputAs("application/json"); // for now we only do JSON
mas01mj@640 40
mas01mj@640 41 var query = sparqler.createQuery();
mas01mj@640 42 query.addDefualtGraph(...) query.addNamedGraph(...) query.setPrefix(...) query.setRequestHeader(...) // this query only
mas01mj@640 43
mas01mj@640 44 // query forms:
mas01mj@640 45
mas01mj@640 46 // passes standard JSON results object to success callback
mas01mj@640 47 query.setPrefix("ldf", "http://thefigtrees.net/lee/ldf-card#");
mas01mj@640 48 query.query("SELECT ?who ?mbox WHERE { ldf:LDF foaf:knows ?who . ?who foaf:mbox ?mbox }",
mas01mj@640 49 {failure: onFailure, success: function(json) { for (var x in json.head.vars) { ... } ...}}
mas01mj@640 50 );
mas01mj@640 51
mas01mj@640 52 // passes boolean value to success callback
mas01mj@640 53 query.ask("ASK ?person WHERE { ?person foaf:knows [ foaf:name "Dan Connolly" ] }",
mas01mj@640 54 {failure: onFailure, success: function(bool) { if (bool) ... }}
mas01mj@640 55 );
mas01mj@640 56
mas01mj@640 57 // passes a single vector (array) of values representing a single column of results to success callback
mas01mj@640 58 query.setPrefix("ldf", "http://thefigtrees.net/lee/ldf-card#");
mas01mj@640 59 var addresses = query.selectValues("SELECT ?mbox WHERE { _:someone foaf:mbox ?mbox }",
mas01mj@640 60 {failure: onFailure, success: function(values) { for (var i = 0; i < values.length; i++) { ... values[i] ...} } }
mas01mj@640 61 );
mas01mj@640 62
mas01mj@640 63 // passes a single value representing a single row of a single column (variable) to success callback
mas01mj@640 64 query.setPrefix("ldf", "http://thefigtrees.net/lee/ldf-card#");
mas01mj@640 65 var myAddress = query.selectSingleValue("SELECT ?mbox WHERE {ldf:LDF foaf:mbox ?mbox }",
mas01mj@640 66 {failure: onFailure, success: function(value) { alert("value is: " + value); } }
mas01mj@640 67 );
mas01mj@640 68
mas01mj@640 69 // shortcuts for all of the above (w/o ability to set any query-specific graphs or prefixes)
mas01mj@640 70 sparqler.query(...) sparqler.ask(...) sparqler.selectValues(...) sparqler.selectSingleValue(...)
mas01mj@640 71
mas01mj@640 72
mas01mj@640 73 */
mas01mj@640 74
mas01mj@640 75 var SPARQL = {}; // SPARQL namespace
mas01mj@640 76
mas01mj@640 77
mas01mj@640 78 /**
mas01mj@640 79 * Both SPARQL service objects and SPARQL query objects receive one query utility method
mas01mj@640 80 * per entry in this dictionary. The key is the name of the method, and the value is a function
mas01mj@640 81 * that transforms the standard JSON output into a more useful form. The return value of a
mas01mj@640 82 * transformation function is passed into any 'success' callback function provided when the query
mas01mj@640 83 * is issued. The following transformations are included:
mas01mj@640 84 * + query -- identity transform; returns the JSON structure unchanged
mas01mj@640 85 * + ask -- for ASK queries; returns a boolean value indicating the answer to the query
mas01mj@640 86 * + selectValues -- for SELECT queries with a single variable; returns an array containing
mas01mj@640 87 * the answers to the query
mas01mj@640 88 * + selectSingleValue -- for SELECT queries returning one column with one row; returns the
mas01mj@640 89 * value in the first (and presumably, only) cell in the resultset
mas01mj@640 90 * + selectValueArrays -- for SELECT queries returning independent columns; returns a hash
mas01mj@640 91 * keyed on variable name with values as arrays of answers for that variable. Useful
mas01mj@640 92 * for UNION queries.
mas01mj@640 93 * Note that all of the transformations that return values directly lose any type information
mas01mj@640 94 * and the ability to distinguish between URIs, blank nodes, and literals.
mas01mj@640 95 */
mas01mj@640 96 SPARQL._query_transformations = {
mas01mj@640 97 query: function (o) { return o; },
mas01mj@640 98 ask: function (o) { return o["boolean"]; },
mas01mj@640 99 selectValues: function (o) {
mas01mj@640 100 var v = o.head.vars[0]; // assume one variable
mas01mj@640 101 var values = [];
mas01mj@640 102 for (var i = 0; i < o.results.bindings.length; i++)
mas01mj@640 103 values.push(o.results.bindings[i][v].value);
mas01mj@640 104 return values;
mas01mj@640 105 },
mas01mj@640 106 selectSingleValue: function(o) { return o.results.bindings[0][o.head.vars[0]].value; },
mas01mj@640 107 selectValueArrays: function(o) {
mas01mj@640 108 // factor by value (useful for UNION queries)
mas01mj@640 109 var ret = {};
mas01mj@640 110 for (var i = 0; i < o.head.vars.length; i++)
mas01mj@640 111 ret[o.head.vars[i]] = [];
mas01mj@640 112 for (var i = 0; i < o.results.bindings.length; i++)
mas01mj@640 113 for (var v in o.results.bindings[i])
mas01mj@640 114 if (ret[v] instanceof Array) ret[v].push(o.results.bindings[i][v].value);
mas01mj@640 115 return ret;
mas01mj@640 116 },
mas01mj@640 117 selectValueHashes: function(o) {
mas01mj@640 118 var hashes = [];
mas01mj@640 119 for (var i = 0; i < o.results.bindings.length; i++) {
mas01mj@640 120 var hash = {};
mas01mj@640 121 for (var v in o.results.bindings[i])
mas01mj@640 122 hash[v] = o.results.bindings[i][v].value;
mas01mj@640 123 hashes.push(hash);
mas01mj@640 124 }
mas01mj@640 125 return hashes;
mas01mj@640 126 }
mas01mj@640 127 };
mas01mj@640 128
mas01mj@640 129 SPARQL.statistics = {
mas01mj@640 130 queries_sent : 0,
mas01mj@640 131 successes : 0,
mas01mj@640 132 failures : 0
mas01mj@640 133 };
mas01mj@640 134
mas01mj@640 135 // A SPARQL service represents a single endpoint which implements the HTTP (GET or POST)
mas01mj@640 136 // bindings of the SPARQL Protocol. It provides convenience methods to set dataset and
mas01mj@640 137 // prefix options for all queries created for this endpoint.
mas01mj@640 138 SPARQL.Service = function(endpoint) {
mas01mj@640 139 //---------------
mas01mj@640 140 // private fields
mas01mj@640 141 var _endpoint = endpoint;
mas01mj@640 142 var _default_graphs = [];
mas01mj@640 143 var _named_graphs = [];
mas01mj@640 144 var _prefix_map = {};
mas01mj@640 145 var _method = 'POST';
mas01mj@640 146 var _output = 'json';
mas01mj@640 147 var _max_simultaneous = 0;
mas01mj@640 148 var _request_headers = {};
mas01mj@640 149
mas01mj@640 150 //----------
mas01mj@640 151 // accessors
mas01mj@640 152 this.endpoint = function() { return _endpoint; };
mas01mj@640 153 this.defaultGraphs = function() { return _default_graphs; };
mas01mj@640 154 this.namedGraphs = function() { return _named_graphs; };
mas01mj@640 155 this.prefixes = function() { return _prefix_map; };
mas01mj@640 156 this.method = function() { return _method; };
mas01mj@640 157 this.output = function() { return _output; };
mas01mj@640 158 this.maxSimultaneousQueries = function() { return _max_simultaneous; };
mas01mj@640 159 this.requestHeaders = function() { return _request_headers; };
mas01mj@640 160
mas01mj@640 161 //---------
mas01mj@640 162 // mutators
mas01mj@640 163 function _add_graphs(toAdd, arr) {
mas01mj@640 164 if (toAdd instanceof Array)
mas01mj@640 165 for (var i = 0; i < toAdd.length; i++) arr.push(toAdd[i]);
mas01mj@640 166 else
mas01mj@640 167 arr.push(toAdd);
mas01mj@640 168 }
mas01mj@640 169 this.addDefaultGraph = function(g) { _add_graphs(g, this.defaultGraphs()); };
mas01mj@640 170 this.addNamedGraph = function(g) { _add_graphs(g, this.namedGraphs()); };
mas01mj@640 171 this.setPrefix = function(p, u) { this.prefixes()[p] = u; };
mas01mj@640 172 this.createQuery = function(p) { return new SPARQL.Query(this, p); };
mas01mj@640 173 this.setMethod = function(m) {
mas01mj@640 174 if (m != 'GET' && m != 'POST') throw("HTTP methods other than GET and POST are not supported.");
mas01mj@640 175 _method = m;
mas01mj@640 176 };
mas01mj@640 177 this.setOutput = function(o) { _output = o; };
mas01mj@640 178 this.setMaxSimultaneousQueries = function(m) { _max_simultaneous = m; };
mas01mj@640 179 this.setRequestHeader = function(h, v) { _request_headers[h] = v; };
mas01mj@640 180
mas01mj@640 181 //---------------
mas01mj@640 182 // protected methods (should only be called within this module
mas01mj@640 183 this._active_queries = 0;
mas01mj@640 184 this._queued_queries = [];
mas01mj@640 185 this._next_in_queue = 0;
mas01mj@640 186 this._canRun = function() { return this.maxSimultaneousQueries() <= 0 || this._active_queries < this.maxSimultaneousQueries();};
mas01mj@640 187 this._queue = function(q,f, p) {
mas01mj@640 188 if (!p) p = 0;
mas01mj@640 189 if (p > 0) {
mas01mj@640 190 for (var i = 0; i < this._queued_queries.length; i++) {
mas01mj@640 191 if (this._queued_queries[i] != null && this._queued_queries[i][2] < p) {
mas01mj@640 192 this._queued_queries.splice(i, 0, [q, f, p]);
mas01mj@640 193 return;
mas01mj@640 194 }
mas01mj@640 195 }
mas01mj@640 196 }
mas01mj@640 197 this._queued_queries.push([q,f,p]);
mas01mj@640 198 };
mas01mj@640 199 this._markRunning = function(q) { this._active_queries++; };
mas01mj@640 200 this._markDone = function(q) {
mas01mj@640 201 this._active_queries--;
mas01mj@640 202 //document.getElementById('log').innerHTML+="query done. " + this._active_queries + " queries still active.<br>";
mas01mj@640 203 if (this._queued_queries[this._next_in_queue] != null && this._canRun()) {
mas01mj@640 204 var a = this._queued_queries[this._next_in_queue];
mas01mj@640 205 this._queued_queries[this._next_in_queue++] = null;
mas01mj@640 206 // a[0] is query object, a[1] is function to run query
mas01mj@640 207 //document.getElementById('log').innerHTML += "running query from Q<br>";
mas01mj@640 208 a[1]();
mas01mj@640 209 }
mas01mj@640 210 };
mas01mj@640 211
mas01mj@640 212 //---------------
mas01mj@640 213 // public methods
mas01mj@640 214
mas01mj@640 215 // use our varied transformations to create the various shortcut methods of actually
mas01mj@640 216 // issuing queries without explicitly creating a query object
mas01mj@640 217 for (var query_form in SPARQL._query_transformations) {
mas01mj@640 218 // need the extra function to properly scope query_form (qf)
mas01mj@640 219 this[query_form] = (function(qf) {
mas01mj@640 220 return function(queryString, callback) {
mas01mj@640 221 var q = this.createQuery();
mas01mj@640 222 q._doQuery(queryString, callback, SPARQL._query_transformations[qf]);
mas01mj@640 223 };
mas01mj@640 224 })(query_form);
mas01mj@640 225 }
mas01mj@640 226
mas01mj@640 227 //------------
mas01mj@640 228 // constructor
mas01mj@640 229
mas01mj@640 230 if (!_endpoint)
mas01mj@640 231 return null;
mas01mj@640 232
mas01mj@640 233 return this;
mas01mj@640 234 }
mas01mj@640 235
mas01mj@640 236 /**
mas01mj@640 237 * A SPARQL query object should be created using the createQuery method of a SPARQL
mas01mj@640 238 * service object. It allows prefixes and datasets to be defined specifically for
mas01mj@640 239 * a single query, and provides introspective methods to see the query string and the
mas01mj@640 240 * full (HTTP GET) URL of the query.
mas01mj@640 241 */
mas01mj@640 242 SPARQL.Query = function(service, priority) {
mas01mj@640 243 //---------------
mas01mj@640 244 // private fields
mas01mj@640 245 var _conn = null;
mas01mj@640 246 var _service = service;
mas01mj@640 247 var _default_graphs = clone_obj(service.defaultGraphs()); // prevent future updates from affecting us
mas01mj@640 248 var _named_graphs = clone_obj(service.namedGraphs());
mas01mj@640 249 var _prefix_map = clone_obj(service.prefixes());
mas01mj@640 250 var _user_query = ''; // doesn't include auto-generated prefix declarations
mas01mj@640 251 var _method = service.method();
mas01mj@640 252 var _output = service.output();
mas01mj@640 253 var _priority = priority || 0;
mas01mj@640 254 var _request_headers = clone_obj(service.requestHeaders());
mas01mj@640 255
mas01mj@640 256 //------------------
mas01mj@640 257 // private functions
mas01mj@640 258 function _create_json(text) {
mas01mj@640 259 if (!text)
mas01mj@640 260 return null;
mas01mj@640 261 // make sure this is safe JSON
mas01mj@640 262 // see: http://www.ietf.org/internet-drafts/draft-crockford-jsonorg-json-03.txt
mas01mj@640 263
mas01mj@640 264 // (1) strip out quoted strings
mas01mj@640 265 var no_strings = text.replace(/"(\\.|[^"\\])*"/g, '');
mas01mj@640 266 // (2) make sure that all the characters are explicitly part of the JSON grammar
mas01mj@640 267 // (in particular, note as discussed in the IETF submission, there are no assignments
mas01mj@640 268 // or function invocations allowed by this reg. exp.)
mas01mj@640 269 var hasBadCharacter = /[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(no_strings);
mas01mj@640 270 // (3) evaluate the JSON string, returning its contents
mas01mj@640 271 if (!hasBadCharacter) {
mas01mj@640 272 try {
mas01mj@640 273 return eval('(' + text + ')');
mas01mj@640 274 } catch (e) {
mas01mj@640 275 return null;
mas01mj@640 276 }
mas01mj@640 277 }
mas01mj@640 278 return null;
mas01mj@640 279 }
mas01mj@640 280
mas01mj@640 281 function clone_obj(o) {
mas01mj@640 282 var o2 = o instanceof Array ? [] : {};
mas01mj@640 283 for(var x in o) {o2[x] = o[x];}
mas01mj@640 284 return o2;
mas01mj@640 285 }
mas01mj@640 286
mas01mj@640 287 //----------------
mas01mj@640 288 // private methods
mas01mj@640 289 this._doCallback = function(cb, which, arg) {
mas01mj@640 290 //document.getElementById('log').innerHTML += "_doCallback ... <br>";
mas01mj@640 291 var user_data = "argument" in cb ? cb.argument : null;
mas01mj@640 292 if (which in cb) {
mas01mj@640 293 if (cb.scope) {
mas01mj@640 294 cb[which].apply(cb.scope, [arg, user_data]);
mas01mj@640 295 } else {
mas01mj@640 296 cb[which](arg, user_data);
mas01mj@640 297 }
mas01mj@640 298 }
mas01mj@640 299 }
mas01mj@640 300
mas01mj@640 301 this._queryFailure = function(xhr, arg) {
mas01mj@640 302 SPARQL.statistics.failures++;
mas01mj@640 303 _service._markDone(this);
mas01mj@640 304 this._doCallback(arg.callback, 'failure', xhr /* just pass through the connection response object */);
mas01mj@640 305 };
mas01mj@640 306 this._querySuccess = function(xhr, arg) {
mas01mj@640 307 //alert(xhr.responseText);
mas01mj@640 308 SPARQL.statistics.successes++;
mas01mj@640 309 _service._markDone(this);
mas01mj@640 310 this._doCallback(arg.callback, 'success', arg.transformer(
mas01mj@640 311 _output == 'json' ? _create_json(xhr.responseText) : xhr.responseText
mas01mj@640 312 ));
mas01mj@640 313 };
mas01mj@640 314
mas01mj@640 315 function getXmlHttpRequest(url) {
mas01mj@640 316 // right now, this only does Firefox (Opera? Safari?)
mas01mj@640 317 return new XMLHttpRequest();
mas01mj@640 318 }
mas01mj@640 319
mas01mj@640 320 this._doQuery = function(queryString, callback, transformer) {
mas01mj@640 321 _user_query = queryString;
mas01mj@640 322 if (_service._canRun()) {
mas01mj@640 323 try {
mas01mj@640 324 if (_method != 'POST' && _method != 'GET')
mas01mj@640 325 throw("HTTP methods other than GET and POST are not supported.");
mas01mj@640 326
mas01mj@640 327 var url = _method == 'GET' ? this.queryUrl() : this.service().endpoint();
mas01mj@640 328 var xhr = getXmlHttpRequest(url);
mas01mj@640 329 var content = null;
mas01mj@640 330
mas01mj@640 331 try {
mas01mj@640 332 if (!document.domain || (url.match(/^https?:\/\//) && url.slice(7, document.domain.length + 7) != document.domain && window.netscape && netscape.security && netscape.security.PrivilegeManager)) {
mas01mj@640 333 netscape.security.PrivilegeManager.enablePrivilege( "UniversalBrowserRead");
mas01mj@640 334 netscape.security.PrivilegeManager.enablePrivilege( "UniversalXPConnect");
mas01mj@640 335 }
mas01mj@640 336 } catch(e) {
mas01mj@640 337 alert("Cross-site requests prohibited. You will only be able to SPARQL the origin site: " + e);
mas01mj@640 338 return;
mas01mj@640 339 }
mas01mj@640 340
mas01mj@640 341 xhr.open(_method, url, true /* async */);
mas01mj@640 342
mas01mj@640 343 // set the headers, including the content-type for POSTed queries
mas01mj@640 344 for (var header in this.requestHeaders())
mas01mj@640 345 if (typeof(this.requestHeaders()[header]) != "function")
mas01mj@640 346 xhr.setRequestHeader(header, this.requestHeaders()[header]);
mas01mj@640 347 if (_method == 'POST') {
mas01mj@640 348 xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
mas01mj@640 349 content = this.queryParameters();
mas01mj@640 350 }
mas01mj@640 351
mas01mj@640 352 SPARQL.statistics.queries_sent++;
mas01mj@640 353 _service._markRunning(this);
mas01mj@640 354
mas01mj@640 355 var callbackData = {
mas01mj@640 356 scope:this,
mas01mj@640 357 success: this._querySuccess,
mas01mj@640 358 failure: this._queryFailure,
mas01mj@640 359 argument: {
mas01mj@640 360 transformer: transformer,
mas01mj@640 361 callback: callback
mas01mj@640 362 }
mas01mj@640 363 };
mas01mj@640 364
mas01mj@640 365 // I've seen some strange race-condition behavior (strange since normally
mas01mj@640 366 // JS is single-threaded, so synchronization conditions don't occur barring
mas01mj@640 367 // reentrancy) with onreadystatechange. Instead, we poll asynchronously to
mas01mj@640 368 // determine when the request is done.
mas01mj@640 369 var token = window.setInterval(
mas01mj@640 370 function () {
mas01mj@640 371 if (xhr.readyState == 4) { // ready!
mas01mj@640 372 // clear this handler
mas01mj@640 373 window.clearInterval(token);
mas01mj@640 374 // we check the status to know which callback to call
mas01mj@640 375 if (xhr.status >= 200 && xhr.status < 300)
mas01mj@640 376 callbackData.success.apply(callbackData.scope, [xhr, callbackData.argument]);
mas01mj@640 377 else
mas01mj@640 378 callbackData.failure.apply(callbackData.scope, [xhr, callbackData.argument]);
mas01mj@640 379 }
mas01mj@640 380 },
mas01mj@640 381 200 /* maybe this should be customizable */
mas01mj@640 382 );
mas01mj@640 383
mas01mj@640 384 xhr.send(content);
mas01mj@640 385 } catch (e) {
mas01mj@640 386 alert("Error sending SPARQL query: " + e);
mas01mj@640 387 }
mas01mj@640 388 } else {
mas01mj@640 389 var self = this;
mas01mj@640 390 _service._queue(self, function() { self._doQuery(queryString, callback, transformer); }, _priority);
mas01mj@640 391 }
mas01mj@640 392 };
mas01mj@640 393
mas01mj@640 394
mas01mj@640 395 //----------
mas01mj@640 396 // accessors
mas01mj@640 397 this.request = function() { return _conn; };
mas01mj@640 398 this.service = function() { return _service; };
mas01mj@640 399 this.defaultGraphs = function() { return _default_graphs; };
mas01mj@640 400 this.namedGraphs = function() { return _named_graphs; };
mas01mj@640 401 this.prefixes = function() { return _prefix_map; };
mas01mj@640 402 this.method = function() { return _method; };
mas01mj@640 403 this.requestHeaders = function() { return _request_headers; };
mas01mj@640 404
mas01mj@640 405
mas01mj@640 406 /**
mas01mj@640 407 * Returns the SPARQL query represented by this object. The parameter, which can
mas01mj@640 408 * be omitted, determines whether or not auto-generated PREFIX clauses are included
mas01mj@640 409 * in the returned query string.
mas01mj@640 410 */
mas01mj@640 411 this.queryString = function(excludePrefixes) {
mas01mj@640 412 var preamble = '';
mas01mj@640 413 if (!excludePrefixes) {
mas01mj@640 414 for (var prefix in this.prefixes()) {
mas01mj@640 415 if(typeof(this.prefixes()[prefix]) != 'string') continue;
mas01mj@640 416 preamble += 'PREFIX ' + prefix + ': <' + this.prefixes()[prefix] + '> ';
mas01mj@640 417 }
mas01mj@640 418 }
mas01mj@640 419 return preamble + _user_query;
mas01mj@640 420 };
mas01mj@640 421
mas01mj@640 422 /**
mas01mj@640 423 * Returns the HTTP query parameters to invoke this query. This includes entries for
mas01mj@640 424 * all of the default graphs, the named graphs, the SPARQL query itself, and an
mas01mj@640 425 * output parameter to specify JSON (or other) output is desired.
mas01mj@640 426 */
mas01mj@640 427 this.queryParameters = function () {
mas01mj@640 428 var urlQueryString = '';
mas01mj@640 429 var i;
mas01mj@640 430
mas01mj@640 431 // add default and named graphs to the protocol invocation
mas01mj@640 432 for (i = 0; i < this.defaultGraphs().length; i++) urlQueryString += 'default-graph-uri=' + encodeURIComponent(this.defaultGraphs()[i]) + '&';
mas01mj@640 433 for (i = 0; i < this.namedGraphs().length; i++) urlQueryString += 'named-graph-uri=' + encodeURIComponent(this.namedGraphs()[i]) + '&';
mas01mj@640 434
mas01mj@640 435 // specify JSON output (currently output= supported by latest Joseki) (or other output)
mas01mj@640 436 urlQueryString += 'output=' + _output + '&soft-limit=-1&';
mas01mj@640 437 return urlQueryString + 'query=' + encodeURIComponent(this.queryString());
mas01mj@640 438 }
mas01mj@640 439
mas01mj@640 440 /**
mas01mj@640 441 * Returns the HTTP GET URL to invoke this query. (Note that this returns a full HTTP GET URL
mas01mj@640 442 * even if this query is set to actually use POST.)
mas01mj@640 443 */
mas01mj@640 444 this.queryUrl = function() {
mas01mj@640 445 var url = this.service().endpoint() + '?';
mas01mj@640 446 return url + this.queryParameters();
mas01mj@640 447 };
mas01mj@640 448
mas01mj@640 449 //---------
mas01mj@640 450 // mutators
mas01mj@640 451 function _add_graphs(toAdd, arr) {
mas01mj@640 452 if (toAdd instanceof Array)
mas01mj@640 453 for (var i = 0; i < toAdd.length; i++) arr.push(toAdd[i]);
mas01mj@640 454 else
mas01mj@640 455 arr.push(toAdd);
mas01mj@640 456 }
mas01mj@640 457 this.addDefaultGraph = function(g) { _add_graphs(g, this.defaultGraphs()); };
mas01mj@640 458 this.addNamedGraph = function(g) { _add_graphs(g, this.namedGraphs()); };
mas01mj@640 459 this.setPrefix = function(p, u) { this.prefixes()[p] = u; };
mas01mj@640 460 this.setMethod = function(m) {
mas01mj@640 461 if (m != 'GET' && m != 'POST') throw("HTTP methods other than GET and POST are not supported.");
mas01mj@640 462 _method = m;
mas01mj@640 463 };
mas01mj@640 464 this.setRequestHeader = function(h, v) { _request_headers[h] = v; };
mas01mj@640 465
mas01mj@640 466 //---------------
mas01mj@640 467 // public methods
mas01mj@640 468
mas01mj@640 469 // use our varied transformations to create the various methods of actually issuing
mas01mj@640 470 // queries
mas01mj@640 471 for (var query_form in SPARQL._query_transformations) {
mas01mj@640 472 // need the extra function to properly scope query_form (qf)
mas01mj@640 473 this[query_form] = (function(qf) {
mas01mj@640 474 return function(queryString, callback) {
mas01mj@640 475 this._doQuery(queryString, callback, SPARQL._query_transformations[qf]);
mas01mj@640 476 };
mas01mj@640 477 })(query_form);
mas01mj@640 478 }
mas01mj@640 479
mas01mj@640 480
mas01mj@640 481 //------------
mas01mj@640 482 // constructor
mas01mj@640 483
mas01mj@640 484 return this;
mas01mj@640 485 }
mas01mj@640 486
mas01mj@640 487 // Nothing to see here, yet.
mas01mj@640 488 SPARQL.QueryUtilities = {
mas01mj@640 489 };
mas01mj@640 490