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