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