comparison examples/browser/web/js/jOWL.js @ 640:901803e1305f

First instance of audioDB browser code.
author mas01mj
date Thu, 08 Oct 2009 11:19:11 +0000
parents
children
comparison
equal deleted inserted replaced
639:2eaea1afd6b3 640:901803e1305f
1 /**
2 * jOWL - a jQuery plugin for traversing and visualizing OWL-DL documents.
3 * Creator - David Decraene
4 * Version 1.0
5 * Website:
6 * http://Ontologyonline.org
7 * Licensed under the MIT license
8 * http://www.opensource.org/licenses/mit-license.php
9 * Verified with JSLint
10 * http://www.jslint.com/
11 */
12
13 jOWL = window.jOWL = function( resource, options ){ return jOWL.getResource( resource, options ); };
14 jOWL.version = "1.0";
15
16 /** for debugging compatibility */
17 try { console.log('...'); } catch(e) { console = window.console = { log: function() {} } }
18 if ($.browser.opera && opera.postError) { console = window.console = { log : function(){opera.postError(arguments); } }; }
19
20
21
22 (function($){
23
24 /**
25 * if no param: @return string of main namespaces
26 * if 1 param: assume a documentElement, parse namespaces
27 * if prefix & URI: Bind prefix to namespace URI
28 */
29 jOWL.NS = function(prefix, URI){
30 if(!arguments.length)
31 { return "xmlns:"+jOWL.NS.owl.prefix+"='"+jOWL.NS.owl()+"' xmlns:"+jOWL.NS.rdf.prefix+"='"+jOWL.NS.rdf()+"' xmlns:"+jOWL.NS.rdfs.prefix+"='"+jOWL.NS.rdfs()+"' xmlns:"+jOWL.NS.xsd.prefix+" ='"+jOWL.NS.xsd()+"'";}
32
33 if(arguments.length == 1){
34 var attr = prefix.get(0).attributes;
35 for(var i=0;i<attr.length;i++){
36 var nn = attr[i].nodeName.split(':');
37 if(nn.length == 2){
38 if(attr[i].nodeValue == jOWL.NS.owl.URI){ jOWL.NS.owl.prefix = nn[1];}
39 else if(attr[i].nodeValue == jOWL.NS.rdf.URI){ jOWL.NS.rdf.prefix = nn[1];}
40 else if(attr[i].nodeValue == jOWL.NS.rdfs.URI){ jOWL.NS.rdfs.prefix = nn[1];}
41 else if(attr[i].nodeValue == jOWL.NS.xsd.URI){ jOWL.NS.xsd.prefix = nn[1];}
42 else { jOWL.NS(nn[1], attr[i].nodeValue);}
43 }
44 }
45 jOWL.namespace = prefix.xmlAttr('xml:base') || prefix.xmlAttr('xmlns');
46 return;
47 }
48 jOWL.NS[prefix] = function(element){
49 if(element){
50 return (arguments.callee.prefix == 'base') ? element : arguments.callee.prefix + ":" + element;
51 }
52 return arguments.callee.URI;
53 };
54 jOWL.NS[prefix].prefix = prefix;
55 jOWL.NS[prefix].URI = URI;
56 };
57
58 var __ = jOWL.NS;
59
60 /** set Main namespaces */
61 __("owl", "http://www.w3.org/2002/07/owl#");
62 __("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
63 __("rdfs", "http://www.w3.org/2000/01/rdf-schema#");
64 __("xsd", "http://www.w3.org/2001/XMLSchema#");
65
66 /** jQuery function additions for easy parsing of identities */
67 $.fn.extend({
68 /** Used for Opera compatibility when parsing xml attributes, nodeName must be checked, in contrast to native jquery call attr() */
69 xmlAttr : function(nodeName){
70 var t = this[0].attributes; if(!t){ return;}
71 for(var i =0;i<t.length;i++){
72 if(t[i].nodeName == nodeName){ return t[i].nodeValue;}
73 }
74 },
75 RDF_ID : function(match){
76 var res = this.xmlAttr(__.rdf('ID'));
77 if(!res){ return false;}
78 res = jOWL.resolveURI(res);
79 if(match){
80 return res.toLowerCase() == (jOWL.resolveURI(match.toString())).toLowerCase();}
81 return res;
82 },
83 RDF_Resource : function(match){
84 function getClassName(dom){
85 var cl = jOWL.Xpath(__.owl("Class"), dom);
86 if(cl.length == 1){ return new jOWL.Ontology.Class(cl).URI;}
87 return false;
88 }
89 if(!this.length){ return false;}
90 var rsrc = this.xmlAttr(__.rdf('resource'));
91 if(!rsrc){
92 var dom = this.get(0);
93 switch(dom.nodeName){
94 case __.rdfs("subClassOf"): rsrc = getClassName(dom); break;
95 case __.owl("disjointWith"): rsrc = getClassName(dom); break;
96 case __.owl("allValuesFrom"): rsrc = getClassName(dom); break;
97 case __.owl("someValuesFrom"): rsrc = getClassName(dom); break;
98 case __.owl("onProperty"):
99 var t = jOWL.Xpath(__.owl("ObjectProperty"), dom);
100 if(t.length === 0){ t = jOWL.Xpath(__.owl("DatatypeProperty"), dom);}
101 if(t.length === 0){ t = jOWL.Xpath(__.owl("FunctionalProperty"), dom);}
102 rsrc = t.xmlAttr(__.rdf('about')); break;
103 default: return false;
104 }
105 }
106 if(!rsrc){ return false;}
107 rsrc = jOWL.resolveURI(rsrc);
108 if(match){ return rsrc.toLowerCase() == (jOWL.resolveURI(match.toString())).toLowerCase();}
109 return rsrc;
110 },
111 RDF_About : function(match){
112 var res = this.xmlAttr(__.rdf('about'));
113 if(!res){ return false;}
114 res = jOWL.resolveURI(res);
115 if(match){
116 return res.toLowerCase() == (jOWL.resolveURI(match.toString())).toLowerCase();}
117 return res;
118 }
119 });
120
121 /** Check XPath implementation */
122 if( document.implementation.hasFeature("XPath", "3.0") ){
123 XMLDocument.prototype.selectNodes = function(cXPathString, xNode){
124 if( !xNode ){ xNode = this;}
125 var oNSResolver = this.createNSResolver(this.documentElement);
126 var aItems = this.evaluate(cXPathString, xNode, oNSResolver, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); var aResult = []; for( var i = 0; i < aItems.snapshotLength; i++){ aResult[i] = aItems.snapshotItem(i);}
127 return aResult;
128 };
129 Element.prototype.selectNodes = function(cXPathString){
130 if(this.ownerDocument.selectNodes) { return this.ownerDocument.selectNodes(cXPathString, this);}
131 else{throw "For XML Elements Only";}
132 };
133 XMLDocument.prototype.selectSingleNode = function(cXPathString, xNode){ if( !xNode ){ xNode = this;}
134 var xItems = this.selectNodes(cXPathString, xNode); if( xItems.length > 0 ){ return xItems[0];} else { return null;}
135 };
136 Element.prototype.selectSingleNode = function(cXPathString){
137 if(this.ownerDocument.selectSingleNode) { return this.ownerDocument.selectSingleNode(cXPathString, this);}
138 else{throw "For XML Elements Only";}
139 };
140 }
141
142 /** @return A jQuery array of xml elements */
143 jOWL.Xpath = function(selector, elem){
144 var node = null;
145 if(elem){ if(elem.each){ node = elem.get(0);} else { node = elem;} }
146 var arr = node ? node.selectNodes(selector) : jOWL.document.selectNodes(selector);
147 if($.browser.msie){ return $($.makeArray(arr));} return $(arr); //this is needed for IE, it returns a length of 1 on empty node array
148 };
149
150 /** @return a String array of class references */
151 jOWL.Xpath.classes = function(jnode){
152 var cl = [];
153 jOWL.Xpath(__.rdfs("subClassOf"), jnode)
154 .each(function(){
155 var res = $(this).RDF_Resource();
156 if(res){ cl.push(res);}
157 });
158
159 jOWL.Xpath(__.owl("intersectionOf")+"/"+__.owl("Class"), jnode)
160 .each(function(){
161 var p = $(this).RDF_About(); if(p){ cl.push(p);}
162 });
163 return cl;
164 };
165
166 /** Functions stored in jOWL.priv are intended for local access only, to avoid a closure function */
167 jOWL.priv = {
168 /** Arrray functions */
169 Array : {
170 isArray : function(array){
171 return Object.prototype.toString.call(array) === '[object Array]';
172 },
173 pushUnique : function(array, item){
174 if(jOWL.priv.Array.getIndex(array, item) === -1){ array.push(item); return true;}
175 return false;
176 },
177 getIndex : function(array, item){
178 for (var i=0; i<array.length; i++){ if(item == array[i]){ return i;} }
179 return -1;
180 },
181 /** Sorted array as input, returns the same array without duplicates. */
182 unique : function(array){
183 var result = []; var lastValue="";
184 for (var i=0; i<array.length; i++)
185 {
186 var curValue=array[i];
187 if(curValue != lastValue){ result[result.length] = curValue;}
188 lastValue=curValue;
189 }
190 return result;
191 }
192 }
193 };
194
195 /** Make values work with jOWL.Ontology.Array */
196 jOWL.Literal = function(value){
197 this.name = value;
198 };
199
200 /** Access to the owl:Ontology element, also the main coding namespace for ontology objects */
201 jOWL.Ontology = function(){
202 if(!(this instanceof arguments.callee)){ return new jOWL.Ontology();}
203 this.parse(jOWL.Xpath("/"+__.rdf("RDF")+"/"+__.owl("Ontology")));
204 return this;
205 };
206
207 /** 'superclass' for referencable ontology objects */
208 jOWL.Ontology.Thing = function(jnode){
209 this.parse(jnode);
210 };
211
212 jOWL.Ontology.Thing.prototype = {
213 jOWL : jOWL.version,
214 equals : function(id){
215 var URI = (typeof id == "string") ? jOWL.resolveURI(id) : id.URI;
216 return URI === this.URI;
217 },
218 /** Initialization */
219 parse : function(jnode){
220 if(!jnode.length){ return;}
221 var identifier;
222 if(typeof jnode == 'string'){
223 identifier = jnode;
224 jnode = $();
225 }
226 else {
227 identifier = jnode.RDF_ID() || jnode.RDF_About();
228 if(!identifier){identifier = "anonymousOntologyObject";
229 this.isAnonymous = true;
230 }
231 }
232 identifier = jOWL.resolveURI(identifier);
233 this.isExternal = jOWL.isExternal(identifier);
234 if(this.isExternal){this.baseURI = this.isExternal[0]; this.name = this.isExternal[1]; this.URI = this.baseURI+this.name;}
235 else { this.baseURI = jOWL.namespace; this.name = identifier; this.URI = this.name;}
236 this.jnode = jnode;
237 this.type = jnode.get(0).nodeName;
238 },
239 /** @return A jQuery array of elements matching the annotation (qualified name or annotation Property) */
240 annotations : function(annotation){
241 return jOWL.Xpath(annotation, this.jnode);
242 },
243 /** @return rdfs:comment annotations */
244 description : function(){
245 return $.map(this.annotations(__.rdfs('comment')), function(n){ return $(n).text();});
246 },
247 /**
248 @return Array of Arrays, where secondary array is of form: [0] = term (rdfs:label) , [1] = identifier, [2] = language; [3] = type of object
249 example:
250 [
251 ["bleu", "blue", "fr", "owl:Class"]
252 ]
253 */
254 terms : function(){
255 var terms = [], self = this;
256 if(jOWL.options.dictionary.addID && this.name != "anonymousOntologyObject"){ terms.push([this.name.beautify(), this.URI, jOWL.options.defaultlocale, this.type]);}
257 this.annotations(__.rdfs('label')).each(function(){
258 var lbl = $(this);
259 var locale = lbl.xmlAttr("xml:lang") || jOWL.options.defaultlocale;
260 var txt = lbl.text();
261 var match = false;
262 for(var i =0;i<terms.length;i++){
263 if(terms[i][0].toUpperCase() == txt.toUpperCase() && terms[i][2] == locale){ match = true;}
264 }
265 if(!match){ terms.push([lbl.text(), self.URI, locale, self.type]);}
266 });
267 return terms;
268 },
269 /** @return A representation name */
270 label : function(){
271 var label = false;
272 this.annotations(__.rdfs('label')).each(function(){
273 var $label = $(this);
274 if(jOWL.options.locale){
275 var lang = $label.xmlAttr('xml:lang') || jOWL.options.defaultlocale;
276 if(lang == jOWL.options.locale){ label = $label.text(); return false;}
277 } else { label = $label.text(); return false;}
278 });
279 if(label){ return label;}
280 if(this.name == "anonymousOntologyObject"){ return jOWL.Manchester(this) || "anonymous Object";}
281 if(jOWL.options.niceClassLabels && (this.isClass || this.isThing)){
282 return this.name.beautify();
283 }
284 return this.name;
285 },
286 /** Binds the Ontology element to the jQuery element for visual representation
287 * @return jQuery Element
288 */
289 bind : function(jqelem){
290 return jqelem.text(this.label()).attr('typeof', this.type).attr('title', this.URI);
291 }
292 };
293
294 jOWL.Ontology.prototype = jOWL.Ontology.Thing.prototype;
295
296 /** used for jOWL.Ontology.Individual.sourceof */
297 jOWL.priv.testObjectTarget = function(target, matchtarget){
298 if(target.isArray){
299 for(var i=0;i<target.length;i++){
300 if(jOWL.priv.testObjectTarget(target.get(i), matchtarget)){ return true;}
301 }
302 return false;
303 }
304 //if the target is a class, fetch individuals instead.
305 else if(target.isClass){
306 var a = target.individuals();
307 for(var i=0;i<a.length;i++){
308 if(a.get(i).URI == matchtarget){ return true;}
309 }
310 }
311 else if(target.URI == matchtarget){ return true;}
312 return false;
313 };
314
315 /** access to Individuals of the ontology*/
316 jOWL.Ontology.Individual = function(jnode, owlclass){
317 this.parse(jnode);
318 if(this.type == __.owl("Thing")){
319 var t = jOWL.Xpath(__.rdf('type'), this.jnode);
320 if(!t.length){ throw "unable to find a Class for the Individual "+this.name;}
321 this.Class = $(t[0]).RDF_Resource();
322 }
323 else {
324 this.Class = jOWL.resolveURI(jnode.get(0));
325 }
326 this.type = __.owl("Thing");
327 if(owlclass){ this.owlClass(owlclass);}
328 };
329
330 jOWL.Ontology.Individual.prototype = $.extend({}, jOWL.Ontology.Thing.prototype, {
331 isThing : true,
332 /** @return The owl:Class */
333 owlClass : function(owlclass){
334 if(owlclass){ jOWL.data(this.name, "class", owlclass);}
335 else {
336 var cl = jOWL.data(this.name, "class");
337 if(!cl){ cl = jOWL(this.Class); if(cl){ this.owlClass(cl);} }
338 return cl;
339 }
340 },
341 /** Access to restrictions */
342 sourceof : function(property, target, options){
343 options = $.extend({
344 inherited : true, // add restrictions specified on parents as well
345 transitive : true,
346 ignoreGenerics : false, //if a parent has an identical property, with another target 'Thing', skip that restriction
347 ignoreClasses : true,
348 valuesOnly : true
349 }, options);
350
351 var results = new jOWL.Ontology.Array();
352
353 this.jnode.children().filter(function(){return (this.prefix != __.rdfs.prefix && this.prefix != __.rdf.prefix && this.prefix != __.owl.prefix);})
354 .each(function(){
355 var restriction = new jOWL.Ontology.Restriction($(this));
356 var propertyMatch = property ? false : true;
357 var targetMatch = target ? false : true;
358
359 if(!propertyMatch){
360 if( property.isArray){ propertyMatch = property.contains(restriction.property);}
361 else { propertyMatch = (property.URI == restriction.property.URI);}
362 if(!propertyMatch){ return;}
363 }
364
365 if(!target){
366 if(options.transitive && restriction.property.isTransitive && !options.ignoreGenerics){
367 var rTarget = restriction.getTarget();
368 var transitives = rTarget.sourceof(restriction.property, null, options);
369 results.concat(transitives);
370 }
371 }
372 else {
373 if(restriction.property.isObjectProperty){
374 targetMatch = jOWL.priv.testObjectTarget(target, restriction.target);
375 if(!targetMatch && options.transitive && restriction.property.isTransitive){
376 var rTransitives = restriction.getTarget().sourceof(restriction.property, target, options);
377 if(rTransitives.length > 0){ targetMatch = true;}
378 }
379 }
380 else if(restriction.property.isDatatypeProperty){
381 targetMatch = restriction.property.assert(restriction.target, target);
382 }
383 else { targetMatch = (target == restriction.target);}
384 }
385 if(propertyMatch && targetMatch){ results.pushUnique(restriction);}
386
387 });
388 if(options.inherited){
389 var clRestrictions = this.owlClass().sourceof(property, target, options)
390 .each(function(){
391 //target can be a class, null, a duplicate individual...
392 var clRestr = this;
393 if(options.valuesOnly && clRestr.target === null){return;}
394 var clTarget = this.getTarget();
395 if(clTarget.isClass && options.ignoreClasses){ return;}
396
397 var containsProperty = false;
398 for(var i = 0;i<results.length;i++){
399 var restr = results.get(i);
400 if(restr.property.URI == clRestr.property.URI){
401 containsProperty = true;
402 if(!options.ignoreGenerics){
403 if(clRestr.target != restr.target){ results.pushUnique(clRestr);}
404 }
405 }
406 }
407 if(!containsProperty){ results.pushUnique(clRestr);}
408 });
409 }
410 return results;
411
412 },
413 localRestrictions : function(property, target){
414 return this.sourceof(property, target, {inherited : false, transitive : false });
415 },
416 /** Include generic will add transitivity reasoning */
417 valueRestrictions : function(includeGeneric){
418 return this.sourceof(null, null, {ignoreGenerics : !includeGeneric, valuesOnly : true });
419 }
420 });
421
422 /** jNode is of type owl:Restriction */
423 jOWL.Ontology.Restriction = function(jnode){
424
425 var jprop, prop, op, restrtype;
426
427 this.cachedTarget = null;
428
429 if(jnode.get(0).nodeName != __.owl("Restriction")){
430 this.property = jOWL(jOWL.resolveURI(jnode.get(0)), {type: "property"});
431 this.target = jnode.RDF_Resource() || jnode.text();
432 restrtype = "Individual";
433 }
434 else
435 {
436 jprop = jOWL.Xpath(__.owl("onProperty"), jnode);
437 prop = jprop.RDF_Resource(); if(!prop){ throw "no property found for the given owl:restriction";}
438 op = jprop.siblings();
439 restrtype = op.get(0).nodeName;
440 this.property = jOWL(prop, {type: "property"});
441 this.target = null; //string only
442 }
443
444 this.restriction = { minCard: false, maxCard : false, some: [], all : [], value : false };
445 this.type = jnode.get(0).nodeName;
446 this.isAnonymous = true;
447 this.isValueRestriction = (restrtype == __.owl('someValuesFrom') || restrtype == __.owl('allValuesFrom') || restrtype == __.owl('hasValue'));
448 this.isCardinalityRestriction = (restrtype == __.owl('cardinality') || restrtype == __.owl('maxCardinality') || restrtype == __.owl('minCardinality'));
449
450 if(!this.property || !restrtype){ throw "badly formed owl:restriction";}
451 switch(restrtype){
452 case __.owl('cardinality'): this.restriction.minCard = this.restriction.maxCard = parseInt(op.text(), 10); break;
453 case __.owl('maxCardinality'): this.restriction.maxCard = parseInt(op.text(), 10); break;
454 case __.owl('minCardinality'): this.restriction.minCard = parseInt(op.text(), 10); break;
455 case __.owl('hasValue'): var res = op.RDF_Resource(); if(res){ this.target = res;} break;
456 }
457 if(this.property.isObjectProperty){
458 if(this.isCardinalityRestriction && this.property.range){ this.target = this.property.range;}
459 else if(this.isValueRestriction){
460 var t = op.RDF_Resource();
461 if(t == "anonymousOntologyObject"){//nested groupings, anonymous classes
462 this.cachedTarget = new jOWL.Ontology.Class(jOWL.Xpath(__.owl("Class"), op));
463 }
464 this.target = t;
465 }
466 }
467
468 var suffix = this.target || this.restrtype;
469 this.name = this.property.name+'#'+suffix;
470 return this;
471 };
472
473 jOWL.Ontology.Restriction.prototype = {
474 jOWL : jOWL.version,
475 isRestriction : true,
476 bind : function(){return null;},
477 merge : function(crit){
478 if(this.isCardinalityRestriction && crit.isValueRestriction ){ this.target = crit.target; return true;}
479 else if(this.isValueRestriction && crit.isCardinalityRestriction){
480 switch(crit.restrtype){
481 case __.owl('cardinality'): this.restriction.minCard = this.restriction.maxCard = crit.restriction.minCard; return true;
482 case __.owl('minCardinality'): this.restriction.minCard = crit.restriction.minCard; return true;
483 case __.owl('maxCardinality'): this.restriction.maxCard = crit.restriction.maxCard; return true;
484 }
485 }
486 return false;
487 },
488 getTarget : function(){
489 if(!this.target){ return jOWL('Thing');}
490 if(this.cachedTarget){ return this.cachedTarget;}
491 this.cachedTarget = (this.property.isObjectProperty) ? jOWL(this.target) : new jOWL.Literal(this.target);
492 return this.cachedTarget;
493 },
494 equals : function(restr){
495 if(!restr.isRestriction){ return false;}
496 if(this.property.URI == restr.property.URI){
497 if(this.target == 'anonymousOntologyObject'){return false;}//oneof lists etc unsupported right now
498 if(this.target && this.target === restr.target){ return true;}
499 }
500 return false;
501 }
502 };
503
504 /** Datatype Logic, local functions */
505 jOWL.priv.Dt = function(options){
506 this.settings = $.extend({base: null, pattern : null, assert: function(b){return true;}, match: function(a, b){return true;}}, options);
507 this.base = jOWL.Ontology.Datatype[this.settings.base];
508 };
509
510 jOWL.priv.Dt.prototype = {
511 sanitize : function(b){
512 if(this.settings.sanitize){ return this.settings.sanitize(b);}
513 if(this.base && this.base.sanitize){ return this.base.sanitize(b);}
514 },
515 assert : function(b){
516 var v = this.sanitize(b); if(v !== undefined){ b = v;}
517 if(this.base && !this.base.assert(b)){ return false;}
518 if(this.settings.pattern && !this.settings.pattern.test(b)){ return false;}
519 return this.settings.assert(b);
520 },
521 match : function(a, b){
522 var v = this.sanitize(b); if(v !== undefined){ b = v;}
523 if(!this.assert(b)){ return false;}
524 if(this.base && !this.base.match(a, b)){ return false;}
525 return this.settings.match(a, b);
526 }
527 };
528
529 jOWL.Ontology.Datatype = function(URI, options){
530 jOWL.Ontology.Datatype[URI] = new jOWL.priv.Dt(options);
531 };
532
533 /** Datatype Definitions */
534 jOWL.Ontology.Datatype(__.xsd()+"integer", {sanitize : function(x){return parseInt(x, 10);}, assert : function(x){ return Math.round(x) == x;}, match : function(a, b){
535 var check = parseInt(a, 10);
536 if(!isNaN(check)){ return check == b;}
537 var arr = a.split('&&');
538 for(var i=0;i<arr.length;i++){ arr[i] = b+arr[i];}
539 try {
540 return eval(arr.join(' && '));
541 } catch(e){ return false;}
542 } });
543 jOWL.Ontology.Datatype(__.xsd()+"positiveInteger", {base: __.xsd()+"integer", assert : function(x){ return x > 0;} });
544 jOWL.Ontology.Datatype(__.xsd()+"decimal", {base: __.xsd()+"integer" });
545 jOWL.Ontology.Datatype(__.xsd()+"float", {base: __.xsd()+"integer" });
546 jOWL.Ontology.Datatype(__.xsd()+"double", {base: __.xsd()+"integer" });
547 jOWL.Ontology.Datatype(__.xsd()+"negativeInteger", {base: __.xsd()+"integer", assert : function(x){ return x < 0;} });
548 jOWL.Ontology.Datatype(__.xsd()+"nonNegativeInteger", {base: __.xsd()+"integer", assert : function(x){ return x >= 0;} });
549 jOWL.Ontology.Datatype(__.xsd()+"nonPositiveInteger", {base: __.xsd()+"integer", assert : function(x){ return x <= 0;} });
550 jOWL.Ontology.Datatype(__.xsd()+"string");
551
552 var URIPattern = /^([a-z0-9+.\-]+):(?:\/\/(?:((?:[a-z0-9-._~!$&'()*+,;=:]|%[0-9A-F]{2})*)@)?((?:[a-z0-9-._~!$&'()*+,;=]|%[0-9A-F]{2})*)(?::(\d*))?(\/(?:[a-z0-9-._~!$&'()*+,;=:@\/]|%[0-9A-F]{2})*)?|(\/?(?:[a-z0-9-._~!$&'()*+,;=:@]|%[0-9A-F]{2})+(?:[a-z0-9-._~!$&'()*+,;=:@\/]|%[0-9A-F]{2})*)?)(?:\?((?:[a-z0-9-._~!$&'()*+,;=:\/?@]|%[0-9A-F]{2})*))?(?:#((?:[a-z0-9-._~!$&'()*+,;=:\/?@]|%[0-9A-F]{2})*))?$/i;
553
554 jOWL.Ontology.Datatype(__.xsd()+"anyURI", {base: __.xsd()+"string", pattern : URIPattern });
555 jOWL.Ontology.Datatype(__.xsd()+"boolean", {sanitize : function(x){
556 if(typeof x == 'boolean'){ return x;}
557 if(x == 'true'){ return true;}
558 if(x == 'false'){ return false;}
559 }, assert : function(x){
560 return typeof x == 'boolean';
561 }, match: function(a, b){
562 if(a === "false"){ a = false;}
563 if(a === "true"){ a = true;}
564 return (a === b);
565 }});
566
567 /** 'superclass' for Properties */
568 jOWL.Ontology.Property = function(jnode){
569 var r = this.parseProperty(jnode);
570 if(r){ return r;}
571 };
572
573 jOWL.Ontology.Property.prototype = $.extend({}, jOWL.Ontology.Thing.prototype,{
574 isProperty : true,
575 parseProperty : function(jnode){
576 if(!jnode || typeof jnode == 'string'){
577 this.domain = this.range = null;
578 this.parse(jnode);
579 return;
580 }
581 if(jOWL.options.cacheProperties && jOWL.indices.IDs){
582 var res = jnode.RDF_ID() || jnode.RDF_About();
583 var c = jOWL.index('property').get(res);
584 if(c){ return c;}
585 }
586 this.parse(jnode);
587 this.domain= $(this.jnode.get(0).selectSingleNode(__.rdfs('domain'))).RDF_Resource();
588 this.range = $(this.jnode.get(0).selectSingleNode(__.rdfs('range'))).RDF_Resource();
589 }
590 });
591
592 /** access to Datatype properties */
593 jOWL.Ontology.DatatypeProperty = function(jnode){
594 var r = this.parseProperty(jnode);
595 if(r){ return r;}
596 if(this.type == __.owl("AnnotationProperty")){ this.range = __.xsd()+"string";}
597 };
598
599 jOWL.Ontology.DatatypeProperty.prototype = $.extend({}, jOWL.Ontology.Thing.prototype, jOWL.Ontology.Property.prototype, {
600 isDatatypeProperty : true,
601 /** check datatype values against this */
602 assert : function(targetValue, value){
603 var self = this;
604 var dt = jOWL.Ontology.Datatype[this.range];
605 if(!dt){
606 console.log(this.range+" datatype reasoning not implemented");
607 return true;
608 }
609 if(value === undefined){ return dt.assert(targetValue);}
610 else {return dt.match(value, targetValue);}
611 }
612 });
613
614 /** access to Object properties */
615 jOWL.Ontology.ObjectProperty = function(jnode){
616 var r = this.parseProperty(jnode);
617 if(r){ return r;}
618 var self = this;
619 jOWL.Xpath(__.rdf('type'), this.jnode).each(function(){
620 if($(this).RDF_Resource() == __.owl()+"TransitiveProperty"){ self.isTransitive = true;}
621 });
622 if(this.jnode.get(0).nodeName == __.owl("TransitiveProperty")){ self.isTransitive = true;}
623 };
624
625 jOWL.Ontology.ObjectProperty.prototype = $.extend({}, jOWL.Ontology.Thing.prototype, jOWL.Ontology.Property.prototype, {
626 isObjectProperty : true
627 });
628
629 /** access to an owl:Class */
630 jOWL.Ontology.Class = function(jnode){
631 this.parse(jnode);
632 };
633
634 /** @return jOWL Array of Restrictions */
635 jOWL.Xpath.restrictions = function(jnode){
636 var result = new jOWL.Ontology.Array();
637 jOWL.Xpath(__.rdfs("subClassOf")+"/"+__.owl("Restriction"), jnode)
638 .add(jOWL.Xpath(__.owl("intersectionOf")+"/"+__.owl("Restriction"), jnode))
639 .each(function(){
640 result.push(new jOWL.Ontology.Restriction($(this)));
641 });
642 return result;
643 };
644
645 /** Internal Use */
646 jOWL.Ontology.Intersection = function(jnode){
647 var self = this;
648 this.jnode = jnode;
649 this._arr = [];
650 this.URI = this.jnode.parent().RDF_ID();
651 this.matches = {};
652 jOWL.Xpath(__.owl("Restriction"), jnode).each(function(){
653 var restr = new jOWL.Ontology.Restriction($(this));
654 if(restr.isValueRestriction){self._arr.push(restr);}
655 });
656 jOWL.Xpath(__.owl('Class'), jnode).each(function(){
657 var uri = $(this).RDF_About();
658 if(uri){ self._arr.push(jOWL(uri));}
659 });
660 };
661
662 jOWL.Ontology.Intersection.prototype = {
663 isIntersection : true,
664 jOWL : jOWL.version,
665 match : function(id, cls, clRestr){
666 if(id == this.URI){ return false;}
667 if(this.matches[id] !== undefined){ return this.matches[id]; }//local cache
668
669 for(var i =0;i<this._arr.length;i++){
670 var entry = this._arr[i];
671 var m = false;
672 if(entry.isRestriction){
673 clRestr.each(function(){
674 if(this.equals(entry)){ m = true; return false;}
675 });
676 if(!m) {
677 this.matches[id] = false;
678 return false;
679 }
680 } else if(entry.isClass){
681 for(var j = 0;j<cls.length;j++){
682 if(entry.equals(cls[j])){m = true; break;}
683 var it = jOWL.index('ID')[cls[j]];
684 if(it){
685 var narr = jOWL.Xpath.classes(jOWL.index('ID')[cls[j]].jnode);
686 for (var z=0;z<narr.length ; z++){
687 if(entry.equals(narr[z])){m = true; break;}
688 }
689 }
690 }
691 if(!m){
692 this.matches[id] = false;
693 return false;
694 }
695 }
696 }
697 this.matches[id] = true;
698 return this.matches[id];
699 },
700 equals : function(isect){
701 if(!isect.isIntersection){ return false;}
702 for(var i =0;i<this._arr.length;i++){
703 var match = false;
704 for(var j = 0;j<isect._arr.length;j++){
705 if(isect._arr[j].equals(this._arr[i])){ match = true;}
706 }
707 if(!match){ return false;}
708 }
709 return true;
710 }
711 };
712
713 jOWL.Ontology.Class.prototype = $.extend({}, jOWL.Ontology.Thing.prototype, {
714 isClass : true,
715 /** @return A jOWL.Ontology.Array of individuals for this class & its subclasses */
716 individuals : function(){
717 var arr = new jOWL.Ontology.Array();
718 var q = new jOWL.SPARQL_DL("Type(?x, "+this.name+")").execute({async: false, onComplete: function(r){ arr = r.jOWLArray("?x");} });
719 return arr;
720 },
721 /** @return A jOWL.Ontology.Array of individuals (if oneOf list) */
722 oneOf : function(){
723 var arr = new jOWL.Ontology.Array();
724 var oneOf = this.jnode.children().filter(function(){return this.tagName == __.owl("oneOf");});
725 oneOf.children().each(function(){
726 arr.push(jOWL($(this).RDF_About()));
727 });
728 return arr;
729 },
730 /** @return A jOWL.Ontology.Array of direct children */
731 children : function(){
732 var that = this;
733 var oChildren = jOWL.data(this.name, "children");
734 if(oChildren){ return oChildren;}
735 oChildren = new jOWL.Ontology.Array();
736 if(this.oneOf().length){return oChildren;}
737 var URI = this.URI;
738
739 for(x in jOWL.index('ID')){
740 if(x === this.URI){ continue;}
741 var node = jOWL.index('ID')[x];
742 if(!node.isClass){continue;}
743 var cls = jOWL.Xpath.classes(node.jnode); //direct subClasses
744 for(var i=0;i<cls.length;i++){
745 if(this.equals(cls[i])){
746 oChildren.push(node);
747 }
748 }
749 var clRestr = jOWL.Xpath.restrictions(node.jnode);
750 var intersections = jOWL.index("intersection")[URI];
751 if(intersections){
752 intersections.each(function(){//fully defined Subclasses
753 if(this.match(x, cls, clRestr)){oChildren.push(node);}
754 });
755 }
756 }
757 //an ObjectProperty mentions this as domain
758 jOWL.index("property").each(function(){
759 if(this.domain == that.name){
760 var nodes = jOWL.Xpath('//'+__.owl('onProperty')+'[@'+__.rdf('resource')+'="#'+this.name+'"]/parent::'+__.owl('Restriction')+'/..');
761 nodes.filter(function(){ return (this.nodeName == __.owl('intersectionOf') || this.nodeName == __.rdfs('subClassOf'));
762 }).each(function(){
763 var cl = jOWL($(this.selectSingleNode('parent::'+__.owl('Class'))));
764 if(!oChildren.contains(cl) && cl.name != that.name && cl.name !== undefined){ oChildren.push(cl);}
765 });
766 }
767 });
768 //filter out redundancies
769 oChildren.filter(function(){
770 this.hierarchy(false);
771 return (this.parents().contains(URI));
772 });
773 jOWL.data(this.name, "children", oChildren);
774 return oChildren;
775 },
776 setParents : function(parents){
777 jOWL.data(this.name, "parents", parents); return parents;
778 },
779 /** @return A jOWL.Ontology.Array of parents, includes redundancies, to exclude do a hierarchy search first.*/
780 parents : function(){
781 var self = this;
782 var oParents = jOWL.data(this.name, "parents");
783 if(oParents){ return oParents;}
784
785 var temp = [];
786
787 var cls = jOWL.Xpath.classes(this.jnode);
788 for(var i=0;i<cls.length;i++){ jOWL.priv.Array.pushUnique(temp, cls[i]);}
789
790 var restr = jOWL.Xpath.restrictions(this.jnode);
791 restr.each(function(){
792 if(this.property.domain && this.property.domain != self.name){ jOWL.priv.Array.pushUnique(temp, this.property.domain);
793 }
794 });
795
796 var iSectLoop = function(){
797 if(this.match(self.URI, cls, restr)){
798 jOWL.priv.Array.pushUnique(temp, this.URI);
799 }
800
801 };
802
803 if(jOWL.options.reason){
804 for(resource in jOWL.index('intersection')){
805 jOWL.index('intersection')[resource].each(iSectLoop);
806 }
807 }
808
809 oParents = new jOWL.Ontology.Array( jOWL.getXML(temp), true);
810 if(!oParents.length){ oParents.push(jOWL('Thing'));}
811 else if(oParents.length > 1){ oParents.filter(function(){return this.name != ('Thing');});} //Remove Thing reference if other parents exist
812 jOWL.data(this.name, "parents", oParents);
813 return oParents;
814 },
815 /** @return ancestors to the class in a jOWL.Ontology.Array */
816 ancestors : function(){
817 return this.hierarchy(false).flatindex;
818 },
819 /**
820 Constructs the entire (parent) hierarchy for a class
821 @return a jOWL.Ontology.Array containing top nodes (classes directly subsumed by 'owl:Thing')
822 @param addInverse add a variable invParents (jOWL.Ontology.Array of child references) to each node with exception of the leaves (original concept)
823 */
824 hierarchy : function(addInverse){
825 var endNodes = new jOWL.Ontology.Array();
826 var self = this;
827 endNodes.flatindex = new jOWL.Ontology.Array();
828
829 function URIARR(p_arr, obj){
830 var add = true;
831 if(!obj){ obj = {}; add = false;}
832 if(p_arr.each){
833 p_arr.each(function(){
834 if(obj[this.URI]){return;}
835 if(this.URI == __.owl()+'Thing'){ return;}
836 if(add){ obj[this.URI] = true;}
837 if(this.parents){ URIARR(this.parents(), obj);}
838 });
839 }
840 return obj;
841 }
842
843 function traverse(concept){
844 var parents = concept.parents();
845 if(parents.length == 1 && parents.contains(__.owl()+'Thing')){ endNodes.pushUnique(concept); return;}
846 else
847 {
848 var asso = jOWL.options.reason ? URIARR(parents) : {};
849 parents.filter(function(){ return (!asso[this.URI]);}); //throw out redundancies
850 parents.each(function(){
851 var item = endNodes.flatindex.pushUnique(this);
852 if(addInverse){
853 if(!item.invParents){ item.invParents = new jOWL.Ontology.Array();}
854 item.invParents.pushUnique(concept);
855 }
856 traverse(item);
857 });
858 concept.setParents(parents);
859 }
860 }
861
862 traverse(this);
863 return endNodes;
864
865 },
866 /**
867 @param level depth to fetch children, Default 5
868 @return jOWL array of classes that are descendant
869 */
870 descendants : function(level){
871 level = (typeof level == 'number') ? level : 5;
872 var oDescendants = jOWL.data(this.name, "descendants");
873 if(oDescendants && oDescendants.level >= level){ return oDescendants;}
874 oDescendants = new jOWL.Ontology.Array();
875 oDescendants.level = level;
876
877 function descend(concept, i){
878 if(i <= level){
879 i++;
880 var ch = concept.children();
881 oDescendants.concat(ch);
882 ch.each(function(item){ descend(item, i);});
883 }
884 }
885
886 descend(this, 1);
887 jOWL.data(this.name, "descendants", oDescendants);
888 return oDescendants;
889 },
890 /** @return jOWL.Array of Restrictions, target is an individual, not a class or undefined (unless includeAll is specified) - deprecated */
891 valueRestrictions : function(includeAll, array){
892 return this.sourceof(null, null, {ignoreClasses : !includeAll});
893 },
894 /**
895 get all restrictions that satisfy the arguments
896 @param property property or array of properties, or null
897 @param target class, individuals of array of them, or null
898 @return jOWL.Array of Restrictions
899 */
900 sourceof : function(property, target, options){
901 options = $.extend({
902 inherited : true, // add restrictions specified on parents as well
903 transitive : true, //expand on transitive relations too
904 ignoreGenerics : true, //if a parent has an identical property, with another target 'Thing', skip that restriction
905 ignoreClasses : false, //only individuals should return
906 valuesOnly : true //do not return valueless criteria
907 }, options);
908 var self = this;
909 var crit = jOWL.data(this.name, "sourceof");
910 var jnode = this.jnode;
911
912 if(!crit){
913 crit = new jOWL.Ontology.Array();
914 var arr = jOWL.Xpath(__.rdfs("subClassOf")+"/"+__.owl("Restriction"), jnode)
915 .add(jOWL.Xpath(__.owl("intersectionOf")+"/"+__.owl("Restriction"), jnode));
916 arr.each(function(index, entry){
917 var cr = new jOWL.Ontology.Restriction($(entry));
918 var dupe = false;
919 crit.each(function(item, i){
920 if(this.property.name == cr.property.name){ dupe = item;}
921 });
922 if(dupe){ if(!dupe.merge(cr)){ crit.push(cr);} }
923 else { crit.push(cr);}
924 });
925 jOWL.data(self.name, "sourceof", crit);
926 }
927 var results = new jOWL.Ontology.Array();
928
929 crit.each(function(){
930
931 var propertyMatch = property ? false : true;
932 var targetMatch = target ? false : true;
933
934 if(!propertyMatch){
935 if(property.isArray){ propertyMatch = property.contains(this.property);}
936 else { propertyMatch = (property.URI == this.property.URI);}
937 }
938
939 if(!target){
940 if(options.transitive && this.property.isTransitive){
941 var rTarget = this.getTarget();
942 var transitives = rTarget.sourceof(this.property, null, options);
943 results.concat(transitives);
944 }
945 }
946
947 if(!targetMatch && !this.target){
948 targetMatch = !options.valuesOnly;
949 }
950
951 if(!targetMatch){
952 var targ = this.getTarget();
953 if(targ.isClass && options.ignoreClasses){ return;}
954 targetMatch = jOWL.priv.testObjectTarget(target, this.target);
955 if(!targetMatch && options.transitive && propertyMatch && this.property.isTransitive){
956 if(targ.isThing){
957 if(targ.sourceof(property, target).length){ targetMatch = true;}
958 }
959 }
960 }
961
962 if(propertyMatch && targetMatch){ results.pushUnique(this);}
963 });
964
965 if(!options.inherited){ return results;}
966
967 this.parents().each(function(){
968 if(this.sourceof){
969 this.sourceof(property, target, options).each(function(parentsource){
970 var ptarget = this.getTarget();
971 var containsProperty = false;
972 var tempArray = new jOWL.Ontology.Array();
973 results.filter(function(){
974 var restr = this, keep = true;
975 if(restr.property.URI == parentsource.property.URI){
976 containsProperty = true;
977 if(!options.ignoreGenerics){
978 if(parentsource.target != restr.target){ tempArray.push(parentsource);}
979 } else {
980 if(ptarget.isThing){
981 keep = restr.getTarget().isThing && parentsource.target != restr.target;
982 tempArray.push(parentsource);
983 }
984 }
985 }
986 return keep;
987 });
988 if(!containsProperty){ results.push(parentsource);}
989 results.concat(tempArray);
990 });
991 }
992 });
993 return results;
994 }
995 });
996
997 /** Utility object */
998 jOWL.Ontology.Array = function(arr, isXML){
999 var self = this;
1000 this.items = [];
1001 if(arr){
1002 if(isXML){ $.each(arr, function(){
1003 var entry = this.jOWL ? this : jOWL($(this));
1004 self.items.push(entry);});
1005 }
1006 else { this.items = arr;}
1007 }
1008 this.length = this.items.length;
1009 };
1010
1011 jOWL.Ontology.Array.prototype = {
1012 jOWL : jOWL.version,
1013 isArray : true,
1014 bind : function(listitem, fn){
1015 return this.map(function(){
1016 var syntax = listitem ? listitem.clone(true) : $('<span/>');
1017 var html = this.bind(syntax).append(document.createTextNode(' '));
1018 if(fn){ fn.call(html, html, this);}
1019 return html.get(0);
1020 });
1021 },
1022 concat : function(arr, ignoreUnique){
1023 var self = this;
1024 if(arr.each){ arr.each(function(){
1025 if(ignoreUnique){ self.push(this); }
1026 else { self.pushUnique(this); }
1027 });
1028 }
1029 else { self.items = self.items.concat(arr.items); this.length = self.items.length;}
1030 return this;
1031 },
1032 contains : function(o){
1033 return this.get(o) ? true: false;
1034 },
1035 each : function(fn, reverse){
1036 var i, self = this;
1037 var stop = false;
1038 if(reverse){
1039 for(i=this.items.length - 1; i>=0;i--){
1040 if(stop){ break;}
1041 (function(){
1042 var item = self.eq(i);
1043 if(fn.call(item, item, i) === false){ stop = true;}
1044 })();
1045 }
1046 }
1047 else {
1048 for(i=0;i<this.items.length;i++){
1049 if(stop){ break;}
1050 (function(){
1051 var item = self.eq(i);
1052 if(fn.call(item, item, i) === false){ stop = true;}
1053 })();}
1054 }
1055 return this;
1056 },
1057 eq : function(index){
1058 if(index < 0 || index > this.items.length -1){ return null;}
1059 return this.items[index];
1060 },
1061 filter : function(fn){
1062 var self = this;
1063 this.each(function(item, i){
1064 var q = fn.call(item, item, i);
1065 if(!q){ self.items.splice(i, 1);}
1066 }, true);
1067 this.length = this.items.length;
1068 return this;
1069 },
1070 getIndex : function(o){
1071 var found = -1;
1072 if(o.equals){
1073 this.each(function(a, i){
1074 if(this.equals && this.equals(o)){ found = i; return false;}
1075 });
1076 }
1077 else {
1078 if(typeof o == 'number'){ return o;}
1079 var name = typeof o == "string" ? o : o.name;
1080 var URI = o.URI || name;
1081
1082 this.each(function(a, i){
1083 if(this.URI){ if(this.URI == URI){ found = i;}}
1084 else if(this.name == name){ found = i;}
1085 });
1086 }
1087 return found;
1088 },
1089 get : function(o){
1090 return this.eq(this.getIndex(o));
1091 },
1092 map : function(fn){
1093 var arr = [];
1094 this.each(function(){ arr.push(fn.call(this, this));});
1095 return arr;
1096 },
1097 push : function(o){
1098 this.items.push(o);
1099 this.length = this.items.length;
1100 return this;
1101 },
1102 pushUnique : function(o){
1103 return this.get(o) || this.push(o).get(o);
1104 },
1105 toString : function(){
1106 return this.map(function(){return this.URI;}).join(', ');
1107 },
1108 /** Convert this array into an associative array with key = URI */
1109 associative : function(){
1110 var arr = {};
1111 this.each(function(){
1112 if(this.URI){ arr[this.URI] = this;}
1113 });
1114 return arr;
1115 }
1116 };
1117
1118
1119 jOWL.options = {reason: true, locale:false, defaultlocale: 'en',
1120 dictionary : { create: true, addID : true },
1121 onParseError : function(msg){alert("jOWL parseError: "+msg);}, cacheProperties : true, niceClassLabels : true};
1122 jOWL.document = null;
1123 jOWL.namespace = null;
1124 jOWL.indices = { //internal indices
1125 P : null, //jOWL array
1126 data : {},
1127 IDs : null,
1128 I : null, //Intersection
1129 T : null, //Thing
1130 D : null, //dictionary
1131 reset : function(){var i = jOWL.indices; i.data = {}; i.P = null; i.T = null; i.IDs = null; i.I = null;i.D = null;}
1132 };
1133
1134 jOWL.index = function(type, wipe){
1135 var i = jOWL.indices;
1136 switch (type)
1137 {
1138 /**jOWL indexes all elements with rdf:ID, and first order ontology elements specified with rdf:about
1139 @return Associative array with key = URI and value = jOWL object.
1140 */
1141 case "ID":
1142 if(i.IDs === null || wipe){
1143 if(wipe){ i.reset();}
1144 i.IDs = {};
1145 i.T = {};
1146 var start = new Date();
1147
1148 var rID = jOWL.Xpath("//*[@"+__.rdf("ID")+"]").each(function(){
1149 var jowl = jOWL.getResource($(this));
1150 if(jowl){
1151 i.IDs[jowl.URI] = jowl;
1152 if(jowl.isThing){
1153 if(!i.T[jowl.Class]){ i.T[jowl.Class] = new jOWL.Ontology.Array();}
1154 i.T[jowl.Class].push(jowl);
1155 }
1156 }
1157 });
1158
1159 var rAbout = jOWL.Xpath("/"+__.rdf("RDF")+"/*[@"+__.rdf("about")+"]").each(function(){
1160 var jnode = $(this);
1161 var jowl = jOWL.getResource($(this));
1162 if(!jowl){ return;}
1163 if(jowl.isClass || jowl.isProperty || jowl.isThing){
1164 if(i.IDs[jowl.URI]){ jnode.children().appendTo(i.IDs[jowl.URI].jnode); return;}
1165 i.IDs[jowl.URI] = jowl;
1166 if(jowl.isThing){
1167 if(!i.T[jowl.Class]){ i.T[jowl.Class] = new jOWL.Ontology.Array();}
1168 i.T[jowl.Class].push(jowl);
1169 }
1170 return;
1171 }
1172 });
1173 console.log("Loaded in "+(new Date().getTime() - start.getTime())+"ms");
1174 }
1175 return i.IDs;
1176 /** Generated together with ID index.
1177 * @return Associative Array, key = class, value = jOWL Array of individuals.
1178 */
1179 case "Thing":
1180 return i.T;
1181 case "intersection":
1182 if(i.I === null || wipe){
1183 var temp = new jOWL.Ontology.Array();
1184 i.I = {};
1185 jOWL.Xpath("//"+__.owl("intersectionOf")).each(function(){
1186 var isect = new jOWL.Ontology.Intersection($(this));
1187 if(!isect.URI){return;}
1188 var dupe = temp.get(isect);
1189 if(dupe){
1190 console.log("duplicate intersection found between : (Ignoring) "+isect.URI+" and "+dupe.URI);
1191 } else {
1192 if(!i.I[isect.URI]){i.I[isect.URI] = new jOWL.Ontology.Array();}
1193 temp.push(isect);
1194 i.I[isect.URI].push(isect);
1195 }
1196 });
1197 }
1198 return i.I;
1199 case "property":
1200 if(i.P === null || wipe)
1201 {
1202 jOWL.options.cacheProperties = false;
1203 i.P = new jOWL.Ontology.Array();
1204 for(x in i.IDs){
1205 var jowl = i.IDs[x];
1206 if(jowl.isProperty){ i.P.push(jowl);}
1207 }
1208 jOWL.options.cacheProperties = true;
1209 }
1210 return i.P;
1211 case "dictionary":
1212 /**Dictionary: Array of Arrays, where secondary array is of form: [0] = term, [1] = rdfID, [2] = locale */
1213 if(i.D === null || wipe)
1214 {
1215 i.D = [];
1216 for(x in i.IDs){
1217 var entry = i.IDs[x];
1218 i.D = i.D.concat(entry.terms());
1219 }
1220 }
1221 return i.D;
1222 }
1223 };
1224
1225 /** Internal Function, storing data in associative array (JSON),
1226 jquery data function cannot be used as expando data does not work in IE for ActiveX XMLhttprequest*/
1227 jOWL.data = function(rdfID, dtype, data){
1228 var d = jOWL.indices.data;
1229 if(!d[rdfID]){ d[rdfID] = {};}
1230 if(!data){ return d[rdfID][dtype];}
1231 d[rdfID][dtype] = data;
1232 };
1233
1234 /**
1235 * Initialize jOWL with an OWL-RDFS document.
1236 * @param path relative path to xml document
1237 * @param callback callback function to be called when loaded.
1238 * @options : optional settings:
1239 * onParseError : function(msg){} function to ba called when parsing fails
1240 * reason : true/false, turns on additional reasoning at the expense of performance
1241 * locale: set preferred language (if available), examples en, fr...
1242 */
1243 jOWL.load = function(path, callback, options){
1244 var that = this;
1245 if($.browser.msie && location.toString().indexOf('file') === 0){ //IE won't load local xml files otherwise
1246 var xml = document.createElement("xml");
1247 xml.validateOnParse = false; //IE throws DTD errors (for 'rdf:') on perfectly defined OWL files otherwise
1248 xml.src = path;
1249 xml.onreadystatechange = function(){
1250 if(xml.readyState == "interactive"){ var xmldoc = xml.XMLDocument; document.body.removeChild(xml);callback(that.parse(xmldoc, options));}
1251 };
1252 document.body.appendChild(xml);
1253 }
1254 else {
1255 $.get(path, function(xml){callback(that.parse(xml, options));});
1256 }
1257 };
1258
1259 /**
1260 * initialize jOWL with some OWL-RDFS syntax
1261 * @param doc Either an xmlString or an xmlDocument
1262 * @param options optional, onParseError(msg) : function to execute when parse fails
1263 * @returns false on failure, or the jOWL object
1264 */
1265 jOWL.parse = function(doc, options){
1266 jOWL.document = null;
1267 this.options = $.extend(jOWL.options, options);
1268 if(typeof doc == 'string'){ doc = jOWL.fromString(doc);}
1269 jOWL.document = doc;
1270 if($.browser.msie){
1271 if(doc.parseError.errorCode !== 0){ jOWL.options.onParseError(doc.parseError.reason); return false;}
1272 }
1273 else if(doc.documentElement.nodeName == 'parsererror'){jOWL.options.onParseError(doc.documentElement.firstChild.nodeValue); return false;}
1274 var root = $(doc.documentElement);
1275 jOWL.NS(root);
1276 if($.browser.msie){
1277 jOWL.document.setProperty("SelectionLanguage", "XPath");
1278 jOWL.document.setProperty("SelectionNamespaces", __());
1279 }
1280 this.index('ID', true);
1281 if(jOWL.options.cacheProperties){ this.index('property', true);}
1282 if(jOWL.options.dictionary.create){ jOWL.index("dictionary");}
1283 jOWL.Thing = new jOWL.Ontology.Thing($(jOWL.create(__.owl, "Class").attr(__.rdf, 'about', __.owl()+'Thing').node));
1284 jOWL.Thing.type = false;
1285 return this;
1286 };
1287
1288 /**
1289 * A String representation of the OWL-RDFS document
1290 * @param xmlNode optional, node to generate a string from, when unspecified the entire document
1291 */
1292 jOWL.toString = function(xmlNode){
1293 if(!xmlNode){ return jOWL.toString(jOWL.document);}
1294 if($.browser.msie){ return xmlNode.xml;}
1295 return new XMLSerializer().serializeToString(xmlNode);// Gecko-based browsers, Safari, Opera.
1296 };
1297
1298 /** create a document from string */
1299 jOWL.fromString = function(doc){
1300 var owldoc;
1301 if(document.implementation.createDocument){ owldoc = new DOMParser().parseFromString(doc, "text/xml");} // Mozilla and Netscape browsers
1302 else if(window.ActiveXObject){ // MSIE
1303 var xmldoc = new ActiveXObject("Microsoft.XMLDOM");
1304 xmldoc.async="false";
1305 xmldoc.validateOnParse = false;
1306 xmldoc.loadXML(doc);
1307 owldoc = xmldoc;
1308 }
1309 return owldoc;
1310 };
1311
1312 /** @return false if belongs to this namespace, or an array with length two, arr[0] == url, arr[1] == id */
1313 jOWL.isExternal = function(resource){
1314 var r = jOWL.resolveURI(resource, true);
1315 return r[0] != jOWL.namespace ? r : false;
1316 };
1317
1318 /**
1319 if a URI belongs to the loaded namespace, then strips the prefix url of, else preserves URI
1320 also able to parse and reference html (or jquery) elements for their URI.
1321 */
1322 jOWL.resolveURI = function(URI, array){
1323 if(typeof URI != "string"){
1324 var node = URI.jquery ? URI.get(0) : URI;
1325 URI = node.localName || node.baseName;
1326 if(node.namespaceURI){ URI = node.namespaceURI + URI;}
1327 return jOWL.resolveURI(URI, array);
1328 }
1329 var rs = URI, ns = jOWL.namespace;
1330 if(URI.indexOf('http') === 0){
1331 var tr = URI.indexOf('#');
1332 if(tr <= 0){ tr = URI.lastIndexOf('/');}
1333 if(tr > 0)
1334 {
1335 ns = URI.substring(0, tr+1);
1336 rs = URI.substring(tr+1);
1337 }
1338 } else if(URI.charAt(0) == '#'){ return URI.substring(1);}
1339 if(array){ return [ns, rs];}
1340 if(ns == jOWL.namespace){ return rs;}
1341 return URI;
1342 };
1343
1344 /**
1345 Main method to get an Ontology Object, access via jOWL(>String>, options);
1346 resource: rdfID/rdfResource<String> or jQuery node.
1347 */
1348 jOWL.getResource = function(resource, options){
1349 if(!jOWL.document){ throw "You must successfully load an ontology before you can find anything";}
1350 if(!resource){ throw "No resource specified";}
1351 var node;
1352 var opts = $.extend({}, options);
1353 if(typeof resource == 'string'){
1354 resource = jOWL.resolveURI(resource);
1355 if(resource == 'Thing' || resource == __.owl()+'Thing'){ return jOWL.Thing;}
1356 if(opts.type == 'property' && jOWL.options.cacheProperties){
1357 var c = jOWL.index('property').get(resource);
1358 if(c){ return c;}
1359 if(jOWL.isExternal(resource)){ console.log("undeclared resource: "+resource); return new jOWL.Ontology.Property(resource);}
1360 }
1361 var match = jOWL.index("ID")[resource];
1362 if(!match){ //try case insensitive
1363 for(caseIns in jOWL.index("ID")){
1364 if(caseIns.toLowerCase() == resource.replace(/ /g, "").toLowerCase()){ match = jOWL.index("ID")[caseIns]; break;}
1365 }
1366 }
1367 if(!match){
1368 if(jOWL.isExternal(resource)){
1369 console.log("undeclared resource: "+resource);
1370 return new jOWL.Ontology.Thing(resource);
1371 }
1372 console.log(resource+" not found");
1373 return null;
1374 }
1375 return match;
1376 }
1377 node = resource.jquery ? resource : $(resource);
1378 var jj = jOWL.type(node); if(!jj){ return null;}
1379 return new (jj)(node);
1380 };
1381
1382 /**
1383 * @param node jquery or html element.
1384 * @return the ontology type of the object.
1385 */
1386 jOWL.type = function(node){
1387 var xmlNode = node.jquery ? node.get(0) : node;
1388 switch(xmlNode.nodeName){
1389 case __.owl("Class") : return jOWL.Ontology.Class;
1390 case __.rdfs("Class") : return jOWL.Ontology.Class; //test
1391 case __.owl("Ontology") : return jOWL.Ontology;
1392 case __.owl("ObjectProperty") : return jOWL.Ontology.ObjectProperty;
1393 case __.owl("DatatypeProperty") : return jOWL.Ontology.DatatypeProperty;
1394 case __.owl("FunctionalProperty") : return jOWL.Ontology.Property;
1395 case __.rdf("Property") : return jOWL.Ontology.Property;
1396 case __.owl("InverseFunctionalProperty") : return jOWL.Ontology.ObjectProperty;
1397 case __.owl("TransitiveProperty") : return jOWL.Ontology.ObjectProperty;
1398 case __.owl("SymmetricProperty") : return jOWL.Ontology.ObjectProperty;
1399 //jOWL currently treats annotationproperties as string datatypeproperties.
1400 case __.owl("AnnotationProperty") : return jOWL.Ontology.DatatypeProperty;
1401 default :
1402 switch(xmlNode.namespaceURI){
1403 case __.owl(): if(xmlNode.nodeName == __.owl("Thing") ){ return jOWL.Ontology.Individual;} return false;
1404 case __.rdf(): return false;
1405 case __.rdfs(): return false;
1406 default : return jOWL.Ontology.Individual;
1407 }
1408 }
1409 };
1410
1411 /**
1412 @param rdfID <String> or Array<String>
1413 @return Array of DOM (xml) Nodes
1414 */
1415 jOWL.getXML = function(rdfID){
1416 var node = [];
1417 function fetchFromIndex(rdfID){
1418 var el = jOWL.index("ID")[rdfID];
1419 return el ? el : null;
1420 }
1421
1422 if(typeof rdfID == 'string'){ var q = fetchFromIndex(rdfID); if(q){ node.push(q);} }
1423 else if(jOWL.priv.Array.isArray(rdfID)){ //assume an array of string rdfIDs
1424 $.each(rdfID, function(){
1425 var el = fetchFromIndex(this); if(el){ node.push(el);}
1426 });
1427 }
1428 return node;
1429 };
1430
1431 /** Create new ontology elements */
1432 jOWL.create = function(namespace, name, document){
1433 var doc = document ? document : jOWL.document;
1434
1435 var el = {
1436 attr : function(namespace, name, value){
1437 if($.browser.msie){
1438 var attribute = doc.createNode(2, namespace(name), namespace());
1439 attribute.nodeValue = value;
1440 this.node.setAttributeNode(attribute);
1441 }
1442 else { this.node.setAttributeNS(namespace(), namespace(name), value);}
1443 return this;
1444 },
1445 appendTo : function(node){
1446 var n = node.node ? node.node : node;
1447 n.appendChild(this.node);
1448 return this;
1449 },
1450 text : function(text, cdata){
1451 var txt = cdata ? doc.createCDATASection(text) : doc.createTextNode(text);
1452 this.node.appendChild(txt);
1453 return this;
1454 }
1455 };
1456
1457 if($.browser.msie){ el.node = doc.createNode(1, namespace(name), namespace());}
1458 else { el.node = doc.createElementNS(namespace(), namespace(name));}
1459 return el;
1460 };
1461
1462 /** Create a blank ontology document */
1463 jOWL.create.document = function(href){
1464 var owl = [];
1465 var base = href || window.location.href+"#";
1466 owl.push('<?xml version="1.0"?>');
1467 owl.push('<'+__.rdf('RDF')+' xml:base="'+base+'" xmlns="'+base+'" '+__()+'>');
1468 owl.push(' <'+__.owl('Ontology')+' '+__.rdf('about')+'=""/>');
1469 owl.push('</'+__.rdf('RDF')+'>');
1470 return jOWL.fromString(owl.join('\n'));
1471 };
1472
1473 /** Extracts RDFa syntax from current page and feeds it to jOWL, simple implementation, only classes for the time being */
1474 jOWL.parseRDFa = function(fn, options){
1475 var entries = options.node ? $("[typeof]", options.node) : $("[typeof]");
1476 var doc = jOWL.create.document();
1477
1478 function property(p, node){
1479 var arr = [];
1480 $("[property="+p+"]", node).each(function(){ arr.push($(this).attr('content') || $(this).html());});
1481 if(node.attr('property') === p){ arr.push(node.attr('content') || node.html());}
1482 return arr;
1483 }
1484
1485 function rel(p, node){
1486 var arr = [];
1487 $("[rel="+p+"]", node).each(function(){ arr.push($(this).attr('resource'));});
1488 if(node.attr("rel") === p){ arr.push(node.attr('resource'));}
1489 return arr;
1490 }
1491
1492 function makeClass(node, ID){
1493 var cl = jOWL.create(__.owl, "Class", doc).attr(__.rdf, 'about', ID).appendTo(doc.documentElement);
1494
1495 var parents = property(__.rdfs("subClassOf"), node).concat(rel(__.rdfs("subClassOf"), node));
1496 for(var i = 0;i<parents.length;i++){
1497 var p = jOWL.create(__.rdfs, "subClassOf", doc).attr(__.rdf, "resource", parents[i]).appendTo(cl);
1498 }
1499 return cl;
1500 }
1501
1502 entries.each(function(){
1503 var node = $(this);
1504 var type = node.attr("typeof"), el;
1505
1506 if(type == __.owl("Class")){ el = makeClass(node, jOWL.resolveURI(node.attr("about")));}
1507
1508 $.each(property(__.rdfs('comment'), node), function(){
1509 jOWL.create(__.rdfs, "comment", doc).appendTo(el).text(this, true);
1510 });
1511
1512 $.each(property(__.rdfs('label'), node), function(){
1513 jOWL.create(__.rdfs, "label", doc).appendTo(el).text(this);
1514 });
1515 });
1516 jOWL.parse(doc, options);
1517 fn();
1518 };
1519
1520 /**
1521 Match part or whole of the rdfResource<String>
1522 Used for term searches, intend to (partially) replace it by a sparql-dl query later on
1523 options:
1524 filter: filter on a specific type, possible values: Class, Thing, ObjectProperty, DatatypeProperty
1525 exclude: exclude specific types, not fully implemented
1526 */
1527 jOWL.query = function(match, options){
1528 options = $.extend({exclude : false}, options);
1529 if(options.filter == 'Class'){ options.filter = __.owl("Class");}
1530 var that = this;
1531 //filter : [], exclude : false
1532 var items = new jOWL.Ontology.Array();
1533 var jsonobj = {};
1534 var test = jOWL.index("dictionary");
1535
1536 function store(item){
1537 var include = false, i = 0;
1538 if(options.filter){
1539 if(typeof options.filter == 'string'){ include = (options.filter == item[3]);}
1540 else { for(i = 0;i<options.filter.length;i++){ if(options.filter[i] == item[3]){ include = true;} } }
1541 }
1542 else if(options.exclude){
1543 include = true;
1544 if(typeof options.exclude == 'string'){ include = (options.exclude !== item[3]);}
1545 else { for(i = 0;i<options.exclude.length;i++){ if(options.exclude[i] == item[3]){ include = false;} } }
1546 }
1547 else { include = true;}
1548 if(!include){ return;}
1549 if(!jsonobj[item[1]]){ jsonobj[item[1]] = [];}
1550 jsonobj[item[1]].push( { term : item[0], locale: item[2], type: item[3] });
1551 }
1552
1553 for(var y = 0;y<test.length;y++){
1554 var item = test[y];
1555 var bool = options.exclude;
1556 var r = item[0].searchMatch(match);
1557 if(r > -1){
1558 if(options.locale){ if(options.locale == item[2]){ store(item);} }
1559 else { store(item);}
1560 }
1561 }
1562 return jsonobj;
1563 };
1564
1565 /**
1566 allows asynchronous looping over arrays (prevent bowser freezing).
1567 arr the array to loop asynchonrously over.
1568 options.modify(item) things to do with each item of the array
1569 options.onUpdate array the size of chewsize or smaller, containing processed entries
1570 options.onComplete(array of results) function triggered when looping has completed
1571 */
1572 jOWL.throttle =function(array, options){
1573 options = $.extend({
1574 modify : function(result){},
1575 //onUpdate : function(arr){},
1576 onComplete : function(arr){},
1577 async : true,
1578 chewsize : 5,
1579 startIndex : 0,
1580 timing : 5
1581 }, options);
1582 var temp = array.jOWL ? array.items : (array.jquery) ? $.makeArray(array) : array;
1583 var items = options.startIndex ? temp.slice(startIndex) : temp.concat(); //clone the array
1584 var results = [];
1585
1586 (function(){
1587 var count = options.chewsize;
1588 var a = [];
1589 while (count > 0 && items.length > 0)
1590 {
1591 var item = items.shift(); count--;
1592 var result = options.modify.call(item, item);
1593 if(result){ results.push(result); a.push(result);}
1594 }
1595 if(options.onUpdate){ options.onUpdate(a);}
1596
1597 if(items.length> 0){
1598 if(options.async){ setTimeout(arguments.callee, options.timing);}
1599 else {arguments.callee();}
1600 }
1601 else{ options.onComplete(results);}
1602 })();
1603 };
1604
1605 /** Creates a new resultobj for the SPARQL-DL functionality */
1606 jOWL.SPARQL_DL_Result = function(){
1607 this.assert = undefined;
1608 this.head = {}; //associative array of query parameters, with value jOWL Array of results
1609 this.results = []; //sparql-dl bindings
1610 this.isBound = false;
1611 };
1612
1613 jOWL.SPARQL_DL_Result.prototype = {
1614 sort : function(param){
1615 if(!param){ throw "parameter must be defined for sort function";}
1616 function sortResults(a, b){
1617 var o = a[param].name || a[param];
1618 var p = b[param].name || b[param];
1619 return (o < p) ? -1 : 1;
1620 }
1621 if(this.results){ this.results.sort(sortResults); }
1622 },
1623 jOWLArray : function(param){
1624 if(!param){ throw "parameter must be defined for jOWLArray function";}
1625 var arr = new jOWL.Ontology.Array();
1626 for(var i=0;i<this.results.length;i++){
1627 if(this.results[i][param]){ arr.pushUnique(this.results[i][param]);}
1628 }
1629 return arr;
1630 },
1631 /** Filter head Parameters */
1632 filter : function(param, arr){
1633 if(this.head[param] === undefined){this.head[param] = arr;}
1634 else {
1635 var self = this;
1636 this.head[param].filter(function(){ return (arr.contains(this));});
1637 arr.filter(function(){ return (self.head[param].contains(this));});
1638 }
1639 },
1640 /** Update result section, results = SPARQL_DL_Array */
1641 bind : function(results){
1642 if(!this.isBound){//new results
1643 this.results = this.results.concat(results.arr);
1644 this.isBound = true;
1645 return;
1646 }
1647 var multimapping = -1;
1648 for(x in results.mappings){ multimapping++; }
1649 var toAdd = [];
1650
1651 for(x in results.mappings){
1652 var otherKeys;
1653 if(multimapping){
1654 otherKeys = results.keyCentric(x);
1655 }
1656 for(var i = this.results.length-1;i>=0;i--){
1657 var valueX = this.results[i][x];
1658 if(valueX){
1659 if(!results.mappings[x].contains(valueX)){
1660 this.results.splice(i, 1);
1661 continue;
1662 }
1663 if(multimapping){
1664 var keyArr= otherKeys[valueX.URI];
1665 //ignoring the opposite for now (assuming original key x is unique (limits statements))
1666 //TODO: improve these result merging methods/flexibility
1667 for(var oK = 0; oK < keyArr.length;oK++){
1668 var obj = (oK === 0) ? this.results[i] : {};
1669 var valueY = keyArr[oK];
1670 obj[x] = valueX;
1671 for(yK in valueY){ obj[yK] = valueY[yK]; }
1672 toAdd.push(obj);
1673 }
1674 this.results.splice(i, 1);
1675 }
1676 }
1677 }
1678 }
1679 this.results = this.results.concat(toAdd);
1680 }
1681 };
1682 /** Creates a new query for the SPARQL-DL functionality */
1683 jOWL.SPARQL_DL_Query = function(syntax, parameters){
1684 this.parse(syntax);
1685 this.fill(parameters);
1686 this.entries = this.entries.sort(this.sort);
1687 };
1688
1689 jOWL.SPARQL_DL_Query.prototype = {
1690 parse : function(syntax){
1691 var r2 = /(\w+)[(]([^)]+)[)]/;
1692 var entries = syntax.match(/(\w+[(][^)]+[)])/g);
1693 if(!entries){ this.error = "invalid abstract sparql-dl syntax"; return;}
1694 entries = jOWL.priv.Array.unique(entries);
1695 for(var i = 0;i<entries.length;i++){
1696 var y = entries[i].match(r2);
1697 if(y.length != 3){ this.error = "invalid abstract sparql-dl syntax"; return;}
1698 entries[i] = [y[1], y[2].replace(/ /g, "").split(',')];
1699 }
1700 this.entries = entries;
1701 },
1702 fill : function(parameters){
1703 for(var i = 0;i<this.entries.length;i++){
1704 for(var j =0; j<this.entries[i][1].length; j++){
1705 var p = parameters[this.entries[i][1][j]];
1706 if(p !== undefined) { this.entries[i][1][j] = p;}
1707 else {
1708 p = this.entries[i][1][j];
1709 if(p.charAt(0) != '?')
1710 {
1711 if(this.entries[i][0] == "PropertyValue" && j == 2)
1712 {
1713 var m = p.match(/^["'](.+)["']$/);
1714 if(m && m.length == 2){ this.entries[i][1][j] = {test: m[1]}; break;}
1715 }
1716 this.entries[i][1][j] = jOWL(p);
1717 if(this.entries[i][1][j] === null){this.entries.error = "a parameter in the query was not found"; return;}
1718 }
1719 }
1720 }
1721 }
1722 },
1723 sort : function(a, b){
1724 var i;
1725 if(a[1].length == 1){ return (b[0] == 'PropertyValue') ? 1 : -1;}
1726 if(b[1].length == 1){ return (a[0] == 'PropertyValue') ? -1 : 1;}
1727 var avar = 0; for(i = 0;i<a[1].length;i++){ if(typeof a[1][i] == 'string'){ avar++;} }
1728 var bvar = 0; for(i = 0;i<a[1].length;i++){ if(typeof b[1][i] == 'string'){ bvar++;} }
1729 if(avar != bvar){ return avar - bvar;}
1730 if(a[0] == 'Type' && b[0] != 'Type'){ return -1;}
1731 if(a[0] != 'Type' && b[0] == 'Type'){ return 1;}
1732 return 0;
1733 }
1734 };
1735
1736 /** Private function */
1737 function _Binding(bindingarray){
1738 this.value = {};
1739 this.arr = bindingarray;
1740 }
1741
1742 _Binding.prototype = {
1743 bind : function(key, value){
1744 this.value[key] = value;
1745 if(!this.arr.mappings[key]){ this.arr.mappings[key] = new jOWL.Ontology.Array();}
1746 this.arr.mappings[key].push(value);
1747 return this;
1748 }
1749 };
1750
1751 /** Local Function, private access, Temp results */
1752 function SPARQL_DL_Array(keys){
1753 this.arr = [];
1754 this.mappings = {};
1755
1756 if(keys){
1757 for(var i =0;i<keys.length;i++){
1758 if(keys[i]){this.mappings[keys[i]] = new jOWL.Ontology.Array();}
1759 }
1760 }
1761 }
1762
1763 SPARQL_DL_Array.prototype = {
1764 add : function(binding){
1765 this.arr.push(binding.value);
1766 return binding;
1767 },
1768 push : function(key, value){
1769 var binding = new _Binding(this);
1770 binding.bind(key, value);
1771 this.arr.push(binding.value);
1772 return binding;
1773 },
1774 keyCentric : function(keyX){
1775 var arr = {};
1776 for(var i = this.arr.length-1;i>=0;i--){
1777 if(this.arr[i][keyX]){
1778 if(!arr[this.arr[i][keyX].URI]){ arr[this.arr[i][keyX].URI] = []; }
1779 arr[this.arr[i][keyX].URI].push(this.arr[i]);
1780 }
1781 }
1782 return arr;
1783 },
1784 get : function(key)
1785 {
1786 return (this.mappings[key]) ? this.mappings[key] : new jOWL.Ontology.Array();
1787 },
1788 getArray : function(){
1789 //check mappings for presence, discard arr entries based on that, return remainder.
1790 for(var i = this.arr.length - 1;i>=0;i--){
1791 var binding = this.arr[i], splice = false;
1792 for(key in binding){
1793 if(!splice){
1794 splice = (!this.mappings[key] || !this.mappings[key].contains(binding[key]));
1795 }
1796 }
1797 if(splice){
1798 this.arr.splice(i, 1);
1799 }
1800 }
1801 return this;
1802 }
1803 };
1804
1805 /**
1806 Support for abstract SPARQl-DL syntax
1807 options.onComplete: function triggered when all individuals have been looped over
1808 options.childDepth: depth to fetch children, default 5, impacts performance
1809 options.chewsize: arrays will be processed in smaller chunks (asynchronous), with size indicated by chewsize, default 10
1810 options.async: default true, query asynchronously
1811 parameters: prefill some sparql-dl parameters with jOWL objects
1812 execute: start query, results are passed through options.onComplete
1813 */
1814 jOWL.SPARQL_DL = function(syntax, parameters, options){
1815 if(!(this instanceof arguments.callee)){ return new jOWL.SPARQL_DL(syntax, parameters, options);}
1816 var self = this;
1817 this.parameters = $.extend({}, parameters);
1818 this.query = new jOWL.SPARQL_DL_Query(syntax, this.parameters).entries;
1819 this.result = new jOWL.SPARQL_DL_Result();
1820 this.options = $.extend({onComplete: function(results){}}, options);
1821 };
1822
1823 jOWL.SPARQL_DL.prototype = {
1824 error: function(msg){ this.result.error = msg; return this.options.onComplete(this.result);},
1825 /**
1826 if(options.async == false) then this method returns the result of options.onComplete,
1827 no matter what, result is always passed in options.onComplete
1828 */
1829 execute : function(options){
1830 var self = this;
1831 this.options = $.extend(this.options, options);
1832 if(this.query.error){ return this.error(this.query.error);}
1833
1834 var resultobj = this.result;
1835 var i = 0;
1836 var loopoptions = $.extend({}, this.options);
1837 loopoptions.onComplete = function(results){ i++; resultobj = results; loop(i);};
1838
1839 if(!this.query.length){
1840 resultobj.error = "no query found or query did not parse properly";
1841 return self.options.onComplete(resultobj);
1842 }
1843
1844 function loop(i){
1845 if(i < self.query.length){
1846 self.process(self.query[i], resultobj, loopoptions );
1847 }
1848 else {
1849 for(var j =0;j<resultobj.results.length;j++){ //Convert Literals into strings
1850 var b = resultobj.results[j];
1851 for(x in b){
1852 if(b[x] instanceof jOWL.Literal){b[x] = b[x].name;}
1853 }
1854 }
1855 return self.options.onComplete(resultobj);
1856 }
1857 }
1858 loop(i);
1859 },
1860 /** results are passed in the options.onComplete function */
1861 process: function(entry, resultobj, options){
1862 var self = this;
1863 options = $.extend({chewsize: 10, async : true, onComplete : function(results){}}, options);
1864 var q = entry[0];
1865 var sizes = {
1866 "Type": [__.owl('Thing'), __.owl('Class')],
1867 "DirectType": [__.owl('Thing'), __.owl('Class')],
1868 "PropertyValue" : [false, false, false],
1869 "Class": [false],
1870 "Thing": [false],
1871 "ObjectProperty": [false],
1872 "DatatypeProperty": [false],
1873 "SubClassOf" : [__.owl('Class'), __.owl('Class')],
1874 "DirectSubClassOf" : [__.owl('Class'), __.owl('Class')]
1875 };
1876
1877 if(!sizes[q]){ return self.error("'"+q+"' queries are not implemented");}
1878 if(sizes[q].length != entry[1].length){ return self.error("invalid SPARQL-DL "+q+" specifications, "+sizes[q].length+" parameters required");}
1879 for(var i = 0;i<entry[1].length;i++){
1880 var v = sizes[q][i];
1881 if(v){
1882 var m = entry[1][i];
1883 if(typeof m != 'string' && m.type != v){ return self.error("Parameter "+i+" in SPARQL-DL Query for "+q+" must be of the type: "+v);}
1884 }
1885 }
1886 if(q == "DirectType"){ options.childDepth = 0; return self.fn.Type.call(self, entry[1], resultobj, options);}
1887 else if(q == "DirectSubClassOf"){ options.childDepth = 1; return self.fn.SubClassOf.call(self, entry[1], resultobj, options);}
1888 return self.fn[q].call(self, entry[1], resultobj, options);
1889 },
1890 fn : {
1891 "SubClassOf" : function(syntax, resultobj, options){
1892 var atom = new jOWL.SPARQL_DL.DoubleAtom(syntax, resultobj.head);
1893 var results = new SPARQL_DL_Array();
1894
1895 if(atom.source.isURI() && atom.target.isURI()){//assert
1896 if(resultobj.assert !== false){
1897 var parents = atom.source.value.ancestors();
1898 resultobj.assert = parents.contains(atom.target.value);
1899 }
1900 return options.onComplete(resultobj);
1901 }
1902 else if(atom.source.isURI()){//get parents
1903 atom.source.value.ancestors().each(function(){
1904 results.push(atom.target.value, this);
1905 });
1906 resultobj.filter(atom.target.value, results.get(atom.target.value));
1907 resultobj.bind(results.getArray());
1908 return options.onComplete(resultobj);
1909 }
1910 else if(atom.target.isURI()){//get children
1911 atom.target.value.descendants(options.childDepth).each(function(){
1912 results.push(atom.source.value, this);
1913 });
1914 resultobj.filter(atom.source.value, results.get(atom.source.value));
1915 resultobj.bind(results.getArray());
1916 return options.onComplete(resultobj);
1917 }
1918 else{//both undefined
1919 return this.error('Unsupported SubClassOf query');
1920 }
1921 },
1922 "Type" : function(syntax, resultobj, options){
1923 var atom = new jOWL.SPARQL_DL.DoubleAtom(syntax, resultobj.head);
1924
1925 function addIndividual(cl){
1926 if(indivs[this.URI]){ return;}
1927 var b = results.push(atom.source.value, this);
1928 if(addTarget){ b.bind(atom.target.value, cl);}
1929 indivs[this.URI] = true;
1930 }
1931
1932 function traverse(node, match){
1933 var a = node.parents();
1934 var found = false;
1935 if(a.contains(match)){ found = true;}
1936 else {
1937 a.each(function(){
1938 if(this == jOWL.Thing){ return;}
1939 if(!found && traverse(this, match)){ found = true;} });
1940 }
1941 return found;
1942 }
1943
1944 if(atom.source.isURI() && atom.target.isURI()){//assert
1945 return jOWL.SPARQL_DL.priv.assert(resultobj, function(){
1946 var cl = atom.source.value.owlClass();
1947 if(cl.URI == atom.target.value.URI){ return true;}
1948 return traverse(cl, atom.target.value);
1949 }, options.onComplete);
1950 }
1951 else if(atom.source.getURIs() && !atom.target.getURIs()){//get class
1952 var results = new SPARQL_DL_Array();
1953 var addSource = !atom.source.isURI();
1954 var addTarget = !atom.target.isURI();
1955 atom.source.getURIs().each(function(){
1956 var b;
1957 if(addTarget){ b = results.push(atom.target.value, this.owlClass());}
1958 if(addSource){
1959 if(addTarget){ b.bind(atom.source.value, this);}
1960 else {results.push(atom.source.value, this);}
1961 }
1962 });
1963 if(addSource){ resultobj.filter(atom.source.value, results.get(atom.source.value));}
1964 if(addTarget){ resultobj.filter(atom.target.value, results.get(atom.target.value));}
1965 resultobj.bind(results.getArray());
1966 return options.onComplete(resultobj);
1967 }
1968 else if(atom.target.getURIs()){//get Individuals, slow
1969 var addTarget = !atom.target.isURI();
1970 var classlist = atom.target.getURIs(),
1971 classes = {}, indivs = {};
1972
1973 var results = new SPARQL_DL_Array();
1974
1975
1976 classlist.each(function(){ //expand list of classes, not very fast!
1977 if(classes[this.URI]){ return;}
1978 var oneOf = this.oneOf(), cl = this;
1979 if(oneOf.length){ oneOf.each(function(){ addIndividual.call(this, cl);});}
1980 else{ this.descendants(options.childDepth).each(function(){ //this is the slower call
1981 classes[this.URI] = true;
1982 }); }
1983 classes[this.URI] = true;
1984 });
1985
1986 for(x in classes){
1987 var individuals = jOWL.index("Thing")[x];
1988 if(individuals){
1989 var cl = jOWL.index('ID')[x];
1990 if(options.onUpdate){ options.onUpdate(individuals);}
1991 individuals.each(function(){
1992 addIndividual.call(this, cl);
1993 });
1994 }
1995 }
1996 resultobj.filter(atom.source.value, results.get(atom.source.value));
1997 resultobj.bind(results.getArray());
1998 return options.onComplete(resultobj);
1999 }
2000 return this.error('Unsupported Type query');
2001 },
2002 "Thing" : function(syntax, resultobj, options){
2003 jOWL.SPARQL_DL.priv.IDQuery(syntax[0], "isThing", resultobj, options);
2004 },
2005 "Class" : function(syntax, resultobj, options){ console.log('cl');
2006 jOWL.SPARQL_DL.priv.IDQuery(syntax[0], "isClass", resultobj, options);
2007 },
2008 "ObjectProperty" : function(syntax, resultobj, options){
2009 jOWL.SPARQL_DL.priv.PropertyQuery(syntax[0], jOWL.index("property").items, "isObjectProperty", resultobj, options);
2010 },
2011 "DatatypeProperty" : function(syntax, resultobj, options){
2012 jOWL.SPARQL_DL.priv.PropertyQuery(syntax[0], jOWL.index("property").items, "isDatatypeProperty", resultobj, options);
2013 },
2014 "PropertyValue" : function(syntax, resultobj, options){
2015 var atom = new jOWL.SPARQL_DL.TripleAtom(syntax, resultobj.head);
2016
2017 if(atom.source.isURI() && atom.property.isURI() && atom.target.isURI()){//assert
2018 if(resultobj.assert !== false){
2019 jOWL.SPARQL_DL.priv.PropertyValuegetSourceInfo(atom.source.value, atom.property.value, atom.target.value, resultobj, { assert : true });
2020 }
2021 return options.onComplete(resultobj);
2022 }
2023
2024 if(!atom.source.getURIs()){
2025 jOWL.SPARQL_DL.priv.IDQuery(atom.source.value, ["isClass", "isThing"], resultobj, options);
2026 return;
2027 }
2028 var filterTarget = atom.target.isVar() ? atom.target.value : false;
2029 var filterProperty = atom.property.isVar() ? atom.property.value : false;
2030 var filterSource = atom.source.isVar() ? atom.source.value : false;
2031 jOWL.SPARQL_DL.priv.PropertyValuegetSourceInfo(atom.source.getURIs(), atom.property.getURIs(), atom.target.getURIs(), resultobj,
2032 {
2033 filterTarget : filterTarget, filterProperty : filterProperty, filterSource : filterSource
2034 });
2035 return options.onComplete(resultobj);
2036 }
2037 }
2038 };
2039
2040 jOWL.SPARQL_DL.priv = {
2041 assert : function(resultobj, fn, onComplete){
2042 if(resultobj.assert !== false){
2043 resultobj.assert = fn();
2044 }
2045 onComplete(resultobj);
2046 },
2047 //reusable function
2048 PropertyValuegetSourceInfo : function(jSource, property, target, resultobj, options){
2049 if(!(jSource.isArray)){
2050 return jOWL.SPARQL_DL.priv.PropertyValuegetSourceInfo(new jOWL.Ontology.Array([jSource]), property, target, resultobj, options);
2051 }
2052
2053 options = $.extend({}, options);
2054 var results = new SPARQL_DL_Array([options.filterSource, options.filterProperty, options.filterTarget]),
2055 match = false;
2056 jSource.each(function(){
2057 var source = this;
2058 if(target && target.isArray && target.length == 1){
2059 var literal = target.get(0).test;
2060 if(literal){ target = literal;}//unwrap literal expressions
2061 }
2062 var restrictions = source.sourceof(property, target);
2063 if(options.assert){
2064 if(restrictions.length > 0){ match = true;}
2065 return;
2066 }
2067 if(!restrictions.length){ return;}
2068 restrictions.each(function(){
2069 var binding = new _Binding(results);
2070 if(options.filterSource){
2071 binding.bind(options.filterSource, source);
2072 if(!options.filterProperty && !options.filterTarget){ results.add(binding); return false;}
2073 }
2074 if(options.filterProperty){
2075 binding.bind(options.filterProperty, this.property);
2076 }
2077 if(options.filterTarget){
2078 binding.bind(options.filterTarget, this.getTarget());
2079 }
2080 results.add(binding);
2081 });
2082 return true;
2083 });
2084 if(options.assert){
2085 resultobj.assert = match;
2086 return resultobj.assert;
2087 }
2088 if(options.filterSource){ resultobj.filter(options.filterSource, results.get(options.filterSource));}
2089 if(options.filterProperty){ resultobj.filter(options.filterProperty, results.get(options.filterProperty));}
2090 if(options.filterTarget) { resultobj.filter(options.filterTarget, results.get(options.filterTarget));}
2091 resultobj.bind(results.getArray());
2092 },
2093 hasClassID: function(match, classID){
2094 if(Object.prototype.toString.call(classID) === '[object Array]'){
2095 for(var i =0;i<classID.length;i++){
2096 if(match[classID]){ return true;}
2097 }
2098 } else if(match[classID]){ return true;}
2099 return false;
2100 },
2101 IDQuery : function(parameter, classID, resultobj, options){
2102 var atom = new jOWL.SPARQL_DL.Atom(parameter, resultobj.head);
2103 if(atom.isURI()){
2104 return jOWL.SPARQL_DL.priv.assert(resultobj, function(){
2105 return jOWL.SPARQL_DL.priv.hasClassID(atom.getURIs().get(0), classID);
2106 }, options.onComplete);
2107 }
2108 var results = new SPARQL_DL_Array();
2109 for(x in jOWL.index("ID")){
2110 var match = jOWL.index("ID")[x];
2111 if(jOWL.SPARQL_DL.priv.hasClassID(match, classID)){ results.push(parameter, match);}
2112 }
2113 resultobj.filter(parameter, results.get(parameter));
2114 resultobj.bind(results.getArray());
2115 options.onComplete(resultobj);
2116 },
2117 PropertyQuery : function(parameter, index, className, resultobj, options){
2118 var atom = new jOWL.SPARQL_DL.Atom(parameter, resultobj.head);
2119 if(atom.isURI()){
2120 return jOWL.SPARQL_DL.priv.assert(resultobj, function(){
2121 return jOWL.SPARQL_DL.priv.hasClassID(atom.getURIs().get(0), className);
2122 }, options.onComplete);
2123 }
2124 var results = new SPARQL_DL_Array();
2125 var tr = new jOWL.throttle(index, $.extend({}, options, {
2126 modify : function(result){
2127 if(!result.jOWL){ result = jOWL(result);}
2128 if(jOWL.SPARQL_DL.priv.hasClassID(result, className)){results.push(parameter, result);}
2129 return false;
2130 },
2131 onComplete : function(){
2132 resultobj.filter(parameter, results.get(parameter));
2133 resultobj.bind(results.getArray());
2134 options.onComplete(resultobj);
2135 }
2136 }));
2137 }
2138 };
2139
2140 jOWL.SPARQL_DL.TripleAtom = function(syntax, store){
2141 this.source = new jOWL.SPARQL_DL.Atom(syntax[0], store);
2142 this.property = new jOWL.SPARQL_DL.Atom(syntax[1], store);
2143 this.target = new jOWL.SPARQL_DL.Atom(syntax[2], store);
2144 };
2145
2146 jOWL.SPARQL_DL.DoubleAtom = function(syntax, store){
2147 this.source = new jOWL.SPARQL_DL.Atom(syntax[0], store);
2148 this.target = new jOWL.SPARQL_DL.Atom(syntax[1], store);
2149 };
2150
2151
2152 jOWL.SPARQL_DL.Atom = function(syntax, store){
2153 this.value = syntax;
2154 this.type = 0;
2155 if(typeof syntax == 'string'){
2156 if(syntax.indexOf('?') === 0){
2157 this.type = this.VAR;
2158 if(store && store[syntax]){ this.mappings = store[syntax];}
2159 } else {
2160 this.type = this.LITERAL;
2161 }
2162 } else {
2163 this.type = this.URI;
2164 }
2165 };
2166
2167 jOWL.SPARQL_DL.Atom.prototype = {
2168 URI : 1, LITERAL : 2, VAR : 3,
2169 getURIs : function(){
2170 if(this.isURI()){return new jOWL.Ontology.Array([this.value]);}
2171 return this.mappings;
2172 },
2173 isVar : function(){return this.type == this.VAR;},
2174 isLiteral : function(){return this.type == this.LITERAL;},
2175 isURI : function(){ return this.type == this.URI;}
2176 };
2177
2178 /**
2179 * @return Associative array of parameters in the current documents URL
2180 */
2181 jOWL.getURLParameters = function(){
2182 var href = window.location.href.split("?", 2), param = {};
2183 if(href.length == 1){ return {};}
2184 var qstr = href[1].split('&');
2185 for(var i =0;i<qstr.length;i++){
2186 var arr = qstr[i].split("=");
2187 if(arr.length == 2){ param[arr[0]] = arr[1];}
2188 }
2189 return param;
2190 };
2191
2192 /**
2193 Without arguments this function will parse the current url and see if any parameters are defined, returns a JOWL object
2194 @return With argument it will return a string that identifies the potential permalink fr the given entry
2195 */
2196 jOWL.permalink = function(entry){
2197 if(!entry){
2198 var param = jOWL.getURLParameters();
2199 if(param.owlClass){ return jOWL(unescape(param.owlClass));}
2200 }
2201 else {
2202 if(!entry.URI){ return false;}
2203 var href = window.location.href.split("?", 2);
2204 if(window.location.search){ href = href[0];}
2205 if(entry.isClass){ return href+'?owlClass='+escape(entry.URI);}
2206 }
2207 return false;
2208 };
2209
2210 /** Convert an item into Manchester syntax, currently only for oneOf
2211 * @return String
2212 */
2213 jOWL.Manchester = function(owlElement){
2214 var syntax = [];
2215 if(owlElement.isClass){
2216 var oneOf = owlElement.oneOf().map(function(){ return this.label();});
2217 if(oneOf.length){ syntax.push("{ "+oneOf.join(", ")+" }");}
2218 }
2219 return syntax.join(", ");
2220 };
2221
2222 })(jQuery);
2223
2224 /**
2225 * @return 1 for exact match, 0 for partial match, -1 for no match.
2226 */
2227 String.prototype.searchMatch = function(matchstring, exact){
2228 if(this.search(new RegExp(matchstring, "i")) > -1){ return 1;} //contained within
2229 var c = 0; var arr = matchstring.match(new RegExp("\\w+", "ig"));
2230 for(var i = 0;i<arr.length;i++){ if(this.search(arr[i]) > -1){ c++;} }
2231 if(c == arr.length){ return 0;} //word shift
2232 return -1; //nomatch
2233 };
2234 /**
2235 * @return Modified String.
2236 */
2237 String.prototype.beautify = function(){
2238 var e1 = new RegExp("([a-z0-9])([A-Z])", "g");
2239 var e2 = new RegExp("([A-Z])([A-Z0-9])([a-z])", "g");
2240 var e3 = new RegExp("_", "g");
2241 return this.replace(e1, "$1 $2").replace(e2, "$1 $2$3").replace(e3, " ");
2242 };