1 /*
  2  * jQuery RDF @VERSION
  3  *
  4  * Copyright (c) 2008,2009 Jeni Tennison
  5  * Licensed under the MIT (MIT-LICENSE.txt)
  6  *
  7  * Depends:
  8  *  jquery.uri.js
  9  *  jquery.xmlns.js
 10  *  jquery.datatype.js
 11  *  jquery.curie.js
 12  *  jquery.json.js
 13  */
 14 /**
 15  * @fileOverview jQuery RDF
 16  * @author <a href="mailto:jeni@jenitennison.com">Jeni Tennison</a>
 17  * @copyright (c) 2008,2009 Jeni Tennison
 18  * @license MIT license (MIT-LICENSE.txt)
 19  * @version 1.0
 20  */
 21 /**
 22  * @exports $ as jQuery
 23  */
 24 /**
 25  * @ignore
 26  */
 27 (function ($) {
 28   var
 29     memResource = {},
 30     memBlank = {},
 31     memLiteral = {},
 32     memTriple = {},
 33     memPattern = {},
 34     
 35     xsdNs = "http://www.w3.org/2001/XMLSchema#",
 36     rdfNs = "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
 37     rdfsNs = "http://www.w3.org/2000/01/rdf-schema#",
 38     
 39     uriRegex = /^<(([^>]|\\>)*)>$/,
 40     literalRegex = /^("""((\\"|[^"])*)"""|"((\\"|[^"])*)")(@([a-z]+(-[a-z0-9]+)*)|\^\^(.+))?$/,
 41     tripleRegex = /(("""((\\"|[^"])*)""")|("(\\"|[^"]|)*")|(<(\\>|[^>])*>)|\S)+/g,
 42 
 43     blankNodeSeed = databankSeed = new Date().getTime() % 1000,
 44     blankNodeID = function () {
 45       blankNodeSeed += 1;
 46       return 'b' + blankNodeSeed.toString(16);
 47     },
 48 
 49     databankID = function () {
 50       databankSeed += 1;
 51       return 'data' + databankSeed.toString(16);
 52     },
 53     databanks = {},
 54 
 55     documentQueue = {},
 56 
 57     subject = function (subject, opts) {
 58       if (typeof subject === 'string') {
 59         try {
 60           return $.rdf.resource(subject, opts);
 61         } catch (e) {
 62           try {
 63             return $.rdf.blank(subject, opts);
 64           } catch (f) {
 65             throw "Bad Triple: Subject " + subject + " is not a resource: " + f;
 66           }
 67         }
 68       } else {
 69         return subject;
 70       }
 71     },
 72 
 73     property = function (property, opts) {
 74       if (property === 'a') {
 75         return $.rdf.type;
 76       } else if (typeof property === 'string') {
 77         try {
 78           return $.rdf.resource(property, opts);
 79         } catch (e) {
 80           throw "Bad Triple: Property " + property + " is not a resource: " + e;
 81         }
 82       } else {
 83         return property;
 84       }
 85     },
 86 
 87     object = function (object, opts) {
 88       if (typeof object === 'string') {
 89         try {
 90           return $.rdf.resource(object, opts);
 91         } catch (e) {
 92           try {
 93             return $.rdf.blank(object, opts);
 94           } catch (f) {
 95             try {
 96               return $.rdf.literal(object, opts);
 97             } catch (g) {
 98               throw "Bad Triple: Object " + object + " is not a resource or a literal " + g;
 99             }
100           }
101         }
102       } else {
103         return object;
104       }
105     },
106 
107     testResource = function (resource, filter, existing) {
108       var variable;
109       if (typeof filter === 'string') {
110         variable = filter.substring(1);
111         if (existing[variable] && existing[variable] !== resource) {
112           return null;
113         } else {
114           existing[variable] = resource;
115           return existing;
116         }
117       } else if (filter === resource) {
118         return existing;
119       } else {
120         return null;
121       }
122     },
123 
124     findMatches = function (databank, pattern) {
125       if (databank.union === undefined) {
126         if (pattern.subject.type !== undefined) {
127           if (databank.subjectIndex[pattern.subject] === undefined) {
128             return [];
129           }
130           return $.map(databank.subjectIndex[pattern.subject], function (triple) {
131             var bindings = pattern.exec(triple);
132             return bindings === null ? null : { bindings: bindings, triples: [triple] };
133           });
134         } else if (pattern.object.type === 'uri' || pattern.object.type === 'bnode') {
135           if (databank.objectIndex[pattern.object] === undefined) {
136             return [];
137           }
138           return $.map(databank.objectIndex[pattern.object], function (triple) {
139             var bindings = pattern.exec(triple);
140             return bindings === null ? null : { bindings: bindings, triples: [triple] };
141           });
142         } else if (pattern.property.type !== undefined) {
143           if (databank.propertyIndex[pattern.property] === undefined) {
144             return [];
145           }
146           return $.map(databank.propertyIndex[pattern.property], function (triple) {
147             var bindings = pattern.exec(triple);
148             return bindings === null ? null : { bindings: bindings, triples: [triple] };
149           });
150         }
151       }
152       return $.map(databank.triples(), function (triple) {
153         var bindings = pattern.exec(triple);
154         return bindings === null ? null : { bindings: bindings, triples: [triple] };
155       });
156     },
157 
158     mergeMatches = function (existingMs, newMs, optional) {
159       return $.map(existingMs, function (existingM, i) {
160         var compatibleMs = $.map(newMs, function (newM) {
161           // For newM to be compatible with existingM, all the bindings
162           // in newM must either be the same as in existingM, or not
163           // exist in existingM
164           var k, b, isCompatible = true;
165           for (k in newM.bindings) {
166             b = newM.bindings[k];
167             if (!(existingM.bindings[k] === undefined ||
168                   existingM.bindings[k] === b)) {
169               isCompatible = false;
170               break;
171             }
172           }
173           return isCompatible ? newM : null;
174         });
175         if (compatibleMs.length > 0) {
176           return $.map(compatibleMs, function (compatibleM) {
177             return {
178               bindings: $.extend({}, existingM.bindings, compatibleM.bindings),
179               triples: unique(existingM.triples.concat(compatibleM.triples))
180             };
181           });
182         } else {
183           return optional ? existingM : null;
184         }
185       });
186     },
187 
188     registerQuery = function (databank, query) {
189       var s, p, o;
190       if (query.filterExp !== undefined && !$.isFunction(query.filterExp)) {
191         if (databank.union === undefined) {
192           s = typeof query.filterExp.subject === 'string' ? '' : query.filterExp.subject;
193           p = typeof query.filterExp.property === 'string' ? '' : query.filterExp.property;
194           o = typeof query.filterExp.object === 'string' ? '' : query.filterExp.object;
195           if (databank.queries[s] === undefined) {
196             databank.queries[s] = {};
197           }
198           if (databank.queries[s][p] === undefined) {
199             databank.queries[s][p] = {};
200           }
201           if (databank.queries[s][p][o] === undefined) {
202             databank.queries[s][p][o] = [];
203           }
204           databank.queries[s][p][o].push(query);
205         } else {
206           $.each(databank.union, function (i, databank) {
207             registerQuery(databank, query);
208           });
209         }
210       }
211     },
212 
213     resetQuery = function (query) {
214       query.length = 0;
215       query.matches = [];
216       $.each(query.children, function (i, child) {
217         resetQuery(child);
218       });
219       $.each(query.partOf, function (i, union) {
220         resetQuery(union);
221       });
222     },
223 
224     updateQuery = function (query, matches) {
225       if (matches.length > 0) {
226         $.each(query.children, function (i, child) {
227           leftActivate(child, matches);
228         });
229         $.each(query.partOf, function (i, union) {
230           updateQuery(union, matches);
231         });
232         $.each(matches, function (i, match) {
233           query.matches.push(match);
234           Array.prototype.push.call(query, match.bindings);
235         });
236       }
237     },
238 
239     filterMatches = function (matches, variables) {
240       var i, bindings, triples, j, k, variable, value, nvariables = variables.length,
241         newbindings, match = {}, keyobject = {}, keys = {}, filtered = [];
242       for (i = 0; i < matches.length; i += 1) {
243         bindings = matches[i].bindings;
244         triples = matches[i].triples;
245         keyobject = keys;
246         for (j = 0; j < nvariables; j += 1) {
247           variable = variables[j];
248           value = bindings[variable];
249           if (j === nvariables - 1) {
250             if (keyobject[value] === undefined) {
251               match = { bindings: {}, triples: triples };
252               for (k = 0; k < nvariables; k += 1) {
253                 match.bindings[variables[k]] = bindings[variables[k]];
254               }
255               keyobject[value] = match;
256               filtered.push(match);
257             } else {
258               match = keyobject[value];
259               match.triples = match.triples.concat(triples);
260             }
261           } else {
262             if (keyobject[value] === undefined) {
263               keyobject[value] = {};
264             }
265             keyobject = keyobject[value];
266           }
267         }
268       }
269       return filtered;
270     },
271 
272     renameMatches = function (matches, old) {
273       var i, match, newMatch, keys = {}, renamed = [];
274       for (i = 0; i < matches.length; i += 1) {
275         match = matches[i];
276         if (keys[match.bindings[old]] === undefined) {
277           newMatch = {
278             bindings: { node: match.bindings[old] },
279             triples: match.triples
280           };
281           renamed.push(newMatch);
282           keys[match.bindings[old]] = newMatch;
283         } else {
284           newMatch = keys[match.bindings[old]];
285           newMatch.triples = newMatch.triples.concat(match.triples);
286         }
287       }
288       return renamed;
289     },
290 
291     leftActivate = function (query, matches) {
292       var newMatches;
293       if (query.union === undefined) {
294         if (query.top || query.parent.top) {
295           newMatches = query.alphaMemory;
296         } else {
297           matches = matches || query.parent.matches;
298           if ($.isFunction(query.filterExp)) {
299             newMatches = $.map(matches, function (match, i) {
300               return query.filterExp.call(match.bindings, i, match.bindings, match.triples) ? match : null;
301             });
302           } else if (query.filterExp !== undefined) {
303             newMatches = mergeMatches(matches, query.alphaMemory, query.filterExp.optional);
304           } else {
305             newMatches = matches;
306           }
307         }
308       } else {
309         newMatches = $.map(query.union, function (q) {
310           return q.matches;
311         });
312       }
313       if (query.selections !== undefined) {
314         newMatches = filterMatches(newMatches, query.selections);
315       } else if (query.navigate !== undefined) {
316         newMatches = renameMatches(newMatches, query.navigate);
317       }
318       updateQuery(query, newMatches);
319     },
320 
321     rightActivate = function (query, match) {
322       var newMatches;
323       if (query.filterExp.optional) {
324         resetQuery(query);
325         leftActivate(query);
326       } else {
327         if (query.top || query.parent.top) {
328           newMatches = [match];
329         } else {
330           newMatches = mergeMatches(query.parent.matches, [match], false);
331         }
332         updateQuery(query, newMatches);
333       }
334     },
335 
336     addToQuery = function (query, triple) {
337       var match,
338         bindings = query.filterExp.exec(triple);
339       if (bindings !== null) {
340         match = { triples: [triple], bindings: bindings };
341         query.alphaMemory.push(match);
342         rightActivate(query, match);
343       }
344     },
345 
346     removeFromQuery = function (query, triple) {
347       query.alphaMemory.splice($.inArray(triple, query.alphaMemory), 1);
348       resetQuery(query);
349       leftActivate(query);
350     },
351 
352     addToQueries = function (queries, triple) {
353       $.each(queries, function (i, query) {
354         addToQuery(query, triple);
355       });
356     },
357 
358     removeFromQueries = function (queries, triple) {
359       $.each(queries, function (i, query) {
360         removeFromQuery(query, triple);
361       });
362     },
363 
364     addToDatabankQueries = function (databank, triple) {
365       var s = triple.subject,
366         p = triple.property,
367         o = triple.object;
368       if (databank.union === undefined) {
369         if (databank.queries[s] !== undefined) {
370           if (databank.queries[s][p] !== undefined) {
371             if (databank.queries[s][p][o] !== undefined) {
372               addToQueries(databank.queries[s][p][o], triple);
373             }
374             if (databank.queries[s][p][''] !== undefined) {
375               addToQueries(databank.queries[s][p][''], triple);
376             }
377           }
378           if (databank.queries[s][''] !== undefined) {
379             if (databank.queries[s][''][o] !== undefined) {
380               addToQueries(databank.queries[s][''][o], triple);
381             }
382             if (databank.queries[s][''][''] !== undefined) {
383               addToQueries(databank.queries[s][''][''], triple);
384             }
385           }
386         }
387         if (databank.queries[''] !== undefined) {
388           if (databank.queries[''][p] !== undefined) {
389             if (databank.queries[''][p][o] !== undefined) {
390               addToQueries(databank.queries[''][p][o], triple);
391             }
392             if (databank.queries[''][p][''] !== undefined) {
393               addToQueries(databank.queries[''][p][''], triple);
394             }
395           }
396           if (databank.queries[''][''] !== undefined) {
397             if (databank.queries[''][''][o] !== undefined) {
398               addToQueries(databank.queries[''][''][o], triple);
399             }
400             if (databank.queries[''][''][''] !== undefined) {
401               addToQueries(databank.queries[''][''][''], triple);
402             }
403           }
404         }
405       } else {
406         $.each(databank.union, function (i, databank) {
407           addToDatabankQueries(databank, triple);
408         });
409       }
410     },
411 
412     removeFromDatabankQueries = function (databank, triple) {
413       var s = triple.subject,
414         p = triple.property,
415         o = triple.object;
416       if (databank.union === undefined) {
417         if (databank.queries[s] !== undefined) {
418           if (databank.queries[s][p] !== undefined) {
419             if (databank.queries[s][p][o] !== undefined) {
420               removeFromQueries(databank.queries[s][p][o], triple);
421             }
422             if (databank.queries[s][p][''] !== undefined) {
423               removeFromQueries(databank.queries[s][p][''], triple);
424             }
425           }
426           if (databank.queries[s][''] !== undefined) {
427             if (databank.queries[s][''][o] !== undefined) {
428               removeFromQueries(databank.queries[s][''][o], triple);
429             }
430             if (databank.queries[s][''][''] !== undefined) {
431               removeFromQueries(databank.queries[s][''][''], triple);
432             }
433           }
434         }
435         if (databank.queries[''] !== undefined) {
436           if (databank.queries[''][p] !== undefined) {
437             if (databank.queries[''][p][o] !== undefined) {
438               removeFromQueries(databank.queries[''][p][o], triple);
439             }
440             if (databank.queries[''][p][''] !== undefined) {
441               removeFromQueries(databank.queries[''][p][''], triple);
442             }
443           }
444           if (databank.queries[''][''] !== undefined) {
445             if (databank.queries[''][''][o] !== undefined) {
446               removeFromQueries(databank.queries[''][''][o], triple);
447             }
448             if (databank.queries[''][''][''] !== undefined) {
449               removeFromQueries(databank.queries[''][''][''], triple);
450             }
451           }
452         }
453       } else {
454         $.each(databank.union, function (i, databank) {
455           removeFromDatabankQueries(databank, triple);
456         });
457       }
458     },
459     
460     group = function (bindings, variables, base) {
461       var variable = variables[0], grouped = {}, results = [], i, newbase;
462       base = base || {};
463       if (variables.length === 0) {
464         for (i = 0; i < bindings.length; i += 1) {
465           for (v in bindings[i]) {
466             if (base[v] === undefined) {
467               base[v] = [];
468             }
469             if ($.isArray(base[v])) {
470               base[v].push(bindings[i][v]);
471             }
472           }
473         }
474         return [base];
475       }
476       // collect together the grouped results
477       for (i = 0; i < bindings.length; i += 1) {
478         key = bindings[i][variable];
479         if (grouped[key] === undefined) {
480           grouped[key] = [];
481         }
482         grouped[key].push(bindings[i]);
483       }
484       // call recursively on each group
485       variables = variables.splice(1, 1);
486       for (v in grouped) {
487         newbase = $.extend({}, base);
488         newbase[variable] = grouped[v][0][variable];
489         results = results.concat(group(grouped[v], variables, newbase));
490       }
491       return results;
492     },
493     
494     queue = function (databank, url, callbacks) {
495       if (documentQueue[databank.id] === undefined) {
496         documentQueue[databank.id] = {};
497       }
498       if (documentQueue[databank.id][url] === undefined) {
499         documentQueue[databank.id][url] = callbacks;
500         return false;
501       }
502       return true;
503     },
504     
505     dequeue = function (databank, url, result, args) {
506       var callbacks = documentQueue[databank.id][url];
507       if ($.isFunction(callbacks[result])) {
508         callbacks[result].call(databank, args);
509       }
510       documentQueue[databank.id][url] = undefined;
511     },
512 
513     unique = function( b ) {
514       var a = [];
515       var l = b.length;
516       for(var i=0; i<l; i++) {
517         for(var j=i+1; j<l; j++) {
518           // If b[i] is found later in the array
519           if (b[i] === b[j])
520             j = ++i;
521         }
522         a.push(b[i]);
523       }
524       return a;
525      };
526 
527 
528   $.typedValue.types['http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral'] = {
529     regex: /^.*$/m,
530     strip: false,
531     value: function (v) {
532       return v;
533     }
534   };
535 
536   /**
537    * <p>Creates a new jQuery.rdf object. This should be invoked as a method rather than constructed using new; indeed you will usually want to generate these objects using a method such as {@link jQuery#rdf} or {@link jQuery.rdf#where}.</p>
538    * @class <p>A jQuery.rdf object represents the results of a query over its {@link jQuery.rdf#databank}. The results of a query are a sequence of objects which represent the bindings of values to the variables used in filter expressions specified using {@link jQuery.rdf#where} or {@link jQuery.rdf#optional}. Each of the objects in this sequence has associated with it a set of triples that are the sources for the variable bindings, which you can get at using {@link jQuery.rdf#sources}.</p>
539     * <p>The {@link jQuery.rdf} object itself is a lot like a {@link jQuery} object. It has a {@link jQuery.rdf#length} and the individual matches can be accessed using <code>[<var>n</var>]</code>, but you can also iterate through the matches using {@link jQuery.rdf#map} or {@link jQuery.rdf#each}.</p>
540     * <p>{@link jQuery.rdf} is designed to mirror the functionality of <a href="http://www.w3.org/TR/rdf-sparql-query/">SPARQL</a> while providing an interface that's familiar and easy to use for jQuery programmers.</p>
541    * @param {Object} [options]
542    * @param {jQuery.rdf.databank} [options.databank] The databank that this query should operate over.
543    * @param {jQuery.rdf.triple[]} [options.triples] A set of triples over which the query operates; this is only used if options.databank isn't specified, in which case a new databank with these triples is generated.
544    * @param {Object} [options.namespaces] An object representing a set of namespace bindings. Rather than passing this in when you construct the {@link jQuery.rdf} instance, you will usually want to use the {@link jQuery.rdf#prefix} method.
545    * @param {String|jQuery.uri} [options.base] The base URI used to interpret any relative URIs used within the query.
546    * @returns {jQuery.rdf}
547    * @example rdf = jQuery.rdf();
548    * @see jQuery#rdf
549    */
550   $.rdf = function (options) {
551     return new $.rdf.fn.init(options);
552   };
553 
554   $.rdf.fn = $.rdf.prototype = {
555     /**
556      * The version of rdfQuery.
557      * @type String
558      */
559     rdfquery: '1.1',
560 
561     init: function (options) {
562       var databanks, i;
563       options = options || {};
564       /* must specify either a parent or a union, otherwise it's the top */
565       this.parent = options.parent;
566       this.union = options.union;
567       this.top = this.parent === undefined && this.union === undefined;
568       if (this.union === undefined) {
569         if (options.databank === undefined) {
570           /**
571            * The databank over which this query operates.
572            * @type jQuery.rdf.databank
573            */
574           this.databank = this.parent === undefined ? $.rdf.databank(options.triples, options) : this.parent.databank;
575         } else {
576           this.databank = options.databank;
577         }
578       } else {
579         databanks = $.map(this.union, function (query) {
580           return query.databank;
581         });
582         databanks = unique(databanks);
583         if (databanks[1] !== undefined) {
584           this.databank = $.rdf.databank(undefined, { union: databanks });
585         } else {
586           this.databank = databanks[0];
587         }
588       }
589       this.children = [];
590       this.partOf = [];
591       this.filterExp = options.filter;
592       this.selections = options.distinct;
593       this.navigate = options.navigate;
594       this.alphaMemory = [];
595       this.matches = [];
596       /**
597        * The number of matches represented by the {@link jQuery.rdf} object.
598        * @type Integer
599        */
600       this.length = 0;
601       if (this.filterExp !== undefined) {
602         if (!$.isFunction(this.filterExp)) {
603           registerQuery(this.databank, this);
604           this.alphaMemory = findMatches(this.databank, this.filterExp);
605         }
606       } else if (options.nodes !== undefined) {
607         this.alphaMemory = [];
608         for (i = 0; i < options.nodes.length; i += 1) {
609           this.alphaMemory.push({
610             bindings: { node: options.nodes[i] },
611             triples: []
612           });
613         }
614       }
615       leftActivate(this);
616       return this;
617     },
618 
619     /**
620      * Sets or returns the base URI of the {@link jQuery.rdf#databank}.
621      * @param {String|jQuery.uri} [base]
622      * @returns A {@link jQuery.uri} if no base URI is specified, otherwise returns this {@link jQuery.rdf} object.
623      * @example baseURI = jQuery('html').rdf().base();
624      * @example jQuery('html').rdf().base('http://www.example.org/');
625      * @see jQuery.rdf.databank#base
626      */
627     base: function (base) {
628       if (base === undefined) {
629         return this.databank.base();
630       } else {
631         this.databank.base(base);
632         return this;
633       }
634     },
635 
636     /**
637      * Sets or returns a namespace binding on the {@link jQuery.rdf#databank}.
638      * @param {String} [prefix]
639      * @param {String} [namespace]
640      * @returns {Object|jQuery.uri|jQuery.rdf} If no prefix or namespace is specified, returns an object providing all namespace bindings on the {@link jQuery.rdf.databank}. If a prefix is specified without a namespace, returns the {@link jQuery.uri} associated with that prefix. Otherwise returns this {@link jQuery.rdf} object after setting the namespace binding.
641      * @example namespace = jQuery('html').rdf().prefix('foaf');
642      * @example jQuery('html').rdf().prefix('foaf', 'http://xmlns.com/foaf/0.1/');
643      * @see jQuery.rdf.databank#prefix
644      */
645     prefix: function (prefix, namespace) {
646       if (namespace === undefined) {
647         return this.databank.prefix(prefix);
648       } else {
649         this.databank.prefix(prefix, namespace);
650         return this;
651       }
652     },
653 
654     /**
655      * Adds a triple to the {@link jQuery.rdf#databank} or another {@link jQuery.rdf} object to create a union.
656      * @param {String|jQuery.rdf.triple|jQuery.rdf.pattern|jQuery.rdf} triple The triple, {@link jQuery.rdf.pattern} or {@link jQuery.rdf} object to be added to this one. If the triple is a {@link jQuery.rdf} object, the two queries are unioned together. If the triple is a string, it's parsed as a {@link jQuery.rdf.pattern}. The pattern will be completed using the current matches on the {@link jQuery.rdf} object to create multiple triples, one for each set of bindings.
657      * @param {Object} [options]
658      * @param {Object} [options.namespaces] An object representing a set of namespace bindings used to interpret CURIEs within the triple. Defaults to the namespace bindings defined on the {@link jQuery.rdf#databank}.
659      * @param {String|jQuery.uri} [options.base] The base URI used to interpret any relative URIs used within the triple. Defaults to the base URI defined on the {@link jQuery.rdf#databank}.
660      * @returns {jQuery.rdf} This {@link jQuery.rdf} object.
661      * @example
662      * var rdf = $.rdf()
663      *   .prefix('dc', ns.dc)
664      *   .prefix('foaf', ns.foaf)
665      *   .add('<photo1.jpg> dc:creator <http://www.blogger.com/profile/1109404> .')
666      *   .add('<http://www.blogger.com/profile/1109404> foaf:img <photo1.jpg> .');
667      * @example
668      * var rdfA = $.rdf()
669      *   .prefix('dc', ns.dc)
670      *   .add('<photo1.jpg> dc:creator "Jane"');
671      * var rdfB = $.rdf()
672      *   .prefix('foaf', ns.foaf)
673      *   .add('<photo1.jpg> foaf:depicts "Jane"');
674      * var rdf = rdfA.add(rdfB);
675      * @see jQuery.rdf.databank#add
676      */
677     add: function (triple, options) {
678       var query, databank;
679       if (triple.rdfquery !== undefined) {
680         if (triple.top) {
681           databank = this.databank.add(triple.databank);
682           query = $.rdf({ parent: this.parent, databank: databank });
683           return query;
684         } else if (this.top) {
685           databank = triple.databank.add(this.databank);
686           query = $.rdf({ parent: triple.parent, databank: databank });
687           return query;
688         } else if (this.union === undefined) {
689           query = $.rdf({ union: [this, triple] });
690           this.partOf.push(query);
691           triple.partOf.push(query);
692           return query;
693         } else {
694           this.union.push(triple);
695           triple.partOf.push(this);
696         }
697       } else {
698         if (typeof triple === 'string') {
699           options = $.extend({}, { base: this.base(), namespaces: this.prefix(), source: triple }, options);
700           triple = $.rdf.pattern(triple, options);
701         }
702         if (triple.isFixed()) {
703           this.databank.add(triple.triple(), options);
704         } else {
705           query = this;
706           this.each(function (i, data) {
707             var t = triple.triple(data);
708             if (t !== null) {
709               query.databank.add(t, options);
710             }
711           });
712         }
713       }
714       return this;
715     },
716 
717     /**
718      * Removes a triple or several triples from the {@link jQuery.rdf#databank}.
719      * @param {String|jQuery.rdf.triple|jQuery.rdf.pattern} triple The triple to be removed, or a {@link jQuery.rdf.pattern} that matches the triples that should be removed.
720      * @param {Object} [options]
721      * @param {Object} [options.namespaces] An object representing a set of namespace bindings used to interpret any CURIEs within the triple or pattern. Defaults to the namespace bindings defined on the {@link jQuery.rdf#databank}.
722      * @param {String|jQuery.uri} [options.base] The base URI used to interpret any relative URIs used within the triple or pattern. Defaults to the base URI defined on the {@link jQuery.rdf#databank}.
723      * @returns {jQuery.rdf} The {@link jQuery.rdf} object itself.
724      * @example
725      * var rdf = $('html').rdf()
726      *   .prefix('foaf', ns.foaf)
727      *   .where('?person foaf:givenname ?gname')
728      *   .where('?person foaf:family_name ?fname')
729      *   .remove('?person foaf:family_name ?fname');
730      * @see jQuery.rdf.databank#remove
731      */
732     remove: function (triple, options) {
733       if (typeof triple === 'string') {
734         options = $.extend({}, { base: this.base(), namespaces: this.prefix() }, options);
735         triple = $.rdf.pattern(triple, options);
736       }
737       if (triple.isFixed()) {
738         this.databank.remove(triple.triple(), options);
739       } else {
740         query = this;
741         this.each(function (i, data) {
742           var t = triple.triple(data);
743           if (t !== null) {
744             query.databank.remove(t, options);
745           }
746         });
747       }
748       return this;
749     },
750 
751     /**
752      * Loads some data into the {@link jQuery.rdf#databank}
753      * @param data
754      * @param {Object} [options]
755      * @see jQuery.rdf.databank#load
756      */
757     load: function (data, options) {
758       var rdf = this,
759         options = options || {},
760         success = options.success;
761       if (success !== undefined) {
762         options.success = function () {
763           success.call(rdf);
764         }
765       }
766       this.databank.load(data, options);
767       return this;
768     },
769 
770     /**
771      * Creates a new {@link jQuery.rdf} object whose databank contains all the triples in this object's databank except for those in the argument's databank.
772      * @param {jQuery.rdf} query
773      * @see jQuery.rdf.databank#except
774      */
775     except: function (query) {
776       return $.rdf({ databank: this.databank.except(query.databank) });
777     },
778 
779     /**
780      * Creates a new {@link jQuery.rdf} object that is the result of filtering the matches on this {@link jQuery.rdf} object based on the filter that's passed into it.
781      * @param {String|jQuery.rdf.pattern} filter An expression that filters the triples in the {@link jQuery.rdf#databank} to locate matches based on the matches on this {@link jQuery.rdf} object. If it's a string, the filter is parsed as a {@link jQuery.rdf.pattern}.
782      * @param {Object} [options]
783      * @param {Object} [options.namespaces] An object representing a set of namespace bindings used to interpret any CURIEs within the pattern. Defaults to the namespace bindings defined on the {@link jQuery.rdf#databank}.
784      * @param {String|jQuery.uri} [options.base] The base URI used to interpret any relative URIs used within the pattern. Defaults to the base URI defined on the {@link jQuery.rdf#databank}.
785      * @param {boolean} [options.optional] Not usually used (use {@link jQuery.rdf#optional} instead).
786      * @returns {jQuery.rdf} A new {@link jQuery.rdf} object whose {@link jQuery.rdf#parent} is this {@link jQuery.rdf}.
787      * @see jQuery.rdf#optional
788      * @see jQuery.rdf#filter
789      * @see jQuery.rdf#about
790      * @example
791      * var rdf = $.rdf()
792      *   .prefix('foaf', ns.foaf)
793      *   .add('_:a foaf:givenname   "Alice" .')
794      *   .add('_:a foaf:family_name "Hacker" .')
795      *   .add('_:b foaf:givenname   "Bob" .')
796      *   .add('_:b foaf:family_name "Hacker" .')
797      *   .where('?person foaf:family_name "Hacker"')
798      *   .where('?person foaf:givenname "Bob");
799      */ 
800     where: function (filter, options) {
801       var query, base, namespaces, optional;
802       options = options || {};
803       if (typeof filter === 'string') {
804         base = options.base || this.base();
805         namespaces = $.extend({}, this.prefix(), options.namespaces || {});
806         optional = options.optional || false;
807         filter = $.rdf.pattern(filter, { namespaces: namespaces, base: base, optional: optional });
808       }
809       query = $.rdf($.extend({}, options, { parent: this, filter: filter }));
810       this.children.push(query);
811       return query;
812     },
813 
814     /**
815      * Creates a new {@link jQuery.rdf} object whose set of bindings might optionally include those based on the filter pattern.
816      * @param {String|jQuery.rdf.pattern} filter An pattern for a set of bindings that might be added to those in this {@link jQuery.rdf} object.
817      * @param {Object} [options]
818      * @param {Object} [options.namespaces] An object representing a set of namespace bindings used to interpret any CURIEs within the pattern. Defaults to the namespace bindings defined on the {@link jQuery.rdf#databank}.
819      * @param {String|jQuery.uri} [options.base] The base URI used to interpret any relative URIs used within the pattern. Defaults to the base URI defined on the {@link jQuery.rdf#databank}.
820      * @returns {jQuery.rdf} A new {@link jQuery.rdf} object whose {@link jQuery.rdf#parent} is this {@link jQuery.rdf}.
821      * @see jQuery.rdf#where
822      * @see jQuery.rdf#filter
823      * @see jQuery.rdf#about
824      * @example
825      * var rdf = $.rdf()
826      *   .prefix('foaf', 'http://xmlns.com/foaf/0.1/')
827      *   .prefix('rdf', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#')
828      *   .add('_:a  rdf:type        foaf:Person .')
829      *   .add('_:a  foaf:name       "Alice" .')
830      *   .add('_:a  foaf:mbox       <mailto:alice@example.com> .')
831      *   .add('_:a  foaf:mbox       <mailto:alice@work.example> .')
832      *   .add('_:b  rdf:type        foaf:Person .')
833      *   .add('_:b  foaf:name       "Bob" .')
834      *   .where('?x foaf:name ?name')
835      *   .optional('?x foaf:mbox ?mbox');
836      */
837     optional: function (filter, options) {
838       return this.where(filter, $.extend({}, options || {}, { optional: true }));
839     },
840 
841     /**
842      * Creates a new {@link jQuery.rdf} object whose set of bindings include <code>property</code> and <code>value</code> for every triple that is about the specified resource.
843      * @param {String|jQuery.rdf.resource} resource The subject of the matching triples.
844      * @param {Object} [options]
845      * @param {Object} [options.namespaces] An object representing a set of namespace bindings used to interpret the resource if it's a CURIE. Defaults to the namespace bindings defined on the {@link jQuery.rdf#databank}.
846      * @param {String|jQuery.uri} [options.base] The base URI used to interpret the resource if it's a relative URI (wrapped in <code><</code> and <code>></code>). Defaults to the base URI defined on the {@link jQuery.rdf#databank}.
847      * @returns {jQuery.rdf} A new {@link jQuery.rdf} object whose {@link jQuery.rdf#parent} is this {@link jQuery.rdf}.
848      * @see jQuery.rdf#where
849      * @see jQuery.rdf#optional
850      * @see jQuery.rdf#filter
851      * @example
852      * var rdf = $.rdf()
853      *   .prefix('dc', ns.dc)
854      *   .prefix('foaf', ns.foaf)
855      *   .add('<photo1.jpg> dc:creator <http://www.blogger.com/profile/1109404> .')
856      *   .add('<http://www.blogger.com/profile/1109404> foaf:img <photo1.jpg> .')
857      *   .add('<photo2.jpg> dc:creator <http://www.blogger.com/profile/1109404> .')
858      *   .add('<http://www.blogger.com/profile/1109404> foaf:img <photo2.jpg> .')
859      *   .about('<http://www.blogger.com/profile/1109404>');
860      */
861     about: function (resource, options) {
862       return this.where(resource + ' ?property ?value', options);
863     },
864 
865     /**
866      * Creates a new {@link jQuery.rdf} object whose set of bindings include only those that satisfy some arbitrary condition. There are two main ways to call this method: with two arguments in which case the first is a binding to be tested and the second represents a condition on the test, or with one argument which is a function that should return true for acceptable bindings.
867      * @param {Function|String} property <p>In the two-argument version, this is the name of a property to be tested against the condition specified in the second argument. In the one-argument version, this is a function in which <code>this</code> is an object whose properties are a set of {@link jQuery.rdf.resource}, {@link jQuery.rdf.literal} or {@link jQuery.rdf.blank} objects and whose arguments are:</p>
868      * <dl>
869      *   <dt>i</dt>
870      *   <dd>The index of the set of bindings amongst the other matches</dd>
871      *   <dt>bindings</dt>
872      *   <dd>An object representing the bindings (the same as <code>this</code>)</dd>
873      *   <dt>triples</dt>
874      *   <dd>The {@link jQuery.rdf.triple}s that underly this set of bindings</dd>
875      * </dl>
876      * @param {RegExp|String} condition In the two-argument version of this function, the condition that the property's must match. If it is a regular expression, the value must match the regular expression. If it is a {@link jQuery.rdf.literal}, the value of the literal must match the property's value. Otherwise, they must be the same resource.
877      * @returns {jQuery.rdf} A new {@link jQuery.rdf} object whose {@link jQuery.rdf#parent} is this {@link jQuery.rdf}.
878      * @see jQuery.rdf#where
879      * @see jQuery.rdf#optional
880      * @see jQuery.rdf#about
881      * @example
882      * var rdf = $.rdf()
883      *   .prefix('foaf', 'http://xmlns.com/foaf/0.1/')
884      *   .add('_:a foaf:surname "Jones" .')
885      *   .add('_:b foaf:surname "Macnamara" .')
886      *   .add('_:c foaf:surname "O\'Malley"')
887      *   .add('_:d foaf:surname "MacFee"')
888      *   .where('?person foaf:surname ?surname')
889      *     .filter('surname', /^Ma?c/)
890      *       .each(function () { scottish.push(this.surname.value); })
891      *     .end()
892      *     .filter('surname', /^O'/)
893      *       .each(function () { irish.push(this.surname.value); })
894      *     .end();
895      * @example
896      * var rdf = $.rdf()
897      *   .prefix('foaf', 'http://xmlns.com/foaf/0.1/')
898      *   .add('_:a foaf:surname "Jones" .')
899      *   .add('_:b foaf:surname "Macnamara" .')
900      *   .add('_:c foaf:surname "O\'Malley"')
901      *   .add('_:d foaf:surname "MacFee"')
902      *   .where('?person foaf:surname ?surname')
903      *   .filter(function () { return this.surname !== "Jones"; })
904      */
905     filter: function (property, condition) {
906       var func, query;
907       if (typeof property === 'string') {
908         if (condition.constructor === RegExp) {
909           /** @ignore func */
910           func = function () {
911             return condition.test(this[property].value);
912           };
913         } else {
914           func = function () {
915             return this[property].type === 'literal' ? this[property].value === condition : this[property] === condition;
916           };
917         }
918       } else {
919         func = property;
920       }
921       query = $.rdf({ parent: this, filter: func });
922       this.children.push(query);
923       return query;
924     },
925 
926     /**
927      * Creates a new {@link jQuery.rdf} object containing one binding for each selected resource.
928      * @param {String|Object} node The node to be selected. If this is a string beginning with a question mark the resources are those identified by the bindings of that value in the currently selected bindings. Otherwise, only the named resource is selected as the node.
929      * @returns {jQuery.rdf} A new {@link jQuery.rdf} object.
930      * @see jQuery.rdf#find
931      * @see jQuery.rdf#back
932      * @example
933      * // returns an rdfQuery object with a pointer to <http://example.com/aReallyGreatBook>
934      * var rdf = $('html').rdf()
935      *   .node('<http://example.com/aReallyGreatBook>');
936      */
937     node: function (resource) {
938       var variable, query;
939       if (resource.toString().substring(0, 1) === '?') {
940         variable = resource.toString().substring(1);
941         query = $.rdf({ parent: this, navigate: variable });
942       } else {
943         if (typeof resource === 'string') {
944           resource = object(resource, { namespaces: this.prefix(), base: this.base() });
945         }
946         query = $.rdf({ parent: this, nodes: [resource] });
947       }
948       this.children.push(query);
949       return query;
950     },
951     
952     /**
953      * Navigates from the resource identified by the 'node' binding to another node through the property passed as the argument.
954      * @param {String|Object} property The property whose value will be the new node.
955      * @returns {jQuery.rdf} A new {@link jQuery.rdf} object whose {@link jQuery.rdf#parent} is this {@link jQuery.rdf}.
956      * @see jQuery.rdf#back
957      * @see jQuery.rdf#node
958      * @example
959      * var creators = $('html').rdf()
960      *   .node('<>')
961      *   .find('dc:creator');
962      */
963     find: function (property) {
964       return this.where('?node ' + property + ' ?object', { navigate: 'object' });
965     },
966     
967     /**
968      * Navigates from the resource identified by the 'node' binding to another node through the property passed as the argument, like {jQuery.rdf#find}, but backwards.
969      * @param {String|Object} property The property whose value will be the new node.
970      * @returns {jQuery.rdf} A new {@link jQuery.rdf} object whose {@link jQuery.rdf#parent} is this {@link jQuery.rdf}.
971      * @see jQuery.rdf#find
972      * @see jQuery.rdf#node
973      * @example
974      * var people = $('html').rdf()
975      *   .node('foaf:Person')
976      *   .back('rdf:type');
977      */
978     back: function (property) {
979       return this.where('?subject ' + property + ' ?node', { navigate: 'subject' });
980     },
981 
982     /**
983      * Groups the bindings held by this {@link jQuery.rdf} object based on the values of the variables passed as the parameter.
984      * @param {String[]} [bindings] The variables to group by. The returned objects will contain all their current properties, but those aside from the specified variables will be arrays listing the relevant values.
985      * @returns {jQuery} A jQuery object containing objects representing the grouped bindings.
986      * @example
987      * // returns one object per person and groups all the names and all the emails together in arrays
988      * var grouped = rdf
989      *   .where('?person foaf:name ?name')
990      *   .where('?person foaf:email ?email')
991      *   .group('person');
992      * @example
993      * // returns one object per surname/firstname pair, with the person property being an array in the resulting objects
994      * var grouped = rdf
995      *   .where('?person foaf:first_name ?forename')
996      *   .where('?person foaf:givenname ?surname')
997      *   .group(['surname', 'forename']);
998      */
999     group: function (bindings) {
1000       var grouped = {}, results = [], i, key, v;
1001       if (!$.isArray(bindings)) {
1002         bindings = [bindings];
1003       }
1004       return $(group(this, bindings));
1005     },
1006 
1007     /**
1008      * Filters the variable bindings held by this {@link jQuery.rdf} object down to those listed in the bindings parameter. This mirrors the <a href="http://www.w3.org/TR/rdf-sparql-query/#select">SELECT</a> form in SPARQL.
1009      * @param {String[]} [bindings] The variables that you're interested in. The returned objects will only contain those variables. If bindings is undefined, you will get all the variable bindings in the returned objects.
1010      * @returns {Object[]} An array of objects with the properties named by the bindings parameter.
1011      * @example
1012      * var filtered = rdf
1013      *   .where('?photo dc:creator ?creator')
1014      *   .where('?creator foaf:img ?photo');
1015      * var selected = rdf.select(['creator']);
1016      */
1017     select: function (bindings) {
1018       var s = [], i, j;
1019       for (i = 0; i < this.length; i += 1) {
1020         if (bindings === undefined) {
1021           s[i] = this[i];
1022         } else {
1023           s[i] = {};
1024           for (j = 0; j < bindings.length; j += 1) {
1025             s[i][bindings[j]] = this[i][bindings[j]];
1026           }
1027         }
1028       }
1029       return s;
1030     },
1031 
1032     /**
1033      * Provides <a href="http://n2.talis.com/wiki/Bounded_Descriptions_in_RDF#Simple_Concise_Bounded_Description">simple concise bounded descriptions</a> of the resources or bindings that are passed in the argument. This mirrors the <a href="http://www.w3.org/TR/rdf-sparql-query/#describe">DESCRIBE</a> form in SPARQL.
1034      * @param {(String|jQuery.rdf.resource)[]} bindings An array that can contain strings, {@link jQuery.rdf.resource}s or a mixture of the two. Any strings that begin with a question mark (<code>?</code>) are taken as variable names; each matching resource is described by the function.
1035      * @returns {jQuery} A {@link jQuery} object that contains {@link jQuery.rdf.triple}s that describe the listed resources.
1036      * @see jQuery.rdf.databank#describe
1037      * @example
1038      * $.rdf.dump($('html').rdf().describe(['<photo1.jpg>']));
1039      * @example
1040      * $('html').rdf()
1041      *   .where('?person foaf:img ?picture')
1042      *   .describe(['?photo'])
1043      */
1044     describe: function (bindings) {
1045       var i, j, binding, resources = [];
1046       for (i = 0; i < bindings.length; i += 1) {
1047         binding = bindings[i];
1048         if (binding.substring(0, 1) === '?') {
1049           binding = binding.substring(1);
1050           for (j = 0; j < this.length; j += 1) {
1051             resources.push(this[j][binding]);
1052           }
1053         } else {
1054           resources.push(binding);
1055         }
1056       }
1057       return this.databank.describe(resources);
1058     },
1059 
1060     /**
1061      * Returns a new {@link jQuery.rdf} object that contains only one set of variable bindings. This is designed to mirror the <a href="http://docs.jquery.com/Traversing/eq#index">jQuery#eq</a> method.
1062      * @param {Integer} n The index number of the match that should be selected.
1063      * @returns {jQuery.rdf} A new {@link jQuery.rdf} object with just that match.
1064      * @example
1065      * var rdf = $.rdf()
1066      *   .prefix('foaf', 'http://xmlns.com/foaf/0.1/')
1067      *   .add('_:a  foaf:name       "Alice" .')
1068      *   .add('_:a  foaf:homepage   <http://work.example.org/alice/> .')
1069      *   .add('_:b  foaf:name       "Bob" .')
1070      *   .add('_:b  foaf:mbox       <mailto:bob@work.example> .')
1071      *   .where('?x foaf:name ?name')
1072      *   .eq(1);
1073      */
1074     eq: function (n) {
1075       return this.filter(function (i) {
1076         return i === n;
1077       });
1078     },
1079 
1080     /**
1081      * Returns a {@link jQuery.rdf} object that includes no filtering (and therefore has no matches) over the {@link jQuery.rdf#databank}.
1082      * @returns {jQuery.rdf} An empty {@link jQuery.rdf} object.
1083      * @example
1084      * $('html').rdf()
1085      *   .where('?person foaf:family_name "Hacker"')
1086      *   .where('?person foaf:givenname "Alice"')
1087      *   .each(...do something with Alice Hacker...)
1088      *   .reset()
1089      *   .where('?person foaf:family_name "Jones"')
1090      *   .where('?person foaf:givenname "Bob"')
1091      *   .each(...do something with Bob Jones...);
1092      */
1093     reset: function () {
1094       var query = this;
1095       while (query.parent !== undefined) {
1096         query = query.parent;
1097       }
1098       return query;
1099     },
1100 
1101     /**
1102      * Returns the parent {@link jQuery.rdf} object, which is equivalent to undoing the most recent filtering operation (such as {@link jQuery.rdf#where} or {@link jQuery.rdf#filter}). This is designed to mirror the <a href="http://docs.jquery.com/Traversing/end">jQuery#end</a> method.
1103      * @returns {jQuery.rdf}
1104      * @example
1105      * $('html').rdf()
1106      *   .where('?person foaf:family_name "Hacker"')
1107      *   .where('?person foaf:givenname "Alice"')
1108      *   .each(...do something with Alice Hacker...)
1109      *   .end()
1110      *   .where('?person foaf:givenname "Bob"')
1111      *   .each(...do something with Bob Hacker...);
1112      */
1113     end: function () {
1114       return this.parent;
1115     },
1116 
1117     /**
1118      * Returns the number of matches in this {@link jQuery.rdf} object (equivalent to {@link jQuery.rdf#length}).
1119      * @returns {Integer} The number of matches in this {@link jQuery.rdf} object.
1120      * @see jQuery.rdf#length
1121      */
1122     size: function () {
1123       return this.length;
1124     },
1125 
1126     /**
1127      * Gets the triples that form the basis of the variable bindings that are the primary product of {@link jQuery.rdf}. Getting hold of the triples can be useful for understanding the facts that form the basis of the variable bindings.
1128      * @returns {jQuery} A {@link jQuery} object containing arrays of {@link jQuery.rdf.triple} objects. A {@link jQuery} object is returned so that you can easily iterate over the contents.
1129      * @example
1130      * $('html').rdf()
1131      *   .where('?thing a foaf:Person')
1132      *   .sources()
1133      *   .each(function () {
1134      *     ...do something with the array of triples... 
1135      *   });
1136      */
1137     sources: function () {
1138       return $($.map(this.matches, function (match) {
1139         // return an array-of-an-array because arrays automatically get expanded by $.map()
1140         return [match.triples];
1141       }));
1142     },
1143 
1144     /**
1145      * Dumps the triples that form the basis of the variable bindings that are the primary product of {@link jQuery.rdf} into a format that can be shown to the user or sent to a server.
1146      * @param {Object} [options] Options that control the formatting of the triples. See {@link jQuery.rdf.dump} for details.
1147      * @see jQuery.rdf.dump
1148      */
1149     dump: function (options) {
1150       var triples = $.map(this.matches, function (match) {
1151         return match.triples;
1152       });
1153       options = $.extend({ namespaces: this.databank.namespaces, base: this.databank.base }, options || {});
1154       return $.rdf.dump(triples, options);
1155     },
1156 
1157     /**
1158      * Either returns the item specified by the argument or turns the {@link jQuery.rdf} object into an array. This mirrors the <a href="http://docs.jquery.com/Core/get">jQuery#get</a> method.
1159      * @param {Integer} [num] The number of the item to be returned.
1160      * @returns {Object[]|Object} Returns either a single Object representing variable bindings or an array of such.
1161      * @example
1162      * $('html').rdf()
1163      *   .where('?person a foaf:Person')
1164      *   .get(0)
1165      *   .subject
1166      *   .value;
1167      */
1168     get: function (num) {
1169       return (num === undefined) ? $.makeArray(this) : this[num];
1170     },
1171 
1172     /**
1173      * Iterates over the matches held by the {@link jQuery.rdf} object and performs a function on each of them. This mirrors the <a href="http://docs.jquery.com/Core/each">jQuery#each</a> method.
1174      * @param {Function} callback A function that is called for each match on the {@link jQuery.rdf} object. Within the function, <code>this</code> is set to the object representing the variable bindings. The function can take up to three parameters:
1175      * <dl>
1176      *   <dt>i</dt><dd>The index of the match amongst the other matches.</dd>
1177      *   <dt>bindings</dt><dd>An object representing the variable bindings for the match, the same as <code>this</code>.</dd>
1178      *   <dt>triples</dt><dd>An array of {@link jQuery.rdf.triple}s associated with the particular match.</dd>
1179      * </dl>
1180      * @returns {jQuery.rdf} The {@link jQuery.rdf} object.
1181      * @see jQuery.rdf#map
1182      * @example
1183      * var rdf = $('html').rdf()
1184      *   .where('?photo dc:creator ?creator')
1185      *   .where('?creator foaf:img ?photo')
1186      *   .each(function () {
1187      *     photos.push(this.photo.value);
1188      *   });
1189      */
1190     each: function (callback) {
1191       $.each(this.matches, function (i, match) {
1192         callback.call(match.bindings, i, match.bindings, match.triples);
1193       });
1194       return this;
1195     },
1196 
1197     /**
1198      * Iterates over the matches held by the {@link jQuery.rdf} object and creates a new {@link jQuery} object that holds the result of applying the passed function to each one. This mirrors the <a href="http://docs.jquery.com/Traversing/map">jQuery#map</a> method.
1199      * @param {Function} callback A function that is called for each match on the {@link jQuery.rdf} object. Within the function, <code>this</code> is set to the object representing the variable bindings. The function can take up to three parameters and should return some kind of value:
1200      * <dl>
1201      *   <dt>i</dt><dd>The index of the match amongst the other matches.</dd>
1202      *   <dt>bindings</dt><dd>An object representing the variable bindings for the match, the same as <code>this</code>.</dd>
1203      *   <dt>triples</dt><dd>An array of {@link jQuery.rdf.triple}s associated with the particular match.</dd>
1204      * </dl>
1205      * @returns {jQuery} A jQuery object holding the results of the function for each of the matches on the original {@link jQuery.rdf} object.
1206      * @example
1207      * var photos = $('html').rdf()
1208      *   .where('?photo dc:creator ?creator')
1209      *   .where('?creator foaf:img ?photo')
1210      *   .map(function () {
1211      *     return this.photo.value;
1212      *   });
1213      */
1214     map: function (callback) {
1215       return $($.map(this.matches, function (match, i) {
1216         // in the callback, "this" is the bindings, and the arguments are swapped from $.map()
1217         return callback.call(match.bindings, i, match.bindings, match.triples);
1218       }));
1219     },
1220 
1221     /**
1222      * Returns a {@link jQuery} object that wraps this {@link jQuery.rdf} object.
1223      * @returns {jQuery}
1224      */
1225     jquery: function () {
1226       return $(this);
1227     }
1228   };
1229 
1230   $.rdf.fn.init.prototype = $.rdf.fn;
1231 
1232   $.rdf.gleaners = [];
1233   $.rdf.parsers = {};
1234 
1235   /**
1236    * Dumps the triples passed as the first argument into a format that can be shown to the user or sent to a server.
1237    * @param {jQuery.rdf.triple[]} triples An array (or {@link jQuery} object) of {@link jQuery.rdf.triple}s.
1238    * @param {Object} [options] Options that control the format of the dump.
1239    * @param {String} [options.format='application/json'] The mime type of the format of the dump. The supported formats are:
1240    * <table>
1241    *   <tr><th>mime type</th><th>description</th></tr>
1242    *   <tr>
1243    *     <td><code>application/json</code></td>
1244    *     <td>An <a href="http://n2.talis.com/wiki/RDF_JSON_Specification">RDF/JSON</a> object</td>
1245    *   </tr>
1246    *   <tr>
1247    *     <td><code>application/rdf+xml</code></td>
1248    *     <td>An DOMDocument node holding XML in <a href="http://www.w3.org/TR/rdf-syntax-grammar/">RDF/XML syntax</a></td>
1249    *   </tr>
1250    *   <tr>
1251    *     <td><code>text/turtle</code></td>
1252    *     <td>A String holding a representation of the RDF in <a href="http://www.w3.org/TeamSubmission/turtle/">Turtle syntax</a></td>
1253    *   </tr>
1254    * </table>
1255    * @param {Object} [options.namespaces={}] A set of namespace bindings used when mapping resource URIs to CURIEs or QNames (particularly in a RDF/XML serialisation).
1256    * @param {boolean} [options.serialize=false] If true, rather than creating an Object, the function will return a string which is ready to display or send to a server.
1257    * @param {boolean} [options.indent=false] If true, the serialised (RDF/XML) output has indentation added to it to make it more readable.
1258    * @returns {Object|String} The alternative representation of the triples.
1259    */
1260   $.rdf.dump = function (triples, options) {
1261     var opts = $.extend({}, $.rdf.dump.defaults, options || {}),
1262       format = opts.format,
1263       serialize = opts.serialize,
1264       dump, parser, parsers;
1265     parser = $.rdf.parsers[format];
1266     if (parser === undefined) {
1267       parsers = [];
1268       for (p in $.rdf.parsers) {
1269         parsers.push(p);
1270       }
1271       throw "Unrecognised dump format: " + format + ". Expected one of " + parsers.join(", ");
1272     }
1273     dump = parser.dump(triples, opts);
1274     return serialize ? parser.serialize(dump) : dump;
1275   };
1276 
1277   $.rdf.dump.defaults = {
1278     format: 'application/json',
1279     serialize: false,
1280     indent: false,
1281     namespaces: {}
1282   }
1283 
1284   /**
1285    * Gleans RDF triples from the nodes held by the {@link jQuery} object, puts them into a {@link jQuery.rdf.databank} and returns a {@link jQuery.rdf} object that allows you to query and otherwise manipulate them. The mechanism for gleaning RDF triples from the web page depends on the rdfQuery modules that have been included. The core version of rdfQuery doesn't support any gleaners; other versions support a RDFa gleaner, and there are some modules available for common microformats.
1286    * @methodOf jQuery#
1287    * @name jQuery#rdf
1288    * @param {Function} [callback] A callback function that is called every time a triple is gleaned from the page. Within the function, <code>this</code> is set to the triple that has been located. The function can take up to two parameters:
1289    * <dl>
1290    *   <dt>node</dt><dd>The node on which the triple has been found; should be the same as <code>this.source</code>.</dd>
1291    *   <dt>triple</dt><dd>The triple that's been found; the same as <code>this</code>.</dd>
1292    * </dl>
1293    * The callback should return the triple or triples that should be added to the databank. This enables you to filter, extend or modify the contents of the databank itself, should you wish to.
1294    * @returns {jQuery.rdf} An empty query over the triples stored within the page.
1295    * @example $('#content').rdf().databank.dump();
1296    */
1297   $.fn.rdf = function (callback) {
1298     var triples = [],
1299       callback = callback || function () { return this; };
1300     if ($(this)[0] && $(this)[0].nodeType === 9) {
1301       return $(this).children('*').rdf(callback);
1302     } else if ($(this).length > 0) {
1303       triples = $(this).map(function (i, elem) {
1304         return $.map($.rdf.gleaners, function (gleaner) {
1305           return gleaner.call($(elem), { callback: callback });
1306         });
1307       });
1308       return $.rdf({ triples: triples, namespaces: $(this).xmlns() });
1309     } else {
1310       return $.rdf();
1311     }
1312   };
1313 
1314   $.extend($.expr[':'], {
1315 
1316     about: function (a, i, m) {
1317       var j = $(a),
1318         resource = m[3] ? j.safeCurie(m[3]) : null,
1319         isAbout = false;
1320       $.each($.rdf.gleaners, function (i, gleaner) {
1321         isAbout = gleaner.call(j, { about: resource });
1322         if (isAbout) {
1323           return null;
1324         }
1325       });
1326       return isAbout;
1327     },
1328 
1329     type: function (a, i, m) {
1330       var j = $(a),
1331         type = m[3] ? j.curie(m[3]) : null,
1332         isType = false;
1333       $.each($.rdf.gleaners, function (i, gleaner) {
1334         if (gleaner.call(j, { type: type })) {
1335           isType = true;
1336           return null;
1337         }
1338       });
1339       return isType;
1340     }
1341 
1342   });
1343 
1344   /**
1345    * <p>Creates a new jQuery.rdf.databank object. This should be invoked as a method rather than constructed using new; indeed you will not usually want to generate these objects directly, but manipulate them through a {@link jQuery.rdf} object.</p>
1346    * @class Represents a triplestore, holding a bunch of {@link jQuery.rdf.triple}s.
1347    * @param {(String|jQuery.rdf.triple)[]} [triples=[]] An array of triples to store in the databank.
1348    * @param {Object} [options] Initialisation of the databank.
1349    * @param {Object} [options.namespaces] An object representing a set of namespace bindings used when interpreting the CURIEs in strings representing triples. Rather than passing this in when you construct the {@link jQuery.rdf.databank} instance, you will usually want to use the {@link jQuery.rdf.databank#prefix} method.
1350    * @param {String|jQuery.uri} [options.base] The base URI used to interpret any relative URIs used within the strings representing triples.
1351    * @returns {jQuery.rdf.databank} The newly-created databank.
1352    * @see jQuery.rdf
1353    */
1354   $.rdf.databank = function (triples, options) {
1355     return new $.rdf.databank.fn.init(triples, options);
1356   };
1357 
1358   $.rdf.databank.fn = $.rdf.databank.prototype = {
1359     init: function (triples, options) {
1360       var i;
1361       triples = triples || [];
1362       options = options || {};
1363       this.id = databankID();
1364       databanks[this.id] = this;
1365       if (options.union === undefined) {
1366         this.queries = {};
1367         this.tripleStore = [];
1368         this.subjectIndex = {};
1369         this.propertyIndex = {};
1370         this.objectIndex = {};
1371         this.baseURI = options.base || $.uri.base();
1372         this.namespaces = $.extend({}, options.namespaces || {});
1373         for (i = 0; i < triples.length; i += 1) {
1374           this.add(triples[i]);
1375         }
1376       } else {
1377         this.union = options.union;
1378       }
1379       return this;
1380     },
1381     
1382     /**
1383      * Sets or returns the base URI of the {@link jQuery.rdf.databank}.
1384      * @param {String|jQuery.uri} [base]
1385      * @returns A {@link jQuery.uri} if no base URI is specified, otherwise returns this {@link jQuery.rdf.databank} object.
1386      * @see jQuery.rdf#base
1387      */
1388     base: function (base) {
1389       if (this.union === undefined) {
1390         if (base === undefined) {
1391           return this.baseURI;
1392         } else {
1393           this.baseURI = base;
1394           return this;
1395         }
1396       } else if (base === undefined) {
1397         return this.union[0].base();
1398       } else {
1399         $.each(this.union, function (i, databank) {
1400           databank.base(base);
1401         });
1402         return this;
1403       }
1404     },
1405 
1406     /**
1407      * Sets or returns a namespace binding on the {@link jQuery.rdf.databank}.
1408      * @param {String} [prefix]
1409      * @param {String} [namespace]
1410      * @returns {Object|jQuery.uri|jQuery.rdf} If no prefix or namespace is specified, returns an object providing all namespace bindings on the {@link jQuery.rdf#databank}. If a prefix is specified without a namespace, returns the {@link jQuery.uri} associated with that prefix. Otherwise returns this {@link jQuery.rdf} object after setting the namespace binding.
1411      * @see jQuery.rdf#prefix
1412      */
1413     prefix: function (prefix, uri) {
1414       var namespaces = {};
1415       if (this.union === undefined) {
1416         if (prefix === undefined) {
1417           return this.namespaces;
1418         } else if (uri === undefined) {
1419           return this.namespaces[prefix];
1420         } else {
1421           this.namespaces[prefix] = uri;
1422           return this;
1423         }
1424       } else if (uri === undefined) {
1425         $.each(this.union, function (i, databank) {
1426           $.extend(namespaces, databank.prefix());
1427         });
1428         if (prefix === undefined) {
1429           return namespaces;
1430         } else {
1431           return namespaces[prefix];
1432         }
1433       } else {
1434         $.each(this.union, function (i, databank) {
1435           databank.prefix(prefix, uri);
1436         });
1437         return this;
1438       }
1439     },
1440 
1441     /**
1442      * Adds a triple to the {@link jQuery.rdf.databank} or another {@link jQuery.rdf.databank} object to create a union.
1443      * @param {String|jQuery.rdf.triple|jQuery.rdf.databank} triple The triple or {@link jQuery.rdf.databank} object to be added to this one. If the triple is a {@link jQuery.rdf.databank} object, the two databanks are unioned together. If the triple is a string, it's parsed as a {@link jQuery.rdf.triple}.
1444      * @param {Object} [options]
1445      * @param {Object} [options.namespaces] An object representing a set of namespace bindings used to interpret CURIEs within the triple. Defaults to the namespace bindings defined on the {@link jQuery.rdf.databank}.
1446      * @param {String|jQuery.uri} [options.base] The base URI used to interpret any relative URIs used within the triple. Defaults to the base URI defined on the {@link jQuery.rdf.databank}.
1447      * @param {Integer} [options.depth] The number of links to traverse to gather more information about the subject, property and object of the triple.
1448      * @returns {jQuery.rdf.databank} This {@link jQuery.rdf.databank} object.
1449      * @see jQuery.rdf#add
1450      */
1451     add: function (triple, options) {
1452       var base = (options && options.base) || this.base(),
1453         namespaces = $.extend({}, this.prefix(), (options && options.namespaces) || {}),
1454         depth = (options && options.depth) || $.rdf.databank.defaults.depth,
1455         proxy = (options && options.proxy) || $.rdf.databank.defaults.proxy,
1456         databank;
1457       if (triple === this) {
1458         return this;
1459       } else if (triple.subjectIndex !== undefined) {
1460         // merging two databanks
1461         if (this.union === undefined) {
1462           databank = $.rdf.databank(undefined, { union: [this, triple] });
1463           return databank;
1464         } else {
1465           this.union.push(triple);
1466           return this;
1467         }
1468       } else {
1469         if (typeof triple === 'string') {
1470           triple = $.rdf.triple(triple, { namespaces: namespaces, base: base, source: triple });
1471         }
1472         if (this.union === undefined) {
1473           if (this.subjectIndex[triple.subject] === undefined) {
1474             this.subjectIndex[triple.subject] = [];
1475             if (depth > 0 && triple.subject.type === 'uri') {
1476               this.load(triple.subject.value, { depth: depth - 1, proxy: proxy });
1477             }
1478           }
1479           if (this.propertyIndex[triple.property] === undefined) {
1480             this.propertyIndex[triple.property] = [];
1481             if (depth > 0) {
1482               this.load(triple.property.value, { depth: depth - 1, proxy: proxy });
1483             }
1484           }
1485           if ($.inArray(triple, this.subjectIndex[triple.subject]) === -1) {
1486             this.tripleStore.push(triple);
1487             this.subjectIndex[triple.subject].push(triple);
1488             this.propertyIndex[triple.property].push(triple);
1489             if (triple.object.type === 'uri' || triple.object.type === 'bnode') {
1490               if (this.objectIndex[triple.object] === undefined) {
1491                 this.objectIndex[triple.object] = [];
1492                 if (depth > 0 && triple.object.type === 'uri') {
1493                   this.load(triple.object.value, { depth: depth - 1, proxy: proxy });
1494                 }
1495               }
1496               this.objectIndex[triple.object].push(triple);
1497             }
1498             addToDatabankQueries(this, triple);
1499           }
1500         } else {
1501           $.each(this.union, function (i, databank) {
1502             databank.add(triple);
1503           });
1504         }
1505         return this;
1506       }
1507     },
1508 
1509     /**
1510      * Removes a triple from the {@link jQuery.rdf.databank}.
1511      * @param {String|jQuery.rdf.triple} triple The triple to be removed.
1512      * @param {Object} [options]
1513      * @param {Object} [options.namespaces] An object representing a set of namespace bindings used to interpret any CURIEs within the triple. Defaults to the namespace bindings defined on the {@link jQuery.rdf.databank}.
1514      * @param {String|jQuery.uri} [options.base] The base URI used to interpret any relative URIs used within the triple. Defaults to the base URI defined on the {@link jQuery.rdf.databank}.
1515      * @returns {jQuery.rdf.databank} The {@link jQuery.rdf.databank} object itself.
1516      * @see jQuery.rdf#remove
1517      */
1518     remove: function (triple, options) {
1519       var base = (options && options.base) || this.base(),
1520         namespaces = $.extend({}, this.prefix(), (options && options.namespaces) || {}),
1521         striples, ptriples, otriples,
1522         databank;
1523       if (typeof triple === 'string') {
1524         triple = $.rdf.triple(triple, { namespaces: namespaces, base: base, source: triple });
1525       }
1526       this.tripleStore.splice($.inArray(triple, this.tripleStore), 1);
1527       striples = this.subjectIndex[triple.subject];
1528       if (striples !== undefined) {
1529         striples.splice($.inArray(triple, striples), 1);
1530       }
1531       ptriples = this.propertyIndex[triple.property];
1532       if (ptriples !== undefined) {
1533         ptriples.splice($.inArray(triple, ptriples), 1);
1534       }
1535       if (triple.object.type === 'uri' || triple.object.type === 'bnode') {
1536         otriples = this.objectIndex[triple.object];
1537         if (otriples !== undefined) {
1538           otriples.splice($.inArray(triple, otriples), 1);
1539         }
1540       }
1541       removeFromDatabankQueries(this, triple);
1542       return this;
1543     },
1544 
1545     /**
1546      * Creates a new databank containing all the triples in this {@link jQuery.rdf.databank} except those in the {@link jQuery.rdf.databank} passed as the argument.
1547      * @param {jQuery.rdf.databank} data The other {@link jQuery.rdf.databank}
1548      * @returns {jQuery.rdf.databank} A new {@link jQuery.rdf.databank} containing the triples in this {@link jQuery.rdf.databank} except for those in the data parameter.
1549      * @example
1550      * var old = $('html').rdf().databank;
1551      * ...some processing occurs...
1552      * var new = $('html').rdf().databank;
1553      * var added = new.except(old);
1554      * var removed = old.except(new);
1555      */
1556     except: function (data) {
1557       var store = data.subjectIndex,
1558         diff = [];
1559       $.each(this.subjectIndex, function (s, ts) {
1560         var ots = store[s];
1561         if (ots === undefined) {
1562           diff = diff.concat(ts);
1563         } else {
1564           $.each(ts, function (i, t) {
1565             if ($.inArray(t, ots) === -1) {
1566               diff.push(t);
1567             }
1568           });
1569         }
1570       });
1571       return $.rdf.databank(diff);
1572     },
1573 
1574     /**
1575      * Provides a {@link jQuery} object containing the triples held in this {@link jQuery.rdf.databank}.
1576      * @returns {jQuery} A {@link jQuery} object containing {@link jQuery.rdf.triple} objects.
1577      */
1578     triples: function () {
1579       var s, triples = [];
1580       if (this.union === undefined) {
1581         triples = this.tripleStore;
1582       } else {
1583         $.each(this.union, function (i, databank) {
1584           triples = triples.concat(databank.triples().get());
1585         });
1586         triples = unique(triples);
1587       }
1588       return $(triples);
1589     },
1590 
1591     /**
1592      * Tells you how many triples the databank contains.
1593      * @returns {Integer} The number of triples in the {@link jQuery.rdf.databank}.
1594      * @example $('html').rdf().databank.size();
1595      */
1596     size: function () {
1597       return this.triples().length;
1598     },
1599 
1600     /**
1601      * Provides <a href="http://n2.talis.com/wiki/Bounded_Descriptions_in_RDF#Simple_Concise_Bounded_Description">simple concise bounded descriptions</a> of the resources that are passed in the argument. This mirrors the <a href="http://www.w3.org/TR/rdf-sparql-query/#describe">DESCRIBE</a> form in SPARQL.
1602      * @param {(String|jQuery.rdf.resource)[]} resources An array that can contain strings, {@link jQuery.rdf.resource}s or a mixture of the two.
1603      * @returns {jQuery} A {@link jQuery} object holding the {@link jQuery.rdf.triple}s that describe the listed resources.
1604      * @see jQuery.rdf#describe
1605      */
1606     describe: function (resources) {
1607       var i, r, t, rhash = {}, triples = [];
1608       while (resources.length > 0) {
1609         r = resources.pop();
1610         if (rhash[r] === undefined) {
1611           if (r.value === undefined) {
1612             r = $.rdf.resource(r);
1613           }
1614           if (this.subjectIndex[r] !== undefined) {
1615             for (i = 0; i < this.subjectIndex[r].length; i += 1) {
1616               t = this.subjectIndex[r][i];
1617               triples.push(t);
1618               if (t.object.type === 'bnode') {
1619                 resources.push(t.object);
1620               }
1621             }
1622           }
1623           if (this.objectIndex[r] !== undefined) {
1624             for (i = 0; i < this.objectIndex[r].length; i += 1) {
1625               t = this.objectIndex[r][i];
1626               triples.push(t);
1627               if (t.subject.type === 'bnode') {
1628                 resources.push(t.subject);
1629               }
1630             }
1631           }
1632           rhash[r] = true;
1633         }
1634       }
1635       return unique(triples);
1636     },
1637 
1638     /**
1639      * Dumps the triples in the databank into a format that can be shown to the user or sent to a server.
1640      * @param {Object} [options] Options that control the formatting of the triples. See {@link jQuery.rdf.dump} for details.
1641      * @returns {Object|Node|String}
1642      * @see jQuery.rdf.dump
1643      */
1644     dump: function (options) {
1645       options = $.extend({ namespaces: this.namespaces, base: this.base }, options || {});
1646       return $.rdf.dump(this.triples(), options);
1647     },
1648 
1649     /**
1650      * Loads some data into the databank.
1651      * @param {Node|Object|String} data If the data is a string and starts with 'http://' then it's taken to be a URI and data is loaded from that URI via the proxy specified in the options. If it doesn't start with 'http://' then it's taken to be a serialized version of some format capable of representing RDF, parsed and interpreted. If the data is a node, it's interpreted to be an <a href="http://www.w3.org/TR/rdf-syntax-grammar/">RDF/XML syntax</a> document and will be parsed as such. Otherwise, it's taken to be a <a href="http://n2.talis.com/wiki/RDF_JSON_Specification">RDF/JSON</a> object.
1652      * @param {Object} opts Options governing the loading of the data.
1653      * @param {String} [opts.format] The mime type of the format the data is in, particularly useful if you're supplying the data as a string. If unspecified, the data will be sniffed to see if it might be HTML, RDF/XML, RDF/JSON or Turtle.
1654      * @param {boolean} [opts.async=true] When loading data from a URI, this determines whether it will be done synchronously or asynchronously.
1655      * @param {Function} [opts.success] When loading data from a URI, a function that will be called after the data is successfully loaded.
1656      * @param {Function} [opts.error] When loading data from a URI, a function that will be called if there's an error when accessing the URI.
1657      * @param {String} [opts.proxy='http://www.jenitennison.com/rdfquery/proxy.php'] The URI for a server-side proxy through which the data can be accessed. This does not have to be hosted on the same server as this Javascript, the HTML page or the remote data. The proxy must accept id, url and depth parameters and respond with some Javascript that will invoke the {@link jQuery.rdf.databank.load} function. <a href="http://code.google.com/p/rdfquery/source/browse/#svn/trunk/proxies">Example proxies</a> that do the right thing are available. If you are intending to use this facility a lot, please do not use the default proxy.
1658      * @param {integer} [opts.depth=0] Triggers recursive loading of located resources, to the depth specified. This is useful for automatically populating a databank with linked data.
1659      * @returns {jQuery.rdf.databank} The {@link jQuery.rdf.databank} itself.
1660      * @see jQuery.rdf#load
1661      */
1662     load: function (data, opts) {
1663       var i, triples, url, script, parser, docElem,
1664         format = (opts && opts.format),
1665         async = (opts && opts.async) || $.rdf.databank.defaults.async,
1666         success = (opts && opts.success) || $.rdf.databank.defaults.success,
1667         error = (opts && opts.error) || $.rdf.databank.defaults.error,
1668         proxy = (opts && opts.proxy) || $.rdf.databank.defaults.proxy,
1669         depth = (opts && opts.depth) || $.rdf.databank.defaults.depth;
1670       url = (typeof data === 'string' && data.substring(1, 7) === 'http://') ? $.uri(data) : data;
1671       if (url.scheme) {
1672         if (!queue(this, url, { success: success, error: error })) {
1673           script = '<script type="text/javascript" src="' + proxy + '?id=' + this.id + '&depth=' + depth + '&url=' + encodeURIComponent(url.resolve('').toString()) + '"></script>';
1674           if (async) {
1675             setTimeout("$('head').append('" + script + "')", 0);
1676           } else {
1677             $('head').append(script);
1678           }
1679         }
1680         return this;
1681       } else {
1682         if (format === undefined) {
1683           if (typeof data === 'string') {
1684             if (data.substring(0, 1) === '{') {
1685               format = 'application/json';
1686             } else if (data.substring(0, 14) === '<!DOCTYPE html' || data.substring(0, 5) === '<html') {
1687               format = 'application/xhtml+xml';
1688             } else if (data.substring(0, 5) === '<?xml' || data.substring(0, 8) === '<rdf:RDF') {
1689               format = 'application/rdf+xml';
1690             } else {
1691               format = 'text/turtle';
1692             }
1693           } else if (data.documentElement || data.ownerDocument) {
1694             docElem = data.documentElement ? data.documentElement : data.ownerDocument.documentElement;
1695             if (docElem.nodeName === 'html') {
1696               format = 'application/xhtml+xml';
1697             } else {
1698               format = 'application/rdf+xml';
1699             }
1700           } else {
1701             format = 'application/json';
1702           }
1703         }
1704         parser = $.rdf.parsers[format];
1705         if (typeof data === 'string') {
1706           data = parser.parse(data);
1707         }
1708         triples = parser.triples(data);
1709         for (i = 0; i < triples.length; i += 1) {
1710           this.add(triples[i], opts);
1711         }
1712         return this;
1713       }
1714     },
1715 
1716     /**
1717      * Provides a string representation of the databank which simply specifies how many triples it contains.
1718      * @returns {String}
1719      */
1720     toString: function () {
1721       return '[Databank with ' + this.size() + ' triples]';
1722     }
1723   };
1724 
1725   $.rdf.databank.fn.init.prototype = $.rdf.databank.fn;
1726   
1727   $.rdf.databank.defaults = {
1728     parse: false,
1729     async: true,
1730     success: null,
1731     error: null,
1732     depth: 0,
1733     proxy: 'http://www.jenitennison.com/rdfquery/proxy.php'
1734   };
1735   
1736   $.rdf.databank.load = function (id, url, doc, opts) {
1737     if (doc !== undefined) {
1738       databanks[id].load(doc, opts);
1739     }
1740     dequeue(databanks[id], url, (doc === undefined) ? 'error' : 'success', opts);
1741   };
1742 
1743   /**
1744    * <p>Creates a new jQuery.rdf.pattern object. This should be invoked as a method rather than constructed using new; indeed you will not usually want to generate these objects directly, since they are automatically created from strings where necessary, such as by {@link jQuery.rdf#where}.</p>
1745    * @class Represents a pattern that may or may not match a given {@link jQuery.rdf.triple}.
1746    * @param {String|jQuery.rdf.resource|jQuery.rdf.blank} subject The subject pattern, or a single string that defines the entire pattern. If the subject is specified as a string, it can be a fixed resource (<code><<var>uri</var>></code> or <code><var>curie</var></code>), a blank node (<code>_:<var>id</var></code>) or a variable placeholder (<code>?<var>name</var></code>).
1747    * @param {String|jQuery.rdf.resource} [property] The property pattern. If the property is specified as a string, it can be a fixed resource (<code><<var>uri</var>></code> or <code><var>curie</var></code>) or a variable placeholder (<code>?<var>name</var></code>).
1748    * @param {String|jQuery.rdf.resource|jQuery.rdf.blank|jQuery.rdf.literal} [value] The value pattern. If the property is specified as a string, it can be a fixed resource (<code><<var>uri</var>></code> or <code><var>curie</var></code>), a blank node (<code>_:<var>id</var></code>), a literal (<code>"<var>value</var>"</code>) or a variable placeholder (<code>?<var>name</var></code>).
1749    * @param {Object} [options] Initialisation of the pattern.
1750    * @param {Object} [options.namespaces] An object representing a set of namespace bindings used when interpreting the CURIEs in the subject, property and object.
1751    * @param {String|jQuery.uri} [options.base] The base URI used to interpret any relative URIs used within the subject, property and object.
1752    * @param {boolean} [options.optional]
1753    * @returns {jQuery.rdf.pattern} The newly-created pattern.
1754    * @throws {String} Errors if any of the strings are not in a recognised format.
1755    * @example pattern = $.rdf.pattern('?person', $.rdf.type, 'foaf:Person', { namespaces: { foaf: "http://xmlns.com/foaf/0.1/" }});
1756    * @example 
1757    * pattern = $.rdf.pattern('?person a foaf:Person', { 
1758    *   namespaces: { foaf: "http://xmlns.com/foaf/0.1/" }, 
1759    *   optional: true 
1760    * });
1761    * @see jQuery.rdf#where
1762    * @see jQuery.rdf.resource
1763    * @see jQuery.rdf.blank
1764    * @see jQuery.rdf.literal
1765    */
1766   $.rdf.pattern = function (subject, property, object, options) {
1767     var pattern, m, optional;
1768     // using a two-argument version; first argument is a Turtle statement string
1769     if (object === undefined) {
1770       options = property || {};
1771       m = $.trim(subject).match(tripleRegex);
1772       if (m.length === 3 || (m.length === 4 && m[3] === '.')) {
1773         subject = m[0];
1774         property = m[1];
1775         object = m[2];
1776       } else {
1777         throw "Bad Pattern: Couldn't parse string " + subject;
1778       }
1779       optional = (options.optional === undefined) ? $.rdf.pattern.defaults.optional : options.optional;
1780     }
1781     if (memPattern[subject] && 
1782         memPattern[subject][property] && 
1783         memPattern[subject][property][object] && 
1784         memPattern[subject][property][object][optional]) {
1785       return memPattern[subject][property][object][optional];
1786     }
1787     pattern = new $.rdf.pattern.fn.init(subject, property, object, options);
1788     if (memPattern[pattern.subject] &&
1789         memPattern[pattern.subject][pattern.property] &&
1790         memPattern[pattern.subject][pattern.property][pattern.object] &&
1791         memPattern[pattern.subject][pattern.property][pattern.object][pattern.optional]) {
1792       return memPattern[pattern.subject][pattern.property][pattern.object][pattern.optional];
1793     } else {
1794       if (memPattern[pattern.subject] === undefined) {
1795         memPattern[pattern.subject] = {};
1796       }
1797       if (memPattern[pattern.subject][pattern.property] === undefined) {
1798         memPattern[pattern.subject][pattern.property] = {};
1799       }
1800       if (memPattern[pattern.subject][pattern.property][pattern.object] === undefined) {
1801         memPattern[pattern.subject][pattern.property][pattern.object] = {};
1802       }
1803       memPattern[pattern.subject][pattern.property][pattern.object][pattern.optional] = pattern;
1804       return pattern;
1805     }
1806   };
1807 
1808   $.rdf.pattern.fn = $.rdf.pattern.prototype = {
1809     init: function (s, p, o, options) {
1810       var opts = $.extend({}, $.rdf.pattern.defaults, options);
1811       /**
1812        * The placeholder for the subject of triples matching against this pattern.
1813        * @type String|jQuery.rdf.resource|jQuery.rdf.blank
1814        */
1815       this.subject = s.toString().substring(0, 1) === '?' ? s : subject(s, opts);
1816       /**
1817        * The placeholder for the property of triples matching against this pattern.
1818        * @type String|jQuery.rdf.resource
1819        */
1820       this.property = p.toString().substring(0, 1) === '?' ? p : property(p, opts);
1821       /**
1822        * The placeholder for the object of triples matching against this pattern.
1823        * @type String|jQuery.rdf.resource|jQuery.rdf.blank|jQuery.rdf.literal
1824        */
1825       this.object = o.toString().substring(0, 1) === '?' ? o : object(o, opts);
1826       /**
1827        * Whether the pattern should only optionally match against the triple
1828        * @type boolean
1829        */
1830       this.optional = opts.optional;
1831       return this;
1832     },
1833 
1834     /**
1835      * Creates a new {@link jQuery.rdf.pattern} with any variable placeholders within this one's subject, property or object filled in with values from the bindings passed as the argument.
1836      * @param {Object} bindings An object holding the variable bindings to be used to replace any placeholders in the pattern. These bindings are of the type held by the {@link jQuery.rdf} object.
1837      * @returns {jQuery.rdf.pattern} A new {@link jQuery.rdf.pattern} object.
1838      * @example
1839      * pattern = $.rdf.pattern('?thing a ?class');
1840      * // pattern2 matches all triples that indicate the classes of this page. 
1841      * pattern2 = pattern.fill({ thing: $.rdf.resource('<>') });
1842      */
1843     fill: function (bindings) {
1844       var s = this.subject,
1845         p = this.property,
1846         o = this.object;
1847       if (typeof s === 'string' && bindings[s.substring(1)]) {
1848         s = bindings[s.substring(1)];
1849       }
1850       if (typeof p === 'string' && bindings[p.substring(1)]) {
1851         p = bindings[p.substring(1)];
1852       }
1853       if (typeof o === 'string' && bindings[o.substring(1)]) {
1854         o = bindings[o.substring(1)];
1855       }
1856       return $.rdf.pattern(s, p, o, { optional: this.optional });
1857     },
1858 
1859     /**
1860      * Creates a new Object holding variable bindings by matching the passed triple against this pattern.
1861      * @param {jQuery.rdf.triple} triple A {@link jQuery.rdf.triple} for this pattern to match against.
1862      * @returns {null|Object} An object containing the bindings of variables (as specified in this pattern) to values (as specified in the triple), or <code>null</code> if the triple doesn't match the pattern.
1863      * pattern = $.rdf.pattern('?thing a ?class');
1864      * bindings = pattern.exec($.rdf.triple('<> a foaf:Person', { namespaces: ns }));
1865      * thing = bindings.thing; // the resource for this page
1866      * class = bindings.class; // a resource for foaf:Person
1867      */
1868     exec: function (triple) {
1869       var binding = {};
1870       binding = testResource(triple.subject, this.subject, binding);
1871       if (binding === null) {
1872         return null;
1873       }
1874       binding = testResource(triple.property, this.property, binding);
1875       if (binding === null) {
1876         return null;
1877       }
1878       binding = testResource(triple.object, this.object, binding);
1879       return binding;
1880     },
1881 
1882     /**
1883      * Tests whether this pattern has any variable placeholders in it or not.
1884      * @returns {boolean} True if the pattern doesn't contain any variable placeholders.
1885      * @example
1886      * $.rdf.pattern('?thing a ?class').isFixed(); // false
1887      * $.rdf.pattern('<> a foaf:Person', { namespaces: ns }).isFixed(); // true
1888      */
1889     isFixed: function () {
1890       return typeof this.subject !== 'string' &&
1891         typeof this.property !== 'string' &&
1892         typeof this.object !== 'string';
1893     },
1894 
1895     /**
1896      * Creates a new triple based on the bindings passed to the pattern, if possible.
1897      * @param {Object} bindings An object holding the variable bindings to be used to replace any placeholders in the pattern. These bindings are of the type held by the {@link jQuery.rdf} object.
1898      * @returns {null|jQuery.rdf.triple} A new {@link jQuery.rdf.triple} object, or null if not all the variable placeholders in the pattern are specified in the bindings. The {@link jQuery.rdf.triple#source} of the generated triple is set to the string value of this pattern.
1899      * @example
1900      * pattern = $.rdf.pattern('?thing a ?class');
1901      * // triple is a new triple '<> a foaf:Person'
1902      * triple = pattern.triple({ 
1903      *   thing: $.rdf.resource('<>'),
1904      *   class: $.rdf.resource('foaf:Person', { namespaces: ns }) 
1905      * });
1906      */
1907     triple: function (bindings) {
1908       var t = this;
1909       if (!this.isFixed()) {
1910         t = this.fill(bindings);
1911       }
1912       if (t.isFixed()) {
1913         return $.rdf.triple(t.subject, t.property, t.object, { source: this.toString() });
1914       } else {
1915         return null;
1916       }
1917     },
1918 
1919     /**
1920      * Returns a string representation of the pattern by concatenating the subject, property and object.
1921      * @returns {String}
1922      */
1923     toString: function () {
1924       return this.subject + ' ' + this.property + ' ' + this.object;
1925     }
1926   };
1927 
1928   $.rdf.pattern.fn.init.prototype = $.rdf.pattern.fn;
1929 
1930   $.rdf.pattern.defaults = {
1931     base: $.uri.base(),
1932     namespaces: {},
1933     optional: false
1934   };
1935 
1936   /**
1937    * <p>Creates a new jQuery.rdf.triple object. This should be invoked as a method rather than constructed using new; indeed you will not usually want to generate these objects directly, since they are automatically created from strings where necessary, such as by {@link jQuery.rdf#add}.</p>
1938    * @class Represents an RDF triple.
1939    * @param {String|jQuery.rdf.resource|jQuery.rdf.blank} subject The subject of the triple, or a single string that defines the entire triple. If the subject is specified as a string, it can be a fixed resource (<code><<var>uri</var>></code> or <code><var>curie</var></code>) or a blank node (<code>_:<var>id</var></code>).
1940    * @param {String|jQuery.rdf.resource} [property] The property pattern. If the property is specified as a string, it must be a fixed resource (<code><<var>uri</var>></code> or <code><var>curie</var></code>).
1941    * @param {String|jQuery.rdf.resource|jQuery.rdf.blank|jQuery.rdf.literal} [value] The value pattern. If the property is specified as a string, it can be a fixed resource (<code><<var>uri</var>></code> or <code><var>curie</var></code>), a blank node (<code>_:<var>id</var></code>), or a literal (<code>"<var>value</var>"</code>).
1942    * @param {Object} [options] Initialisation of the triple.
1943    * @param {Object} [options.namespaces] An object representing a set of namespace bindings used when interpreting the CURIEs in the subject, property and object.
1944    * @param {String|jQuery.uri} [options.base] The base URI used to interpret any relative URIs used within the subject, property and object.
1945    * @returns {jQuery.rdf.triple} The newly-created triple.
1946    * @throws {String} Errors if any of the strings are not in a recognised format.
1947    * @example pattern = $.rdf.triple('<>', $.rdf.type, 'foaf:Person', { namespaces: { foaf: "http://xmlns.com/foaf/0.1/" }});
1948    * @example 
1949    * pattern = $.rdf.triple('<> a foaf:Person', { 
1950    *   namespaces: { foaf: "http://xmlns.com/foaf/0.1/" }
1951    * });
1952    * @see jQuery.rdf#add
1953    * @see jQuery.rdf.resource
1954    * @see jQuery.rdf.blank
1955    * @see jQuery.rdf.literal
1956    */
1957   $.rdf.triple = function (subject, property, object, options) {
1958     var triple, graph, m;
1959     // using a two-argument version; first argument is a Turtle statement string
1960     if (object === undefined) {
1961       options = property;
1962       m = $.trim(subject).match(tripleRegex);
1963       if (m.length === 3 || (m.length === 4 && m[3] === '.')) {
1964         subject = m[0];
1965         property = m[1];
1966         object = m[2];
1967       } else {
1968         throw "Bad Triple: Couldn't parse string " + subject;
1969       }
1970     }
1971     graph = (options && options.graph) || '';
1972     if (memTriple[graph] &&
1973         memTriple[graph][subject] &&
1974         memTriple[graph][subject][property] &&
1975         memTriple[graph][subject][property][object]) {
1976       return memTriple[graph][subject][property][object];
1977     }
1978     triple = new $.rdf.triple.fn.init(subject, property, object, options);
1979     graph = triple.graph || '';
1980     if (memTriple[graph] &&
1981         memTriple[graph][triple.subject] &&
1982         memTriple[graph][triple.subject][triple.property] &&
1983         memTriple[graph][triple.subject][triple.property][triple.object]) {
1984       return memTriple[graph][triple.subject][triple.property][triple.object];
1985     } else {
1986       if (memTriple[graph] === undefined) {
1987         memTriple[graph] = {};
1988       }
1989       if (memTriple[graph][triple.subject] === undefined) {
1990         memTriple[graph][triple.subject] = {};
1991       }
1992       if (memTriple[graph][triple.subject][triple.property] === undefined) {
1993         memTriple[graph][triple.subject][triple.property] = {};
1994       }
1995       memTriple[graph][triple.subject][triple.property][triple.object] = triple;
1996       return triple;
1997     }
1998   };
1999 
2000   $.rdf.triple.fn = $.rdf.triple.prototype = {
2001     init: function (s, p, o, options) {
2002       var opts;
2003       opts = $.extend({}, $.rdf.triple.defaults, options);
2004       /**
2005        * The subject of the triple.
2006        * @type jQuery.rdf.resource|jQuery.rdf.blank
2007        */
2008       this.subject = subject(s, opts);
2009       /**
2010        * The property of the triple.
2011        * @type jQuery.rdf.resource
2012        */
2013       this.property = property(p, opts);
2014       /**
2015        * The object of the triple.
2016        * @type jQuery.rdf.resource|jQuery.rdf.blank|jQuery.rdf.literal
2017        */
2018       this.object = object(o, opts);
2019       /**
2020        * (Experimental) The named graph the triple belongs to.
2021        * @type jQuery.rdf.resource|jQuery.rdf.blank
2022        */
2023       this.graph = opts.graph === undefined ? undefined : subject(opts.graph, opts);
2024       /**
2025        * The source of the triple, which might be a node within the page (if the RDF is generated from the page) or a string holding the pattern that generated the triple.
2026        */
2027       this.source = opts.source;
2028       return this;
2029     },
2030 
2031     /**
2032      * Always returns true for triples.
2033      * @see jQuery.rdf.pattern#isFixed
2034      */
2035     isFixed: function () {
2036       return true;
2037     },
2038 
2039     /**
2040      * Always returns this triple.
2041      * @see jQuery.rdf.pattern#triple
2042      */
2043     triple: function (bindings) {
2044       return this;
2045     },
2046 
2047     /**
2048      * Returns a <a href="http://n2.talis.com/wiki/RDF_JSON_Specification">RDF/JSON</a> representation of this triple.
2049      * @returns {Object}
2050      */
2051     dump: function () {
2052       var e = {},
2053         s = this.subject.value.toString(),
2054         p = this.property.value.toString();
2055       e[s] = {};
2056       e[s][p] = this.object.dump();
2057       return e;
2058     },
2059 
2060     /**
2061      * Returns a string representing this triple in Turtle format.
2062      * @returns {String}
2063      */
2064     toString: function () {
2065       return this.subject + ' ' + this.property + ' ' + this.object + ' .';
2066     }
2067   };
2068 
2069   $.rdf.triple.fn.init.prototype = $.rdf.triple.fn;
2070 
2071   $.rdf.triple.defaults = {
2072     base: $.uri.base(),
2073     source: [document],
2074     namespaces: {}
2075   };
2076 
2077   /**
2078    * <p>Creates a new jQuery.rdf.resource object. This should be invoked as a method rather than constructed using new; indeed you will not usually want to generate these objects directly, since they are automatically created from strings where necessary, such as by {@link jQuery.rdf#add}.</p>
2079    * @class Represents an RDF resource.
2080    * @param {String|jQuery.uri} value The value of the resource. If it's a string it must be in the format <code><<var>uri</var>></code> or <code><var>curie</var></code>.
2081    * @param {Object} [options] Initialisation of the resource.
2082    * @param {Object} [options.namespaces] An object representing a set of namespace bindings used when interpreting the CURIE specifying the resource.
2083    * @param {String|jQuery.uri} [options.base] The base URI used to interpret any relative URIs used within the URI specifying the resource.
2084    * @returns {jQuery.rdf.resource} The newly-created resource.
2085    * @throws {String} Errors if the string is not in a recognised format.
2086    * @example thisPage = $.rdf.resource('<>');
2087    * @example foaf.Person = $.rdf.resource('foaf:Person', { namespaces: ns });
2088    * @see jQuery.rdf.pattern
2089    * @see jQuery.rdf.triple
2090    * @see jQuery.rdf.blank
2091    * @see jQuery.rdf.literal
2092    */
2093   $.rdf.resource = function (value, options) {
2094     var resource;
2095     if (memResource[value]) {
2096       return memResource[value];
2097     }
2098     resource = new $.rdf.resource.fn.init(value, options);
2099     if (memResource[resource]) {
2100       return memResource[resource];
2101     } else {
2102       memResource[resource] = resource;
2103       return resource;
2104     }
2105   };
2106 
2107   $.rdf.resource.fn = $.rdf.resource.prototype = {
2108     /**
2109      * Always fixed to 'uri' for resources.
2110      * @type String
2111      */
2112     type: 'uri',
2113     /**
2114      * The URI for the resource.
2115      * @type jQuery.rdf.uri
2116      */
2117     value: undefined,
2118 
2119     init: function (value, options) {
2120       var m, prefix, uri, opts;
2121       if (typeof value === 'string') {
2122         m = uriRegex.exec(value);
2123         opts = $.extend({}, $.rdf.resource.defaults, options);
2124         if (m !== null) {
2125           this.value = $.uri.resolve(m[1].replace(/\\>/g, '>'), opts.base);
2126         } else if (value.substring(0, 1) === ':') {
2127           uri = opts.namespaces[''];
2128           if (uri === undefined) {
2129             throw "Malformed Resource: No namespace binding for default namespace in " + value;
2130           } else {
2131             this.value = $.uri.resolve(uri + value.substring(1));
2132           }
2133         } else if (value.substring(value.length - 1) === ':') {
2134           prefix = value.substring(0, value.length - 1);
2135           uri = opts.namespaces[prefix];
2136           if (uri === undefined) {
2137             throw "Malformed Resource: No namespace binding for prefix " + prefix + " in " + value;
2138           } else {
2139             this.value = $.uri.resolve(uri);
2140           }
2141         } else {
2142           try {
2143             this.value = $.curie(value, { namespaces: opts.namespaces });
2144           } catch (e) {
2145             throw "Malformed Resource: Bad format for resource " + e;
2146           }
2147         }
2148       } else {
2149         this.value = value;
2150       }
2151       return this;
2152     }, // end init
2153 
2154     /**
2155      * Returns a <a href="http://n2.talis.com/wiki/RDF_JSON_Specification">RDF/JSON</a> representation of this triple.
2156      * @returns {Object}
2157      */
2158     dump: function () {
2159       return {
2160         type: 'uri',
2161         value: this.value.toString()
2162       };
2163     },
2164 
2165     /**
2166      * Returns a string representing this resource in Turtle format.
2167      * @returns {String}
2168      */
2169     toString: function () {
2170       return '<' + this.value + '>';
2171     }
2172   };
2173 
2174   $.rdf.resource.fn.init.prototype = $.rdf.resource.fn;
2175 
2176   $.rdf.resource.defaults = {
2177     base: $.uri.base(),
2178     namespaces: {}
2179   };
2180 
2181   /**
2182    * A {@link jQuery.rdf.resource} for rdf:type
2183    * @constant
2184    * @type jQuery.rdf.resource
2185    */
2186   $.rdf.type = $.rdf.resource('<' + rdfNs + 'type>');
2187   /**
2188    * A {@link jQuery.rdf.resource} for rdfs:label
2189    * @constant
2190    * @type jQuery.rdf.resource
2191    */
2192   $.rdf.label = $.rdf.resource('<' + rdfsNs + 'label>');
2193   /**
2194    * A {@link jQuery.rdf.resource} for rdf:first
2195    * @constant
2196    * @type jQuery.rdf.resource
2197    */
2198   $.rdf.first = $.rdf.resource('<' + rdfNs + 'first>');
2199   /**
2200    * A {@link jQuery.rdf.resource} for rdf:rest
2201    * @constant
2202    * @type jQuery.rdf.resource
2203    */
2204   $.rdf.rest = $.rdf.resource('<' + rdfNs + 'rest>');
2205   /**
2206    * A {@link jQuery.rdf.resource} for rdf:nil
2207    * @constant
2208    * @type jQuery.rdf.resource
2209    */
2210   $.rdf.nil = $.rdf.resource('<' + rdfNs + 'nil>');
2211   /**
2212    * A {@link jQuery.rdf.resource} for rdf:subject
2213    * @constant
2214    * @type jQuery.rdf.resource
2215    */
2216   $.rdf.subject = $.rdf.resource('<' + rdfNs + 'subject>');
2217   /**
2218    * A {@link jQuery.rdf.resource} for rdf:property
2219    * @constant
2220    * @type jQuery.rdf.resource
2221    */
2222   $.rdf.property = $.rdf.resource('<' + rdfNs + 'property>');
2223   /**
2224    * A {@link jQuery.rdf.resource} for rdf:object
2225    * @constant
2226    * @type jQuery.rdf.resource
2227    */
2228   $.rdf.object = $.rdf.resource('<' + rdfNs + 'object>');
2229 
2230   /**
2231    * <p>Creates a new jQuery.rdf.blank object. This should be invoked as a method rather than constructed using new; indeed you will not usually want to generate these objects directly, since they are automatically created from strings where necessary, such as by {@link jQuery.rdf#add}.</p>
2232    * @class Represents an RDF blank node.
2233    * @param {String} value A representation of the blank node in the format <code>_:<var>id</var></code> or <code>[]</code> (which automatically creates a new blank node with a unique ID).
2234    * @returns {jQuery.rdf.blank} The newly-created blank node.
2235    * @throws {String} Errors if the string is not in a recognised format.
2236    * @example newBlank = $.rdf.blank('[]');
2237    * @example identifiedBlank = $.rdf.blank('_:fred');
2238    * @see jQuery.rdf.pattern
2239    * @see jQuery.rdf.triple
2240    * @see jQuery.rdf.resource
2241    * @see jQuery.rdf.literal
2242    */
2243   $.rdf.blank = function (value) {
2244     var blank;
2245     if (memBlank[value]) {
2246       return memBlank[value];
2247     }
2248     blank = new $.rdf.blank.fn.init(value);
2249     if (memBlank[blank]) {
2250       return memBlank[blank];
2251     } else {
2252       memBlank[blank] = blank;
2253       return blank;
2254     }
2255   };
2256 
2257   $.rdf.blank.fn = $.rdf.blank.prototype = {
2258     /**
2259      * Always fixed to 'bnode' for blank nodes.
2260      * @type String
2261      */
2262     type: 'bnode',
2263     /**
2264      * The value of the blank node in the format <code>_:<var>id</var></code>
2265      * @type String
2266      */
2267     value: undefined,
2268     /**
2269      * The id of the blank node.
2270      * @type String
2271      */
2272     id: undefined,
2273 
2274     init: function (value) {
2275       if (value === '[]') {
2276         this.id = blankNodeID();
2277         this.value = '_:' + this.id;
2278       } else if (value.substring(0, 2) === '_:') {
2279         this.id = value.substring(2);
2280         this.value = value;
2281       } else {
2282         throw "Malformed Blank Node: " + value + " is not a legal format for a blank node";
2283       }
2284       return this;
2285     },
2286 
2287     /**
2288      * Returns a <a href="http://n2.talis.com/wiki/RDF_JSON_Specification">RDF/JSON</a> representation of this blank node.
2289      * @returns {Object}
2290      */
2291     dump: function () {
2292       return {
2293         type: 'bnode',
2294         value: this.value
2295       };
2296     },
2297 
2298     /**
2299      * Returns the value this blank node.
2300      * @returns {String}
2301      */
2302     toString: function () {
2303       return this.value;
2304     }
2305   };
2306 
2307   $.rdf.blank.fn.init.prototype = $.rdf.blank.fn;
2308 
2309   /**
2310    * <p>Creates a new jQuery.rdf.literal object. This should be invoked as a method rather than constructed using new; indeed you will not usually want to generate these objects directly, since they are automatically created from strings where necessary, such as by {@link jQuery.rdf#add}.</p>
2311    * @class Represents an RDF literal.
2312    * @param {String|boolean|Number} value Either the value of the literal or a string representation of it. If the datatype or lang options are specified, the value is taken as given. Otherwise, if it's a Javascript boolean or numeric value, it is interpreted as a value with a xsd:boolean or xsd:double datatype. In all other cases it's interpreted as a literal as defined in <a href="http://www.w3.org/TeamSubmission/turtle/#literal">Turtle syntax</a>.
2313    * @param {Object} [options] Initialisation options for the literal.
2314    * @param {String} [options.datatype] The datatype for the literal. This should be a safe CURIE; in other words, it can be in the format <code><var>uri</var></code> or <code>[<var>curie</var>]</code>. Must not be specified if options.lang is also specified.
2315    * @param {String} [options.lang] The language for the literal. Must not be specified if options.datatype is also specified.
2316    * @param {Object} [options.namespaces] An object representing a set of namespace bindings used when interpreting a CURIE in the datatype.
2317    * @param {String|jQuery.uri} [options.base] The base URI used to interpret a relative URI in the datatype.
2318    * @returns {jQuery.rdf.literal} The newly-created literal.
2319    * @throws {String} Errors if the string is not in a recognised format or if both options.datatype and options.lang are specified.
2320    * @example trueLiteral = $.rdf.literal(true);
2321    * @example numericLiteral = $.rdf.literal(5);
2322    * @example dateLiteral = $.rdf.literal('"2009-07-13"^^xsd:date', { namespaces: ns });
2323    * @see jQuery.rdf.pattern
2324    * @see jQuery.rdf.triple
2325    * @see jQuery.rdf.resource
2326    * @see jQuery.rdf.blank
2327    */
2328   $.rdf.literal = function (value, options) {
2329     var literal;
2330     if (memLiteral[value]) {
2331       return memLiteral[value];
2332     }
2333     literal = new $.rdf.literal.fn.init(value, options);
2334     if (memLiteral[literal]) {
2335       return memLiteral[literal];
2336     } else {
2337       memLiteral[literal] = literal;
2338       return literal;
2339     }
2340   };
2341 
2342   $.rdf.literal.fn = $.rdf.literal.prototype = {
2343     /**
2344      * Always fixed to 'literal' for literals.
2345      * @type String
2346      */
2347     type: 'literal',
2348     /**
2349      * The value of the literal as a string.
2350      * @type String
2351      */
2352     value: undefined,
2353     /**
2354      * The language of the literal, if it has one; otherwise undefined.
2355      * @type String
2356      */
2357     lang: undefined,
2358     /**
2359      * The datatype of the literal, if it has one; otherwise undefined.
2360      * @type jQuery.uri
2361      */
2362     datatype: undefined,
2363 
2364     init: function (value, options) {
2365       var
2366         m, datatype,
2367         opts = $.extend({}, $.rdf.literal.defaults, options);
2368       datatype = $.safeCurie(opts.datatype, { namespaces: opts.namespaces });
2369       if (opts.lang !== undefined && opts.datatype !== undefined && datatype.toString() !== (rdfNs + 'XMLLiteral')) {
2370         throw "Malformed Literal: Cannot define both a language and a datatype for a literal (" + value + ")";
2371       }
2372       if (opts.datatype !== undefined) {
2373         datatype = $.safeCurie(opts.datatype, { namespaces: opts.namespaces });
2374         $.extend(this, $.typedValue(value.toString(), datatype));
2375         if (datatype.toString() === rdfNs + 'XMLLiteral') {
2376           this.lang = opts.lang;
2377         }
2378       } else if (opts.lang !== undefined) {
2379         this.value = value.toString();
2380         this.lang = opts.lang;
2381       } else if (typeof value === 'boolean') {
2382         $.extend(this, $.typedValue(value.toString(), xsdNs + 'boolean'));
2383       } else if (typeof value === 'number') {
2384         $.extend(this, $.typedValue(value.toString(), xsdNs + 'double'));
2385       } else if (value === 'true' || value === 'false') {
2386         $.extend(this, $.typedValue(value, xsdNs + 'boolean'));
2387       } else if ($.typedValue.valid(value, xsdNs + 'integer')) {
2388         $.extend(this, $.typedValue(value, xsdNs + 'integer'));
2389       } else if ($.typedValue.valid(value, xsdNs + 'decimal')) {
2390         $.extend(this, $.typedValue(value, xsdNs + 'decimal'));
2391       } else if ($.typedValue.valid(value, xsdNs + 'double') &&
2392                  !/^\s*([\-\+]?INF|NaN)\s*$/.test(value)) {  // INF, -INF and NaN aren't valid literals in Turtle
2393         $.extend(this, $.typedValue(value, xsdNs + 'double'));
2394       } else {
2395         m = literalRegex.exec(value);
2396         if (m !== null) {
2397           this.value = (m[2] || m[4]).replace(/\\"/g, '"').replace(/\\n/g, '\n').replace(/\\t/g, '\t').replace(/\\r/g, '\r');
2398           if (m[9]) {
2399             datatype = $.rdf.resource(m[9], opts);
2400             $.extend(this, $.typedValue(this.value, datatype.value));
2401           } else if (m[7]) {
2402             this.lang = m[7];
2403           }
2404         } else {
2405           throw "Malformed Literal: Couldn't recognise the value " + value;
2406         }
2407       }
2408       return this;
2409     }, // end init
2410 
2411     /**
2412      * Returns a <a href="http://n2.talis.com/wiki/RDF_JSON_Specification">RDF/JSON</a> representation of this blank node.
2413      * @returns {Object}
2414      */
2415     dump: function () {
2416       var e = {
2417         type: 'literal',
2418         value: this.value.toString()
2419       };
2420       if (this.lang !== undefined) {
2421         e.lang = this.lang;
2422       } else if (this.datatype !== undefined) {
2423         e.datatype = this.datatype.toString();
2424       }
2425       return e;
2426     },
2427     
2428     /**
2429      * Returns a string representing this resource in <a href="http://www.w3.org/TeamSubmission/turtle/#literal">Turtle format</a>.
2430      * @returns {String}
2431      */
2432     toString: function () {
2433       var val = '"' + this.value + '"';
2434       if (this.lang !== undefined) {
2435         val += '@' + this.lang;
2436       } else if (this.datatype !== undefined) {
2437         val += '^^<' + this.datatype + '>';
2438       }
2439       return val;
2440     }
2441   };
2442 
2443   $.rdf.literal.fn.init.prototype = $.rdf.literal.fn;
2444 
2445   $.rdf.literal.defaults = {
2446     base: $.uri.base(),
2447     namespaces: {},
2448     datatype: undefined,
2449     lang: undefined
2450   };
2451 
2452 })(jQuery);
2453