From 9c21b1484099626ebb04af28582d476f84b26f52 Mon Sep 17 00:00:00 2001 From: LasseMempel Date: Thu, 1 Aug 2024 14:36:34 +0200 Subject: [PATCH] rdfLibTest --- index.html | 769 +--- js/jquery-3.7.1.min.js | 2 + js/rdflib.js | 9035 ++++++++++++++++++++++++++++++++++++++++ ontologyTest.html | 747 ++++ 4 files changed, 9809 insertions(+), 744 deletions(-) create mode 100644 js/jquery-3.7.1.min.js create mode 100644 js/rdflib.js create mode 100644 ontologyTest.html diff --git a/index.html b/index.html index 1bc415c..d3759e5 100644 --- a/index.html +++ b/index.html @@ -1,747 +1,28 @@ - - - - - - - -
- - -
- -
-
-
-
-
- - + + Test RDF + + + + +
+ + \ No newline at end of file diff --git a/js/jquery-3.7.1.min.js b/js/jquery-3.7.1.min.js new file mode 100644 index 0000000..7f37b5d --- /dev/null +++ b/js/jquery-3.7.1.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.7.1 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(ie,e){"use strict";var oe=[],r=Object.getPrototypeOf,ae=oe.slice,g=oe.flat?function(e){return oe.flat.call(e)}:function(e){return oe.concat.apply([],e)},s=oe.push,se=oe.indexOf,n={},i=n.toString,ue=n.hasOwnProperty,o=ue.toString,a=o.call(Object),le={},v=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},y=function(e){return null!=e&&e===e.window},C=ie.document,u={type:!0,src:!0,nonce:!0,noModule:!0};function m(e,t,n){var r,i,o=(n=n||C).createElement("script");if(o.text=e,t)for(r in u)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[i.call(e)]||"object":typeof e}var t="3.7.1",l=/HTML$/i,ce=function(e,t){return new ce.fn.init(e,t)};function c(e){var t=!!e&&"length"in e&&e.length,n=x(e);return!v(e)&&!y(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+ge+")"+ge+"*"),x=new RegExp(ge+"|>"),j=new RegExp(g),A=new RegExp("^"+t+"$"),D={ID:new RegExp("^#("+t+")"),CLASS:new RegExp("^\\.("+t+")"),TAG:new RegExp("^("+t+"|[*])"),ATTR:new RegExp("^"+p),PSEUDO:new RegExp("^"+g),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ge+"*(even|odd|(([+-]|)(\\d*)n|)"+ge+"*(?:([+-]|)"+ge+"*(\\d+)|))"+ge+"*\\)|)","i"),bool:new RegExp("^(?:"+f+")$","i"),needsContext:new RegExp("^"+ge+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ge+"*((?:-\\d)?\\d*)"+ge+"*\\)|)(?=[^-]|$)","i")},N=/^(?:input|select|textarea|button)$/i,q=/^h\d$/i,L=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,H=/[+~]/,O=new RegExp("\\\\[\\da-fA-F]{1,6}"+ge+"?|\\\\([^\\r\\n\\f])","g"),P=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},M=function(){V()},R=J(function(e){return!0===e.disabled&&fe(e,"fieldset")},{dir:"parentNode",next:"legend"});try{k.apply(oe=ae.call(ye.childNodes),ye.childNodes),oe[ye.childNodes.length].nodeType}catch(e){k={apply:function(e,t){me.apply(e,ae.call(t))},call:function(e){me.apply(e,ae.call(arguments,1))}}}function I(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(V(e),e=e||T,C)){if(11!==p&&(u=L.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return k.call(n,a),n}else if(f&&(a=f.getElementById(i))&&I.contains(e,a)&&a.id===i)return k.call(n,a),n}else{if(u[2])return k.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&e.getElementsByClassName)return k.apply(n,e.getElementsByClassName(i)),n}if(!(h[t+" "]||d&&d.test(t))){if(c=t,f=e,1===p&&(x.test(t)||m.test(t))){(f=H.test(t)&&U(e.parentNode)||e)==e&&le.scope||((s=e.getAttribute("id"))?s=ce.escapeSelector(s):e.setAttribute("id",s=S)),o=(l=Y(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+Q(l[o]);c=l.join(",")}try{return k.apply(n,f.querySelectorAll(c)),n}catch(e){h(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return re(t.replace(ve,"$1"),e,n,r)}function W(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function F(e){return e[S]=!0,e}function $(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function B(t){return function(e){return fe(e,"input")&&e.type===t}}function _(t){return function(e){return(fe(e,"input")||fe(e,"button"))&&e.type===t}}function z(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&R(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function X(a){return F(function(o){return o=+o,F(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function U(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function V(e){var t,n=e?e.ownerDocument||e:ye;return n!=T&&9===n.nodeType&&n.documentElement&&(r=(T=n).documentElement,C=!ce.isXMLDoc(T),i=r.matches||r.webkitMatchesSelector||r.msMatchesSelector,r.msMatchesSelector&&ye!=T&&(t=T.defaultView)&&t.top!==t&&t.addEventListener("unload",M),le.getById=$(function(e){return r.appendChild(e).id=ce.expando,!T.getElementsByName||!T.getElementsByName(ce.expando).length}),le.disconnectedMatch=$(function(e){return i.call(e,"*")}),le.scope=$(function(){return T.querySelectorAll(":scope")}),le.cssHas=$(function(){try{return T.querySelector(":has(*,:jqfake)"),!1}catch(e){return!0}}),le.getById?(b.filter.ID=function(e){var t=e.replace(O,P);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(O,P);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):t.querySelectorAll(e)},b.find.CLASS=function(e,t){if("undefined"!=typeof t.getElementsByClassName&&C)return t.getElementsByClassName(e)},d=[],$(function(e){var t;r.appendChild(e).innerHTML="",e.querySelectorAll("[selected]").length||d.push("\\["+ge+"*(?:value|"+f+")"),e.querySelectorAll("[id~="+S+"-]").length||d.push("~="),e.querySelectorAll("a#"+S+"+*").length||d.push(".#.+[+~]"),e.querySelectorAll(":checked").length||d.push(":checked"),(t=T.createElement("input")).setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),r.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&d.push(":enabled",":disabled"),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||d.push("\\["+ge+"*name"+ge+"*="+ge+"*(?:''|\"\")")}),le.cssHas||d.push(":has"),d=d.length&&new RegExp(d.join("|")),l=function(e,t){if(e===t)return a=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!le.sortDetached&&t.compareDocumentPosition(e)===n?e===T||e.ownerDocument==ye&&I.contains(ye,e)?-1:t===T||t.ownerDocument==ye&&I.contains(ye,t)?1:o?se.call(o,e)-se.call(o,t):0:4&n?-1:1)}),T}for(e in I.matches=function(e,t){return I(e,null,null,t)},I.matchesSelector=function(e,t){if(V(e),C&&!h[t+" "]&&(!d||!d.test(t)))try{var n=i.call(e,t);if(n||le.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){h(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(O,P),e[3]=(e[3]||e[4]||e[5]||"").replace(O,P),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||I.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&I.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return D.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&j.test(n)&&(t=Y(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(O,P).toLowerCase();return"*"===e?function(){return!0}:function(e){return fe(e,t)}},CLASS:function(e){var t=s[e+" "];return t||(t=new RegExp("(^|"+ge+")"+e+"("+ge+"|$)"))&&s(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=I.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function T(e,n,r){return v(n)?ce.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?ce.grep(e,function(e){return e===n!==r}):"string"!=typeof n?ce.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(ce.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||k,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:S.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof ce?t[0]:t,ce.merge(this,ce.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:C,!0)),w.test(r[1])&&ce.isPlainObject(t))for(r in t)v(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=C.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):v(e)?void 0!==n.ready?n.ready(e):e(ce):ce.makeArray(e,this)}).prototype=ce.fn,k=ce(C);var E=/^(?:parents|prev(?:Until|All))/,j={children:!0,contents:!0,next:!0,prev:!0};function A(e,t){while((e=e[t])&&1!==e.nodeType);return e}ce.fn.extend({has:function(e){var t=ce(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,Ce=/^$|^module$|\/(?:java|ecma)script/i;xe=C.createDocumentFragment().appendChild(C.createElement("div")),(be=C.createElement("input")).setAttribute("type","radio"),be.setAttribute("checked","checked"),be.setAttribute("name","t"),xe.appendChild(be),le.checkClone=xe.cloneNode(!0).cloneNode(!0).lastChild.checked,xe.innerHTML="",le.noCloneChecked=!!xe.cloneNode(!0).lastChild.defaultValue,xe.innerHTML="",le.option=!!xe.lastChild;var ke={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function Se(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&fe(e,t)?ce.merge([e],n):n}function Ee(e,t){for(var n=0,r=e.length;n",""]);var je=/<|&#?\w+;/;function Ae(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function Re(e,t){return fe(e,"table")&&fe(11!==t.nodeType?t:t.firstChild,"tr")&&ce(e).children("tbody")[0]||e}function Ie(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function We(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Fe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(_.hasData(e)&&(s=_.get(e).events))for(i in _.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),C.head.appendChild(r[0])},abort:function(){i&&i()}}});var Jt,Kt=[],Zt=/(=)\?(?=&|$)|\?\?/;ce.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Kt.pop()||ce.expando+"_"+jt.guid++;return this[e]=!0,e}}),ce.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Zt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Zt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=v(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Zt,"$1"+r):!1!==e.jsonp&&(e.url+=(At.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||ce.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=ie[r],ie[r]=function(){o=arguments},n.always(function(){void 0===i?ce(ie).removeProp(r):ie[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Kt.push(r)),o&&v(i)&&i(o[0]),o=i=void 0}),"script"}),le.createHTMLDocument=((Jt=C.implementation.createHTMLDocument("").body).innerHTML="
",2===Jt.childNodes.length),ce.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(le.createHTMLDocument?((r=(t=C.implementation.createHTMLDocument("")).createElement("base")).href=C.location.href,t.head.appendChild(r)):t=C),o=!n&&[],(i=w.exec(e))?[t.createElement(i[1])]:(i=Ae([e],t,o),o&&o.length&&ce(o).remove(),ce.merge([],i.childNodes)));var r,i,o},ce.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(ce.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},ce.expr.pseudos.animated=function(t){return ce.grep(ce.timers,function(e){return t===e.elem}).length},ce.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=ce.css(e,"position"),c=ce(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=ce.css(e,"top"),u=ce.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),v(t)&&(t=t.call(e,n,ce.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},ce.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){ce.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===ce.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===ce.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=ce(e).offset()).top+=ce.css(e,"borderTopWidth",!0),i.left+=ce.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-ce.css(r,"marginTop",!0),left:t.left-i.left-ce.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===ce.css(e,"position"))e=e.offsetParent;return e||J})}}),ce.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;ce.fn[t]=function(e){return M(this,function(e,t,n){var r;if(y(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),ce.each(["top","left"],function(e,n){ce.cssHooks[n]=Ye(le.pixelPosition,function(e,t){if(t)return t=Ge(e,n),_e.test(t)?ce(e).position()[n]+"px":t})}),ce.each({Height:"height",Width:"width"},function(a,s){ce.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){ce.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return M(this,function(e,t,n){var r;return y(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?ce.css(e,t,i):ce.style(e,t,n,i)},s,n?e:void 0,n)}})}),ce.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){ce.fn[t]=function(e){return this.on(t,e)}}),ce.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.on("mouseenter",e).on("mouseleave",t||e)}}),ce.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){ce.fn[n]=function(e,t){return 0=0; x--) { + obj.callbacks[callbacks[x]] = []; + } + + obj.addHook = function (hook) { + if (!obj.callbacks[hook]) + obj.callbacks[hook] = []; + } + + obj.addCallback = function (hook, func) { + obj.callbacks[hook].push(func); + } + + obj.removeCallback = function (hook, funcName) { + for (var i=0;i=0; x--) { + // $rdf.log.info('@@ Firing '+hook+' callback '+ obj.callbacks[hook][x]) + if (obj.callbacks[hook][x].apply(obj,args)) { + newCallbacks.push(obj.callbacks[hook][x]) + } + } + + for (var x=newCallbacks.length-1; x>=0; x--) { + replaceCallbacks.push(newCallbacks[x]) + } + + for (var x=len; x 0) { + var pair = lines[x].split(': ') + if (typeof pair[1] == "undefined") { // continuation + headers[last] += "\n"+pair[0] + } else { + last = pair[0].toLowerCase() + headers[last] = pair[1] + } + } + } + return headers + }, + + 'dtstamp': function () { + var now = new Date(); + var year = now.getYear() + 1900; + var month = now.getMonth() + 1; + var day = now.getDate(); + var hour = now.getUTCHours(); + var minute = now.getUTCMinutes(); + var second = now.getSeconds(); + if (month < 10) month = "0" + month; + if (day < 10) day = "0" + day; + if (hour < 10) hour = "0" + hour; + if (minute < 10) minute = "0" + minute; + if (second < 10) second = "0" + second; + return year + "-" + month + "-" + day + "T" + + hour + ":" + minute + ":" + second + "Z"; + }, + + 'enablePrivilege': ((typeof netscape != 'undefined') && (typeof netscape.security.PrivilegeManager != 'undefined') && netscape.security.PrivilegeManager.enablePrivilege) || function() { return; }, + 'disablePrivilege': ((typeof netscape != 'undefined') && (typeof netscape.security.PrivilegeManager != 'undefined') && netscape.security.PrivilegeManager.disablePrivilege) || function() { return; }, + + + + 'RDFArrayRemove': function(a, x) { //removes all statements equal to x from a + for(var i=0; i to <" + docuri + ">") + } + sf.requestURI(docuri, requestedBy); + }, //AJAR_handleNewTerm + 'ArrayIndexOf': function(arr, item, i) { + i || (i = 0); + var length = arr.length; + if (i < 0) i = length + i; + for (; i < length; i++) + if (arr[i] === item) return i; + return -1; + } + +}; + + +////////////////// find the variables in a graph +// SHALLOW +// used? +// +$rdf.Util.variablesIn = function(g) { + for (var i=0; i signature(y)) return +1; + if (signature(x) < signature(y)) return -1; + return x.compareTerm(y); // Too bad -- this order not canonical. + //throw "different bnodes indistinquishable for sorting" + } else { + return x.compareTerm(y); + } +}; + +$rdf.Util.heavyCompareSPO = function(x, y, g) { + var comp = $rdf.Util.heavyCompare; + var d = comp(x.subject, y.subject, g); + if (d) return d; + d = comp(x.predicate, y.predicate, g); + if (d) return d; + return comp(x.object, y.object, g); +}; + + +///////////////////// Parse XML +// +// Returns: A DOM +// + +$rdf.Util.parseXML = function(str) { + var dparser; + if ((typeof tabulator != 'undefined' && tabulator.isExtension)) { + dparser = Components.classes["@mozilla.org/xmlextras/domparser;1"].getService( + Components.interfaces.nsIDOMParser); + } else if (typeof module != 'undefined' && module && module.exports){ // Node.js + //var libxmljs = require('libxmljs'); // Was jsdom before 2012-01 then libxmljs but that nonstandard + //return libxmljs.parseXmlString(str); + var jsdom = require('jsdom'); + var dom = jsdom.jsdom(str, undefined, {} );// html, level, options + return dom + } else { + dparser = new DOMParser(); + } + return dparser.parseFromString(str, 'application/xml'); +}; + + +//////////////////////String Utility +// substitutes given terms for occurrnces of %s +// not well named. Used??? - tim +// +$rdf.Util.string = { + //C++, python style %s -> subs + 'template': function(base, subs){ + var baseA = base.split("%s"); + var result = ""; + for (var i=0;i 0) { + base = base.slice(0, baseHash); + } + if (given.length === 0) { + return base; + } + if (given.indexOf('#') === 0) { + return base + given; + } + colon = given.indexOf(':'); + if (colon >= 0) { + return given; + } + baseColon = base.indexOf(':'); + if (base.length === 0) { + return given; + } + if (baseColon < 0) { + alert("Invalid base: " + base + " in join with given: " + given); + return given; + } + baseScheme = base.slice(0, +baseColon + 1 || 9e9); + if (given.indexOf('//') === 0) { + return baseScheme + given; + } + if (base.indexOf('//', baseColon) === baseColon + 1) { + baseSingle = base.indexOf('/', baseColon + 3); + if (baseSingle < 0) { + if (base.length - baseColon - 3 > 0) { + return base + '/' + given; + } else { + return baseScheme + given; + } + } + } else { + baseSingle = base.indexOf('/', baseColon + 1); + if (baseSingle < 0) { + if (base.length - baseColon - 1 > 0) { + return base + '/' + given; + } else { + return baseScheme + given; + } + } + } + if (given.indexOf('/') === 0) { + return base.slice(0, baseSingle) + given; + } + path = base.slice(baseSingle); + lastSlash = path.lastIndexOf('/'); + if (lastSlash < 0) { + return baseScheme + given; + } + if (lastSlash >= 0 && lastSlash < path.length - 1) { + path = path.slice(0, +lastSlash + 1 || 9e9); + } + path += given; + while (path.match(/[^\/]*\/\.\.\//)) { + path = path.replace(/[^\/]*\/\.\.\//, ''); + } + path = path.replace(/\.\//g, ''); + path = path.replace(/\/\.$/, '/'); + return base.slice(0, baseSingle) + path; + }; + + uri.commonHost = new RegExp('^[-_a-zA-Z0-9.]+:(//[^/]*)?/[^/]*$'); + + uri.hostpart = function(u) { + var m; + m = /[^\/]*\/\/([^\/]*)\//.exec(u); + if (m) { + return m[1]; + } else { + return ''; + } + }; + + uri.refTo = function(base, uri) { + var c, i, j, k, l, n, s, _i, _j, _k, _len, _len1, _ref; + if (!base) { + return uri; + } + if (base === uri) { + return ''; + } + for (i = _i = 0, _len = uri.length; _i < _len; i = ++_i) { + c = uri[i]; + if (c !== base[i]) { + break; + } + } + if (base.slice(0, i).match($rdf.Util.uri.commonHost)) { + k = uri.indexOf('//'); + if (k < 0) { + k = -2; + } + l = uri.indexOf('/', k + 2); + if (uri[l + 1] !== '/' && base[l + 1] !== '/' && uri.slice(0, l) === base.slice(0, l)) { + return uri.slice(l); + } + } + if (uri[i] === '#' && base.length === i) { + return uri.slice(i); + } + while (i > 0 && uri[i - 1] !== '/') { + i--; + } + if (i < 3) { + return uri; + } + if (base.indexOf('//', i - 2) > 0 || uri.indexOf('//', i - 2) > 0) { + return uri; + } + if (base.indexOf(':', i) > 0) { + return uri; + } + n = 0; + _ref = base.slice(i); + for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) { + c = _ref[_j]; + if (c === '/') { + n++; + } + } + if (n === 0 && i < uri.length && uri[i] === '#') { + return './' + uri.slice(i); + } + if (n === 0 && i === uri.length) { + return './'; + } + s = ''; + if (n > 0) { + for (j = _k = 1; 1 <= n ? _k <= n : _k >= n; j = 1 <= n ? ++_k : --_k) { + s += '../'; + } + } + return s + uri.slice(i); + }; + + uri.docpart = function(uri) { + var i; + i = uri.indexOf('#'); + if (i < 0) { + return uri; + } else { + return uri.slice(0, i); + } + }; + + uri.document = function(x) { + return $rdf.sym(uri.docpart(x.uri)); + }; + + uri.protocol = function(uri) { + var i; + i = uri.indexOf(':'); + if (i < 0) { + return null; + } else { + return uri.slice(0, i); + } + }; + + return uri; + +})(); + +$rdf.Util.uri = $rdf.uri; + +if ((typeof module !== "undefined" && module !== null ? module.exports : void 0) != null) { + if ((_base = module.exports).Util == null) { + _base.Util = {}; + } + _ref = $rdf.Util; + for (k in _ref) { + if (!__hasProp.call(_ref, k)) continue; + v = _ref[k]; + module.exports.Util[k] = v; + } + module.exports.uri = $rdf.uri; +} +/* + * These are the classes corresponding to the RDF and N3 data models + * + * Designed to look like rdflib and cwm + * + * This is coffee see http://coffeescript.org + */ +var $rdf, k, v, + __hasProp = {}.hasOwnProperty, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + +if (typeof $rdf === "undefined" || $rdf === null) { + $rdf = {}; +} + + +/* + the superclass of all RDF Statement objects, that is + $rdf.Symbol, $rdf.Literal, $rdf.BlankNode + No class extends this yet, but it could be a place to put common behavior. + */ + +$rdf.Node = (function() { + function Node() {} + + Node.prototype.substitute = function(bindings) { + return this; + }; + + return Node; + +})(); + +$rdf.Empty = (function(_super) { + __extends(Empty, _super); + + function Empty() { + return Empty.__super__.constructor.apply(this, arguments); + } + + Empty.prototype.termType = 'empty'; + + Empty.prototype.toString = function() { + return '()'; + }; + + Empty.prototype.toNT = Empty.prototype.toString; + + return Empty; + +})($rdf.Node); + + +/* + A named node in an RDF graph + todo: badly named. + No, formally a URI is a string, this is a node whose name is a URI. + Connolly pointed out it isa symbol on the language. + @param uri the uri as string + */ + +$rdf.Symbol = (function(_super) { + __extends(Symbol, _super); + + function Symbol(uri) { + this.uri = uri; + this.value = this.uri; + } + + Symbol.prototype.termType = 'symbol'; + + Symbol.prototype.toString = function() { + return "<" + this.uri + ">"; + }; + + Symbol.prototype.toNT = Symbol.prototype.toString; + + Symbol.prototype.sameTerm = function(other) { + if (!other) { + return false; + } + return (this.termType === other.termType) && (this.uri === other.uri); + }; + + Symbol.prototype.compareTerm = function(other) { + if (this.classOrder < other.classOrder) { + return -1; + } + if (this.classOrder > other.classOrder) { + return +1; + } + if (this.uri < other.uri) { + return -1; + } + if (this.uri > other.uri) { + return +1; + } + return 0; + }; + + Symbol.prototype.XSDboolean = new Symbol('http://www.w3.org/2001/XMLSchema#boolean'); + + Symbol.prototype.XSDdecimal = new Symbol('http://www.w3.org/2001/XMLSchema#decimal'); + + Symbol.prototype.XSDfloat = new Symbol('http://www.w3.org/2001/XMLSchema#float'); + + Symbol.prototype.XSDinteger = new Symbol('http://www.w3.org/2001/XMLSchema#integer'); + + Symbol.prototype.XSDdateTime = new Symbol('http://www.w3.org/2001/XMLSchema#dateTime'); + + Symbol.prototype.integer = new Symbol('http://www.w3.org/2001/XMLSchema#integer'); + + return Symbol; + +})($rdf.Node); + +if ($rdf.NextId != null) { + $rdf.log.error("Attempt to re-zero existing blank node id counter at " + $rdf.NextId); +} else { + $rdf.NextId = 0; +} + +$rdf.NTAnonymousNodePrefix = "_:n"; + +$rdf.BlankNode = (function(_super) { + __extends(BlankNode, _super); + + function BlankNode(id) { + this.id = $rdf.NextId++; + this.value = id ? id : this.id.toString(); + } + + BlankNode.prototype.termType = 'bnode'; + + BlankNode.prototype.toNT = function() { + return $rdf.NTAnonymousNodePrefix + this.id; + }; + + BlankNode.prototype.toString = BlankNode.prototype.toNT; + + BlankNode.prototype.sameTerm = function(other) { + if (!other) { + return false; + } + return (this.termType === other.termType) && (this.id === other.id); + }; + + BlankNode.prototype.compareTerm = function(other) { + if (this.classOrder < other.classOrder) { + return -1; + } + if (this.classOrder > other.classOrder) { + return +1; + } + if (this.id < other.id) { + return -1; + } + if (this.id > other.id) { + return +1; + } + return 0; + }; + + return BlankNode; + +})($rdf.Node); + +$rdf.Literal = (function(_super) { + __extends(Literal, _super); + + function Literal(value, lang, datatype) { + this.value = value; + this.lang = lang; + this.datatype = datatype; + if (this.lang == null) { + this.lang = void 0; + } + if (this.datatype == null) { + this.datatype = void 0; + } + } + + Literal.prototype.termType = 'literal'; + + Literal.prototype.toString = function() { + return "" + this.value; + }; + + Literal.prototype.toNT = function() { + var str; + str = this.value; + if (typeof str === !'string') { + if (typeof str === 'number') { + return '' + str; + } + throw Error("Value of RDF literal is not string: " + str); + } + str = str.replace(/\\/g, '\\\\'); + str = str.replace(/\"/g, '\\"'); + str = str.replace(/\n/g, '\\n'); + str = "\"" + str + "\""; + if (this.datatype) { + str += '^^' + this.datatype.toNT(); + } + if (this.lang) { + str += '@' + this.lang; + } + return str; + }; + + Literal.prototype.sameTerm = function(other) { + if (!other) { + return false; + } + return (this.termType === other.termType) && (this.value === other.value) && (this.lang === other.lang) && ((!this.datatype && !other.datatype) || (this.datatype && this.datatype.sameTerm(other.datatype))); + }; + + Literal.prototype.compareTerm = function(other) { + if (this.classOrder < other.classOrder) { + return -1; + } + if (this.classOrder > other.classOrder) { + return +1; + } + if (this.value < other.value) { + return -1; + } + if (this.value > other.value) { + return +1; + } + return 0; + }; + + return Literal; + +})($rdf.Node); + +$rdf.Collection = (function(_super) { + __extends(Collection, _super); + + function Collection(initial) { + var s, _i, _len; + this.id = $rdf.NextId++; + this.elements = []; + this.closed = false; + if (typeof initial !== 'undefined') { + for (_i = 0, _len = initial.length; _i < _len; _i++) { + s = initial[_i]; + this.elements.push($rdf.term(s)); + } + } + } + + Collection.prototype.termType = 'collection'; + + Collection.prototype.toNT = function() { + return $rdf.NTAnonymousNodePrefix + this.id; + }; + + Collection.prototype.toString = function() { + return '(' + this.elements.join(' ') + ')'; + }; + + Collection.prototype.substitute = function(bindings) { + var s; + return new $rdf.Collection((function() { + var _i, _len, _ref, _results; + _ref = this.elements; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + s = _ref[_i]; + _results.push(s.substitute(bindings)); + } + return _results; + }).call(this)); + }; + + Collection.prototype.append = function(el) { + return this.elements.push(el); + }; + + Collection.prototype.unshift = function(el) { + return this.elements.unshift(el); + }; + + Collection.prototype.shift = function() { + return this.elements.shift(); + }; + + Collection.prototype.close = function() { + return this.closed = true; + }; + + return Collection; + +})($rdf.Node); + +$rdf.Collection.prototype.sameTerm = $rdf.BlankNode.prototype.sameTerm; + +$rdf.Collection.prototype.compareTerm = $rdf.BlankNode.prototype.compareTerm; + + +/* + function to transform a value into an $rdf.Node + @param val can be an rdf.Node, a date, string, number, boolean, or undefined. RDF Nodes are returned as is, + undefined as undefined + */ + +$rdf.term = function(val) { + var d2, dt, elt, value, x, _i, _len; + switch (typeof val) { + case 'object': + if (val instanceof Date) { + d2 = function(x) { + return ('' + (100 + x)).slice(1, 3); + }; + value = '' + val.getUTCFullYear() + '-' + d2(val.getUTCMonth() + 1) + '-' + d2(val.getUTCDate()) + 'T' + d2(val.getUTCHours()) + ':' + d2(val.getUTCMinutes()) + ':' + d2(val.getUTCSeconds()) + 'Z'; + return new $rdf.Literal(value, void 0, $rdf.Symbol.prototype.XSDdateTime); + } else if (val instanceof Array) { + x = new $rdf.Collection; + for (_i = 0, _len = val.length; _i < _len; _i++) { + elt = val[_i]; + x.append($rdf.term(elt)); + } + return x; + } + return val; + case 'string': + return new $rdf.Literal(val); + case 'number': + if (('' + val).indexOf('e') >= 0) { + dt = $rdf.Symbol.prototype.XSDfloat; + } else if (('' + val).indexOf('.') >= 0) { + dt = $rdf.Symbol.prototype.XSDdecimal; + } else { + dt = $rdf.Symbol.prototype.XSDinteger; + } + return new $rdf.Literal('' + val, void 0, dt); + case 'boolean': + return new $rdf.Literal((val ? '1' : '0'), void 0, $rdf.Symbol.prototype.XSDboolean); + case 'undefined': + return void 0; + } + throw ("Can't make term from " + val + " of type ") + typeof val; +}; + +$rdf.Statement = (function() { + function Statement(subject, predicate, object, why) { + this.subject = $rdf.term(subject); + this.predicate = $rdf.term(predicate); + this.object = $rdf.term(object); + if (why != null) { + this.why = why; + } + } + + Statement.prototype.toNT = function() { + return [this.subject.toNT(), this.predicate.toNT(), this.object.toNT()].join(' ') + ' .'; + }; + + Statement.prototype.toString = Statement.prototype.toNT; + + Statement.prototype.substitute = function(bindings) { + return new $rdf.Statement(this.subject.substitute(bindings), this.predicate.substitute(bindings), this.object.substitute(bindings), this.why); + }; + + return Statement; + +})(); + +$rdf.st = function(subject, predicate, object, why) { + return new $rdf.Statement(subject, predicate, object, why); +}; + +$rdf.Formula = (function(_super) { + __extends(Formula, _super); + + function Formula() { + this.statements = []; + this.constraints = []; + this.initBindings = []; + this.optional = []; + } + + Formula.prototype.termType = 'formula'; + + Formula.prototype.toNT = function() { + return '{' + this.statements.join('\n') + '}'; + }; + + Formula.prototype.toString = Formula.prototype.toNT; + + Formula.prototype.add = function(s, p, o, why) { + return this.statements.push(new $rdf.Statement(s, p, o, why)); + }; + + Formula.prototype.addStatement = function(st) { + return this.statements.push(st); + }; + + Formula.prototype.substitute = function(bindings) { + var g, s, _i, _len, _ref; + g = new $rdf.Formula; + _ref = this.statements; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + s = _ref[_i]; + g.addStatement(s.substitute(bindings)); + } + return g; + }; + + Formula.prototype.sym = function(uri, name) { + if (name != null) { + throw 'This feature (kb.sym with 2 args) is removed. Do not assume prefix mappings.'; + if (!$rdf.ns[uri]) { + throw "The prefix " + uri + " is not set in the API"; + } + uri = $rdf.ns[uri] + name; + } + return new $rdf.Symbol(uri); + }; + + Formula.prototype.literal = function(val, lang, dt) { + return new $rdf.Literal("" + val, lang, dt); + }; + + Formula.prototype.bnode = function(id) { + return new $rdf.BlankNode(id); + }; + + Formula.prototype.formula = function() { + return new $rdf.Formula; + }; + + Formula.prototype.collection = function() { + return new $rdf.Collection; + }; + + Formula.prototype.list = function(values) { + var elt, r, _i, _len; + r = new $rdf.Collection; + if (values) { + for (_i = 0, _len = values.length; _i < _len; _i++) { + elt = values[_i]; + r.append(elt); + } + } + return r; + }; + + Formula.prototype.variable = function(name) { + return new $rdf.Variable(name); + }; + + Formula.prototype.ns = function(nsuri) { + return function(ln) { + return new $rdf.Symbol(nsuri + (ln != null ? ln : '')); + }; + }; + + + /* + transform an NTriples string format into an $rdf.Node + The bnode bit should not be used on program-external values; designed + for internal work such as storing a bnode id in an HTML attribute. + This will only parse the strings generated by the vaious toNT() methods. + */ + + Formula.prototype.fromNT = function(str) { + var dt, k, lang, x; + switch (str[0]) { + case '<': + return $rdf.sym(str.slice(1, -1)); + case '"': + lang = void 0; + dt = void 0; + k = str.lastIndexOf('"'); + if (k < str.length - 1) { + if (str[k + 1] === '@') { + lang = str.slice(k + 2); + } else if (str.slice(k + 1, k + 3) === '^^') { + dt = $rdf.fromNT(str.slice(k + 3)); + } else { + throw "Can't convert string from NT: " + str; + } + } + str = str.slice(1, k); + str = str.replace(/\\"/g, '"'); + str = str.replace(/\\n/g, '\n'); + str = str.replace(/\\\\/g, '\\'); + return $rdf.lit(str, lang, dt); + case '_': + x = new $rdf.BlankNode; + x.id = parseInt(str.slice(3)); + $rdf.NextId--; + return x; + case '?': + return new $rdf.Variable(str.slice(1)); + } + throw "Can't convert from NT: " + str; + }; + + Formula.prototype.sameTerm = function(other) { + if (!other) { + return false; + } + return this.hashString() === other.hashString(); + }; + + Formula.prototype.each = function(s, p, o, w) { + var elt, results, sts, _i, _j, _k, _l, _len, _len1, _len2, _len3; + results = []; + sts = this.statementsMatching(s, p, o, w, false); + if (s == null) { + for (_i = 0, _len = sts.length; _i < _len; _i++) { + elt = sts[_i]; + results.push(elt.subject); + } + } else if (p == null) { + for (_j = 0, _len1 = sts.length; _j < _len1; _j++) { + elt = sts[_j]; + results.push(elt.predicate); + } + } else if (o == null) { + for (_k = 0, _len2 = sts.length; _k < _len2; _k++) { + elt = sts[_k]; + results.push(elt.object); + } + } else if (w == null) { + for (_l = 0, _len3 = sts.length; _l < _len3; _l++) { + elt = sts[_l]; + results.push(elt.why); + } + } + return results; + }; + + Formula.prototype.any = function(s, p, o, w) { + var st; + st = this.anyStatementMatching(s, p, o, w); + if (st == null) { + return void 0; + } else if (s == null) { + return st.subject; + } else if (p == null) { + return st.predicate; + } else if (o == null) { + return st.object; + } + return void 0; + }; + + Formula.prototype.holds = function(s, p, o, w) { + var st; + st = this.anyStatementMatching(s, p, o, w); + return st != null; + }; + + Formula.prototype.holdsStatement = function(st) { + return this.holds(st.subject, st.predicate, st.object, st.why); + }; + + Formula.prototype.the = function(s, p, o, w) { + var x; + x = this.any(s, p, o, w); + if (x == null) { + $rdf.log.error("No value found for the() {" + s + " " + p + " " + o + "}."); + } + return x; + }; + + Formula.prototype.whether = function(s, p, o, w) { + return this.statementsMatching(s, p, o, w, false).length; + }; + + Formula.prototype.transitiveClosure = function(seeds, predicate, inverse) { + var agenda, done, elt, k, s, sups, t, v, _i, _len; + done = {}; + agenda = {}; + for (k in seeds) { + if (!__hasProp.call(seeds, k)) continue; + v = seeds[k]; + agenda[k] = v; + } + while (true) { + t = (function() { + var p; + for (p in agenda) { + if (!__hasProp.call(agenda, p)) continue; + return p; + } + })(); + if (t == null) { + return done; + } + sups = inverse ? this.each(void 0, predicate, this.fromNT(t)) : this.each(this.fromNT(t), predicate); + for (_i = 0, _len = sups.length; _i < _len; _i++) { + elt = sups[_i]; + s = elt.toNT(); + if (s in done) { + continue; + } + if (s in agenda) { + continue; + } + agenda[s] = agenda[t]; + } + done[t] = agenda[t]; + delete agenda[t]; + } + }; + + + /* + For thisClass or any subclass, anything which has it is its type + or is the object of something which has the type as its range, or subject + of something which has the type as its domain + We don't bother doing subproperty (yet?)as it doesn't seeem to be used much. + Get all the Classes of which we can RDFS-infer the subject is a member + @returns a hash of URIs + */ + + Formula.prototype.findMembersNT = function(thisClass) { + var members, pred, seeds, st, t, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _ref, _ref1, _ref2, _ref3, _ref4, _ref5; + seeds = {}; + seeds[thisClass.toNT()] = true; + members = {}; + _ref = this.transitiveClosure(seeds, this.sym('http://www.w3.org/2000/01/rdf-schema#subClassOf'), true); + for (t in _ref) { + if (!__hasProp.call(_ref, t)) continue; + _ref1 = this.statementsMatching(void 0, this.sym('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), this.fromNT(t)); + for (_i = 0, _len = _ref1.length; _i < _len; _i++) { + st = _ref1[_i]; + members[st.subject.toNT()] = st; + } + _ref2 = this.each(void 0, this.sym('http://www.w3.org/2000/01/rdf-schema#domain'), this.fromNT(t)); + for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) { + pred = _ref2[_j]; + _ref3 = this.statementsMatching(void 0, pred); + for (_k = 0, _len2 = _ref3.length; _k < _len2; _k++) { + st = _ref3[_k]; + members[st.subject.toNT()] = st; + } + } + _ref4 = this.each(void 0, this.sym('http://www.w3.org/2000/01/rdf-schema#range'), this.fromNT(t)); + for (_l = 0, _len3 = _ref4.length; _l < _len3; _l++) { + pred = _ref4[_l]; + _ref5 = this.statementsMatching(void 0, pred); + for (_m = 0, _len4 = _ref5.length; _m < _len4; _m++) { + st = _ref5[_m]; + members[st.object.toNT()] = st; + } + } + } + return members; + }; + + + /* + transform a collection of NTriple URIs into their URI strings + @param t some iterable colletion of NTriple URI strings + @return a collection of the URIs as strings + todo: explain why it is important to go through NT + */ + + Formula.prototype.NTtoURI = function(t) { + var k, uris, v; + uris = {}; + for (k in t) { + if (!__hasProp.call(t, k)) continue; + v = t[k]; + if (k[0] === '<') { + uris[k.slice(1, -1)] = v; + } + } + return uris; + }; + + Formula.prototype.findTypeURIs = function(subject) { + return this.NTtoURI(this.findTypesNT(subject)); + }; + + Formula.prototype.findMemberURIs = function(subject) { + return this.NTtoURI(this.findMembersNT(subject)); + }; + + + /* + Get all the Classes of which we can RDFS-infer the subject is a member + todo: This will loop is there is a class subclass loop (Sublass loops are not illegal) + Returns a hash table where key is NT of type and value is statement why we think so. + Does NOT return terms, returns URI strings. + We use NT representations in this version because they handle blank nodes. + */ + + Formula.prototype.findTypesNT = function(subject) { + var domain, range, rdftype, st, types, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1, _ref2, _ref3; + rdftype = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'; + types = []; + _ref = this.statementsMatching(subject, void 0, void 0); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + st = _ref[_i]; + if (st.predicate.uri === rdftype) { + types[st.object.toNT()] = st; + } else { + _ref1 = this.each(st.predicate, this.sym('http://www.w3.org/2000/01/rdf-schema#domain')); + for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { + range = _ref1[_j]; + types[range.toNT()] = st; + } + } + } + _ref2 = this.statementsMatching(void 0, void 0, subject); + for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) { + st = _ref2[_k]; + _ref3 = this.each(st.predicate, this.sym('http://www.w3.org/2000/01/rdf-schema#range')); + for (_l = 0, _len3 = _ref3.length; _l < _len3; _l++) { + domain = _ref3[_l]; + types[domain.toNT()] = st; + } + } + return this.transitiveClosure(types, this.sym('http://www.w3.org/2000/01/rdf-schema#subClassOf'), false); + }; + + + /* + Get all the Classes of which we can RDFS-infer the subject is a subclass + Returns a hash table where key is NT of type and value is statement why we think so. + Does NOT return terms, returns URI strings. + We use NT representations in this version because they handle blank nodes. + */ + + Formula.prototype.findSuperClassesNT = function(subject) { + var types; + types = []; + types[subject.toNT()] = true; + return this.transitiveClosure(types, this.sym('http://www.w3.org/2000/01/rdf-schema#subClassOf'), false); + }; + + + /* + Get all the Classes of which we can RDFS-infer the subject is a superclass + Returns a hash table where key is NT of type and value is statement why we think so. + Does NOT return terms, returns URI strings. + We use NT representations in this version because they handle blank nodes. + */ + + Formula.prototype.findSubClassesNT = function(subject) { + var types; + types = []; + types[subject.toNT()] = true; + return this.transitiveClosure(types, this.sym('http://www.w3.org/2000/01/rdf-schema#subClassOf'), true); + }; + + + /* + Find the types in the list which have no *stored* supertypes + We exclude the universal class, owl:Things and rdf:Resource, as it is information-free. + */ + + Formula.prototype.topTypeURIs = function(types) { + var j, k, n, tops, v, _i, _len, _ref; + tops = []; + for (k in types) { + if (!__hasProp.call(types, k)) continue; + v = types[k]; + n = 0; + _ref = this.each(this.sym(k), this.sym('http://www.w3.org/2000/01/rdf-schema#subClassOf')); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + j = _ref[_i]; + if (j.uri !== 'http://www.w3.org/2000/01/rdf-schema#Resource') { + n++; + break; + } + } + if (!n) { + tops[k] = v; + } + } + if (tops['http://www.w3.org/2000/01/rdf-schema#Resource']) { + delete tops['http://www.w3.org/2000/01/rdf-schema#Resource']; + } + if (tops['http://www.w3.org/2002/07/owl#Thing']) { + delete tops['http://www.w3.org/2002/07/owl#Thing']; + } + return tops; + }; + + + /* + Find the types in the list which have no *stored* subtypes + These are a set of classes which provide by themselves complete + information -- the other classes are redundant for those who + know the class DAG. + */ + + Formula.prototype.bottomTypeURIs = function(types) { + var bots, bottom, elt, k, subs, v, _i, _len, _ref; + bots = []; + for (k in types) { + if (!__hasProp.call(types, k)) continue; + v = types[k]; + subs = this.each(void 0, this.sym('http://www.w3.org/2000/01/rdf-schema#subClassOf'), this.sym(k)); + bottom = true; + for (_i = 0, _len = subs.length; _i < _len; _i++) { + elt = subs[_i]; + if (_ref = elt.uri, __indexOf.call(types, _ref) >= 0) { + bottom = false; + break; + } + } + if (bottom) { + bots[k] = v; + } + } + return bots; + }; + + Formula.prototype.serialize = function(base, contentType, provenance) { + var documentString, sts, sz; + sz = $rdf.Serializer(this); + sz.suggestNamespaces(this.namespaces); + sz.setBase(base); + if (provenance) { + sts = this.statementsMatching(void 0, void 0, void 0, provenance); + } else { + sts = this.statements; + } + switch (contentType != null ? contentType : 'text/n3') { + case 'application/rdf+xml': + documentString = sz.statementsToXML(sts); + break; + case 'text/n3': + case 'text/turtle': + documentString = sz.statementsToN3(sts); + break; + default: + throw "serialize: Content-type " + contentType(+" not supported."); + } + return documentString; + }; + + return Formula; + +})($rdf.Node); + +$rdf.sym = function(uri) { + return new $rdf.Symbol(uri); +}; + +$rdf.lit = $rdf.Formula.prototype.literal; + +$rdf.Namespace = $rdf.Formula.prototype.ns; + +$rdf.variable = $rdf.Formula.prototype.variable; + + +/* + * Variable + * + * Variables are placeholders used in patterns to be matched. + * In cwm they are symbols which are the formula's list of quantified variables. + * In sparl they are not visibily URIs. Here we compromise, by having + * a common special base URI for variables. Their names are uris, + * but the ? nottaion has an implicit base uri of 'varid:' + */ + +$rdf.Variable = (function(_super) { + __extends(Variable, _super); + + function Variable(rel) { + this.base = 'varid:'; + this.uri = $rdf.Util.uri.join(rel, this.base); + } + + Variable.prototype.termType = 'variable'; + + Variable.prototype.toNT = function() { + if (this.uri.slice(0, this.base.length) === this.base) { + return '?' + this.uri.slice(this.base.length); + } + return "?" + this.uri; + }; + + Variable.prototype.toString = Variable.prototype.toNT; + + Variable.prototype.hashString = Variable.prototype.toNT; + + Variable.prototype.substitute = function(bindings) { + var _ref; + return (_ref = bindings[this.toNT()]) != null ? _ref : this; + }; + + Variable.prototype.sameTerm = function(other) { + if (!other) { + false; + } + return (this.termType === other.termType) && (this.uri === other.uri); + }; + + return Variable; + +})($rdf.Node); + +$rdf.Literal.prototype.classOrder = 1; + +$rdf.Collection.prototype.classOrder = 3; + +$rdf.Formula.prototype.classOrder = 4; + +$rdf.Symbol.prototype.classOrder = 5; + +$rdf.BlankNode.prototype.classOrder = 6; + +$rdf.Variable.prototype.classOrder = 7; + +$rdf.fromNT = $rdf.Formula.prototype.fromNT; + +$rdf.graph = function() { + return new $rdf.IndexedFormula; +}; + +if ((typeof module !== "undefined" && module !== null ? module.exports : void 0) != null) { + for (k in $rdf) { + if (!__hasProp.call($rdf, k)) continue; + v = $rdf[k]; + module.exports[k] = v; + } +} +/** + * @fileoverview + * RDF/XML PARSER + * + * Version 0.1 + * Parser believed to be in full positive RDF/XML parsing compliance + * with the possible exception of handling deprecated RDF attributes + * appropriately. Parser is believed to comply fully with other W3C + * and industry standards where appropriate (DOM, ECMAScript, &c.) + * + * Author: David Sheets + * + * W3C® SOFTWARE NOTICE AND LICENSE + * http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 + * This work (and included software, documentation such as READMEs, or + * other related items) is being provided by the copyright holders under + * the following license. By obtaining, using and/or copying this work, + * you (the licensee) agree that you have read, understood, and will + * comply with the following terms and conditions. + * + * Permission to copy, modify, and distribute this software and its + * documentation, with or without modification, for any purpose and + * without fee or royalty is hereby granted, provided that you include + * the following on ALL copies of the software and documentation or + * portions thereof, including modifications: + * + * 1. The full text of this NOTICE in a location viewable to users of + * the redistributed or derivative work. + * 2. Any pre-existing intellectual property disclaimers, notices, or terms and + * conditions. If none exist, the W3C Software Short Notice should be + * included (hypertext is preferred, text is permitted) within the body + * of any redistributed or derivative code. + * 3. Notice of any changes or modifications to the files, including the + * date changes were made. (We recommend you provide URIs to the location + * from which the code is derived.) + * + * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT + * HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS + * FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR + * DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, + * TRADEMARKS OR OTHER RIGHTS. + * + * COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL + * OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR + * DOCUMENTATION. + * + * The name and trademarks of copyright holders may NOT be used in + * advertising or publicity pertaining to the software without specific, + * written prior permission. Title to copyright in this software and any + * associated documentation will at all times remain with copyright + * holders. + */ +/** + * @class Class defining an RDFParser resource object tied to an RDFStore + * + * @author David Sheets + * @version 0.1 + * + * @constructor + * @param {RDFStore} store An RDFStore object + */ + + $rdf.RDFParser = function(store){ + var RDFParser = {}; + + /** Standard namespaces that we know how to handle @final + * @member RDFParser + */ + RDFParser.ns = {'RDF': "http://www.w3.org/1999/02/22-rdf-syntax-ns#", 'RDFS': "http://www.w3.org/2000/01/rdf-schema#"}; + + /** DOM Level 2 node type magic numbers @final + * @member RDFParser + */ + RDFParser.nodeType = {'ELEMENT': 1, 'ATTRIBUTE': 2, 'TEXT': 3, + 'CDATA_SECTION': 4, 'ENTITY_REFERENCE': 5, + 'ENTITY': 6, 'PROCESSING_INSTRUCTION': 7, + 'COMMENT': 8, 'DOCUMENT': 9, 'DOCUMENT_TYPE': 10, + 'DOCUMENT_FRAGMENT': 11, 'NOTATION': 12}; + + /** + * Frame class for namespace and base URI lookups + * Base lookups will always resolve because the parser knows + * the default base. + * + * @private + */ + + this.frameFactory = function(parser, parent, element){ + return {'NODE': 1, 'ARC': 2, 'parent': parent, 'parser': parser, 'store': parser.store, 'element': element, + 'lastChild': 0, 'base': null, 'lang': null, 'node': null, 'nodeType': null, 'listIndex': 1, 'rdfid': null, 'datatype': null, 'collection': false, /** Terminate the frame and notify the store that we're done */ + 'terminateFrame': function(){ + if (this.collection){ + + this.node.close(); + } + } + , /** Add a symbol of a certain type to the this frame */'addSymbol': function(type, uri){ + uri = $rdf.Util.uri.join(uri, this.base); + this.node = this.store.sym(uri); + + this.nodeType = type; + } + , /** Load any constructed triples into the store */'loadTriple': function(){ + if (this.parent.parent.collection){ + this.parent.parent.node.append(this.node); + } + else { + this.store.add(this.parent.parent.node, this.parent.node, this.node, this.parser.why); + } + if (this.parent.rdfid != null){ + // reify + var triple = this.store.sym($rdf.Util.uri.join("#" + this.parent.rdfid, this.base)); + this.store.add(triple, this.store.sym(RDFParser.ns.RDF + "type"), this.store.sym(RDFParser.ns.RDF + "Statement"), this.parser.why); + this.store.add(triple, this.store.sym(RDFParser.ns.RDF + "subject"), this.parent.parent.node, this.parser.why); + this.store.add(triple, this.store.sym(RDFParser.ns.RDF + "predicate"), this.parent.node, this.parser.why); + + this.store.add(triple, this.store.sym(RDFParser.ns.RDF + "object"), this.node, this.parser.why); + } + } + , /** Check if it's OK to load a triple */'isTripleToLoad': function(){ + + return (this.parent != null && this.parent.parent != null && this.nodeType === this.NODE && this.parent.nodeType === + this.ARC && this.parent.parent.nodeType === this.NODE); + } + , /** Add a symbolic node to this frame */'addNode': function(uri){ + this.addSymbol(this.NODE, uri); + if (this.isTripleToLoad()){ + + this.loadTriple(); + } + } + , /** Add a collection node to this frame */'addCollection': function(){ + this.nodeType = this.NODE; + this.node = this.store.collection(); + this.collection = true; + if (this.isTripleToLoad()){ + + this.loadTriple(); + } + } + , /** Add a collection arc to this frame */'addCollectionArc': function(){ + + this.nodeType = this.ARC; + } + , /** Add a bnode to this frame */'addBNode': function(id){ + if (id != null){ + if (this.parser.bnodes[id] != null){ + this.node = this.parser.bnodes[id]; + } + else { + this.node = this.parser.bnodes[id] = this.store.bnode(); + } + } + else { + this.node = this.store.bnode(); + } + this.nodeType = this.NODE; + if (this.isTripleToLoad()){ + + this.loadTriple(); + } + } + , /** Add an arc or property to this frame */'addArc': function(uri){ + if (uri === RDFParser.ns.RDF + "li"){ + uri = RDFParser.ns.RDF + "_" + this.parent.listIndex; + this.parent.listIndex++; + } + + this.addSymbol(this.ARC, uri); + } + , /** Add a literal to this frame */'addLiteral': function(value){ + if (this.parent.datatype){ + this.node = this.store.literal(value, "", this.store.sym(this.parent.datatype)); + } + else { + this.node = this.store.literal(value, this.lang); + } + this.nodeType = this.NODE; + if (this.isTripleToLoad()){ + this.loadTriple(); + } + } + }; + }; + + //from the OpenLayers source .. needed to get around IE problems. + this.getAttributeNodeNS = function(node, uri, name){ + var attributeNode = null; + if (node.getAttributeNodeNS){ + attributeNode = node.getAttributeNodeNS(uri, name); + } + else { + var attributes = node.attributes; + var potentialNode, fullName; + for (var i = 0;i < attributes.length; ++ i){ + potentialNode = attributes[i]; + if (potentialNode.namespaceURI === uri){ + fullName = (potentialNode.prefix) ? (potentialNode.prefix +":" + name): name; + if (fullName === potentialNode.nodeName){ + attributeNode = potentialNode; + break; + } + } + } + } + return attributeNode; + }; + + + /** Our triple store reference @private */ + + this.store = store;/** Our identified blank nodes @private */ + this.bnodes = {};/** A context for context-aware stores @private */ + this.why = null;/** Reification flag */ + this.reify = false; + + /** + * Build our initial scope frame and parse the DOM into triples + * @param {DOMTree} document The DOM to parse + * @param {String} base The base URL to use + * @param {Object} why The context to which this resource belongs + */ + + this.parse = function(document, base, why){ + var children = document.childNodes;// clean up for the next run + this.cleanParser();// figure out the root element + var root; + if (document.nodeType === RDFParser.nodeType.DOCUMENT){ + for (var c = 0;c < children.length;c++){ + if (children[c].nodeType === RDFParser.nodeType.ELEMENT){ + root = children[c]; + break; + } + } + } + else if (document.nodeType === RDFParser.nodeType.ELEMENT){ + root = document; + } + else { + throw new Error("RDFParser: can't find root in " + base +". Halting. "); + // return false; + } + this.why = why;// our topmost frame + var f = this.frameFactory(this); + this.base = base; + f.base = base; + f.lang = ''; + this.parseDOM(this.buildFrame(f, root)); + return true; + }; + + this.parseDOM = function(frame){ + // a DOM utility function used in parsing + var rdfid; + var elementURI = function(el){ + var result = ""; + if (el.namespaceURI == null){ + throw new Error("RDF/XML syntax error: No namespace for " + el.localName + " in " + this.base); + } + if (el.namespaceURI){ + result = result + el.namespaceURI; + } + if (el.localName){ + result = result + el.localName; + } + else if (el.nodeName){ + if (el.nodeName.indexOf(":") >= 0)result = result + el.nodeName.split(":")[1]; + else result = result + el.nodeName; + } + return result; + }.bind(this); + var dig = true;// if we'll dig down in the tree on the next iter + while (frame.parent){ + var dom = frame.element; + var attrs = dom.attributes; + if (dom.nodeType === RDFParser.nodeType.TEXT || dom.nodeType === RDFParser.nodeType.CDATA_SECTION){ + //we have a literal + if(frame.parent.nodeType == frame.NODE) { + //must have had attributes, store as rdf:value + frame.addArc(RDFParser.ns.RDF + 'value'); + frame = this.buildFrame(frame); + } + frame.addLiteral(dom.nodeValue); + } + else if (elementURI(dom)!== RDFParser.ns.RDF + "RDF"){ + // not root + if (frame.parent && frame.parent.collection){ + // we're a collection element + frame.addCollectionArc(); + frame = this.buildFrame(frame, frame.element); + frame.parent.element = null; + } + if ( ! frame.parent || ! frame.parent.nodeType || frame.parent.nodeType === frame.ARC){ + // we need a node + var about = this.getAttributeNodeNS(dom, RDFParser.ns.RDF, "about"); + rdfid = this.getAttributeNodeNS(dom, RDFParser.ns.RDF, "ID"); + if (about && rdfid){ + throw new Error("RDFParser: " + dom.nodeName + " has both rdf:id and rdf:about." + + " Halting. Only one of these" + " properties may be specified on a" + " node."); + } + if (!about && rdfid){ + frame.addNode("#" + rdfid.nodeValue); + dom.removeAttributeNode(rdfid); + } + else if (about == null && rdfid == null){ + var bnid = this.getAttributeNodeNS(dom, RDFParser.ns.RDF, "nodeID"); + if (bnid){ + frame.addBNode(bnid.nodeValue); + dom.removeAttributeNode(bnid); + } + else { + frame.addBNode(); + } + } + else { + frame.addNode(about.nodeValue); + dom.removeAttributeNode(about); + } + // Typed nodes + var rdftype = this.getAttributeNodeNS(dom, RDFParser.ns.RDF, "type"); + if (RDFParser.ns.RDF + "Description" !== elementURI(dom)){ + rdftype = {'nodeValue': elementURI(dom)}; + } + if (rdftype != null){ + this.store.add(frame.node, this.store.sym(RDFParser.ns.RDF + "type"), this.store.sym($rdf.Util.uri.join(rdftype.nodeValue, + frame.base)), this.why); + if (rdftype.nodeName){ + dom.removeAttributeNode(rdftype); + } + } + // Property Attributes + for (var x = attrs.length - 1;x >= 0;x--){ + this.store.add(frame.node, this.store.sym(elementURI(attrs[x])), this.store.literal(attrs[x].nodeValue, + frame.lang), this.why); + } + } + else { + // we should add an arc (or implicit bnode+arc) + frame.addArc(elementURI(dom));// save the arc's rdf:ID if it has one + if (this.reify){ + rdfid = this.getAttributeNodeNS(dom, RDFParser.ns.RDF, "ID"); + if (rdfid){ + frame.rdfid = rdfid.nodeValue; + dom.removeAttributeNode(rdfid); + } + } + var parsetype = this.getAttributeNodeNS(dom, RDFParser.ns.RDF, "parseType"); + var datatype = this.getAttributeNodeNS(dom, RDFParser.ns.RDF, "datatype"); + if (datatype){ + frame.datatype = datatype.nodeValue; + dom.removeAttributeNode(datatype); + } + if (parsetype){ + var nv = parsetype.nodeValue; + if (nv === "Literal"){ + frame.datatype = RDFParser.ns.RDF + "XMLLiteral";// (this.buildFrame(frame)).addLiteral(dom) + // should work but doesn't + frame = this.buildFrame(frame); + frame.addLiteral(dom); + dig = false; + } + else if (nv === "Resource"){ + frame = this.buildFrame(frame, frame.element); + frame.parent.element = null; + frame.addBNode(); + } + else if (nv === "Collection"){ + frame = this.buildFrame(frame, frame.element); + frame.parent.element = null; + frame.addCollection(); + } + dom.removeAttributeNode(parsetype); + } + if (attrs.length !== 0){ + var resource = this.getAttributeNodeNS(dom, RDFParser.ns.RDF, "resource"); + var bnid2 = this.getAttributeNodeNS(dom, RDFParser.ns.RDF, "nodeID"); + frame = this.buildFrame(frame); + if (resource){ + frame.addNode(resource.nodeValue); + dom.removeAttributeNode(resource); + } + else { + if (bnid2){ + frame.addBNode(bnid2.nodeValue); + dom.removeAttributeNode(bnid2); + } + else { + frame.addBNode(); + } + } + for (var x1 = attrs.length - 1; x1 >= 0; x1--){ + var f = this.buildFrame(frame); + f.addArc(elementURI(attrs[x1])); + if (elementURI(attrs[x1])=== RDFParser.ns.RDF + "type"){ + (this.buildFrame(f)).addNode(attrs[x1].nodeValue); + } + else { + (this.buildFrame(f)).addLiteral(attrs[x1].nodeValue); + } + } + } + else if (dom.childNodes.length === 0){ + (this.buildFrame(frame)).addLiteral(""); + } + } + }// rdf:RDF + // dig dug + dom = frame.element; + while (frame.parent){ + var pframe = frame; + while (dom == null){ + frame = frame.parent; + dom = frame.element; + } + var candidate = dom.childNodes && dom.childNodes[frame.lastChild]; + if (!candidate || ! dig){ + frame.terminateFrame(); + if ( ! (frame = frame.parent)){ + break; + }// done + dom = frame.element; + dig = true; + } + else if ((candidate.nodeType !== RDFParser.nodeType.ELEMENT && + candidate.nodeType !== RDFParser.nodeType.TEXT && + candidate.nodeType !== RDFParser.nodeType.CDATA_SECTION) || + ((candidate.nodeType === RDFParser.nodeType.TEXT || + candidate.nodeType === RDFParser.nodeType.CDATA_SECTION) && + dom.childNodes.length !== 1)){ + frame.lastChild++; + } + else { + // not a leaf + frame.lastChild++; + frame = this.buildFrame(pframe, dom.childNodes[frame.lastChild - 1]); + break; + } + } + }// while + }; + + /** + * Cleans out state from a previous parse run + * @private + */ + this.cleanParser = function(){ + this.bnodes = {}; + this.why = null; + }; + + /** + * Builds scope frame + * @private + */ + this.buildFrame = function(parent, element){ + var frame = this.frameFactory(this, parent, element); + if (parent){ + frame.base = parent.base; + frame.lang = parent.lang; + } + if (!element || element.nodeType === RDFParser.nodeType.TEXT || + element.nodeType === RDFParser.nodeType.CDATA_SECTION){ + return frame; + } + var attrs = element.attributes; + var base = element.getAttributeNode("xml:base"); + if (base != null){ + frame.base = base.nodeValue; + element.removeAttribute("xml:base"); + } + var lang = element.getAttributeNode("xml:lang"); + if (lang != null){ + frame.lang = lang.nodeValue; + element.removeAttribute("xml:lang"); + } + // remove all extraneous xml and xmlns attributes + for (var x = attrs.length - 1;x >= 0;x--){ + if (attrs[x].nodeName.substr(0, 3) === "xml"){ + if (attrs[x].name.slice(0, 6) === 'xmlns:'){ + var uri = attrs[x].nodeValue;// alert('base for namespac attr:'+this.base); + if (this.base) uri = $rdf.Util.uri.join(uri, this.base); + this.store.setPrefixForURI(attrs[x].name.slice(6), uri); + } + // alert('rdfparser: xml atribute: '+attrs[x].name) //@@ + element.removeAttributeNode(attrs[x]); + } + } + return frame; + }; +}; +/** +* +* UTF-8 data encode / decode +* http://www.webtoolkit.info/ +* +**/ + +$rdf.N3Parser = function () { + +function hexify(str) { // also used in parser + return encodeURI(str); +} + +var Utf8 = { + + // public method for url encoding + encode : function (string) { + string = string.replace(/\r\n/g,"\n"); + var utftext = ""; + + for (var n = 0; n < string.length; n++) { + + var c = string.charCodeAt(n); + + if (c < 128) { + utftext += String.fromCharCode(c); + } + else if((c > 127) && (c < 2048)) { + utftext += String.fromCharCode((c >> 6) | 192); + utftext += String.fromCharCode((c & 63) | 128); + } + else { + utftext += String.fromCharCode((c >> 12) | 224); + utftext += String.fromCharCode(((c >> 6) & 63) | 128); + utftext += String.fromCharCode((c & 63) | 128); + } + + } + + return utftext; + }, + + // public method for url decoding + decode : function (utftext) { + var string = ""; + var i = 0; + + while ( i < utftext.length ) { + + var c = utftext.charCodeAt(i); + if (c < 128) { + string += String.fromCharCode(c); + i++; + } + else if((c > 191) && (c < 224)) { + string += String.fromCharCode(((c & 31) << 6) + | (utftext.charCodeAt(i+1) & 63)); + i += 2; + } + else { + string += String.fromCharCode(((c & 15) << 12) + | ((utftext.charCodeAt(i+1) & 63) << 6) + | (utftext.charCodeAt(i+2) & 63)); + i += 3; + } + } + return string; + } + +}// Things we need to define to make converted pythn code work in js +// environment of $rdf + +var RDFSink_forSomeSym = "http://www.w3.org/2000/10/swap/log#forSome"; +var RDFSink_forAllSym = "http://www.w3.org/2000/10/swap/log#forAll"; +var Logic_NS = "http://www.w3.org/2000/10/swap/log#"; + +// pyjs seems to reference runtime library which I didn't find + +var pyjslib_Tuple = function(theList) { return theList }; + +var pyjslib_List = function(theList) { return theList }; + +var pyjslib_Dict = function(listOfPairs) { + if (listOfPairs.length > 0) + throw "missing.js: oops nnonempty dict not imp"; + return []; +} + +var pyjslib_len = function(s) { return s.length } + +var pyjslib_slice = function(str, i, j) { + if (typeof str.slice == 'undefined') + throw '@@ mising.js: No .slice function for '+str+' of type '+(typeof str) + if ((typeof j == 'undefined') || (j ==null)) return str.slice(i); + return str.slice(i, j) // @ exactly the same spec? +} +var StopIteration = Error('dummy error stop iteration'); + +var pyjslib_Iterator = function(theList) { + this.last = 0; + this.li = theList; + this.next = function() { + if (this.last == this.li.length) throw StopIteration; + return this.li[this.last++]; + } + return this; +}; + +var ord = function(str) { + return str.charCodeAt(0) +} + +var string_find = function(str, s) { + return str.indexOf(s) +} + +var assertFudge = function(condition, desc) { + if (condition) return; + if (desc) throw "python Assertion failed: "+desc; + throw "(python) Assertion failed."; +} + + +var stringFromCharCode = function(uesc) { + return String.fromCharCode(uesc); +} + + +String.prototype.encode = function(encoding) { + if (encoding != 'utf-8') throw "UTF8_converter: can only do utf-8" + return Utf8.encode(this); +} +String.prototype.decode = function(encoding) { + if (encoding != 'utf-8') throw "UTF8_converter: can only do utf-8" + //return Utf8.decode(this); + return this; +} + + + +var uripath_join = function(base, given) { + return $rdf.Util.uri.join(given, base) // sad but true +} + +var becauseSubexpression = null; // No reason needed +var diag_tracking = 0; +var diag_chatty_flag = 0; +var diag_progress = function(str) { /*$rdf.log.debug(str);*/ } + +// why_BecauseOfData = function(doc, reason) { return doc }; + + +var RDF_type_URI = "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"; +var DAML_sameAs_URI = "http://www.w3.org/2002/07/owl#sameAs"; + +/* +function SyntaxError(details) { + return new __SyntaxError(details); +} +*/ + +function __SyntaxError(details) { + this.details = details +} + +/* + +$Id: n3parser.js 14561 2008-02-23 06:37:26Z kennyluck $ + +HAND EDITED FOR CONVERSION TO JAVASCRIPT + +This module implements a Nptation3 parser, and the final +part of a notation3 serializer. + +See also: + +Notation 3 +http://www.w3.org/DesignIssues/Notation3 + +Closed World Machine - and RDF Processor +http://www.w3.org/2000/10/swap/cwm + +To DO: See also "@@" in comments + +- Clean up interfaces +______________________________________________ + +Module originally by Dan Connolly, includeing notation3 +parser and RDF generator. TimBL added RDF stream model +and N3 generation, replaced stream model with use +of common store/formula API. Yosi Scharf developped +the module, including tests and test harness. + +*/ + +var ADDED_HASH = "#"; +var LOG_implies_URI = "http://www.w3.org/2000/10/swap/log#implies"; +var INTEGER_DATATYPE = "http://www.w3.org/2001/XMLSchema#integer"; +var FLOAT_DATATYPE = "http://www.w3.org/2001/XMLSchema#double"; +var DECIMAL_DATATYPE = "http://www.w3.org/2001/XMLSchema#decimal"; +var DATE_DATATYPE = "http://www.w3.org/2001/XMLSchema#date"; +var DATETIME_DATATYPE = "http://www.w3.org/2001/XMLSchema#dateTime"; +var BOOLEAN_DATATYPE = "http://www.w3.org/2001/XMLSchema#boolean"; +var option_noregen = 0; +var _notQNameChars = "\t\r\n !\"#$%&'()*.,+/;<=>?@[\\]^`{|}~"; +var _notNameChars = ( _notQNameChars + ":" ) ; +var _rdfns = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; +var N3CommentCharacter = "#"; +var eol = new RegExp("^[ \\t]*(#[^\\n]*)?\\r?\\n", 'g'); +var eof = new RegExp("^[ \\t]*(#[^\\n]*)?$", 'g'); +var ws = new RegExp("^[ \\t]*", 'g'); +var signed_integer = new RegExp("^[-+]?[0-9]+", 'g'); +var number_syntax = new RegExp("^([-+]?[0-9]+)(\\.[0-9]+)?(e[-+]?[0-9]+)?", 'g'); +var datetime_syntax = new RegExp('^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9](T[0-9][0-9]:[0-9][0-9](:[0-9][0-9](\\.[0-9]*)?)?)?Z?'); + +var digitstring = new RegExp("^[0-9]+", 'g'); +var interesting = new RegExp("[\\\\\\r\\n\\\"]", 'g'); +var langcode = new RegExp("^[a-zA-Z0-9]+(-[a-zA-Z0-9]+)?", 'g'); +function SinkParser(store, openFormula, thisDoc, baseURI, genPrefix, metaURI, flags, why) { + return new __SinkParser(store, openFormula, thisDoc, baseURI, genPrefix, metaURI, flags, why); +} +function __SinkParser(store, openFormula, thisDoc, baseURI, genPrefix, metaURI, flags, why) { + if (typeof openFormula == 'undefined') openFormula=null; + if (typeof thisDoc == 'undefined') thisDoc=""; + if (typeof baseURI == 'undefined') baseURI=null; + if (typeof genPrefix == 'undefined') genPrefix=""; + if (typeof metaURI == 'undefined') metaURI=null; + if (typeof flags == 'undefined') flags=""; + if (typeof why == 'undefined') why=null; + /* + note: namespace names should *not* end in #; + the # will get added during qname processing */ + + this._bindings = new pyjslib_Dict([]); + this._flags = flags; + if ((thisDoc != "")) { + assertFudge((thisDoc.indexOf(":") >= 0), ( "Document URI not absolute: " + thisDoc ) ); + this._bindings[""] = ( ( thisDoc + "#" ) ); + } + this._store = store; + if (genPrefix) { + store.setGenPrefix(genPrefix); + } + this._thisDoc = thisDoc; + this.source = store.sym(thisDoc); + this.lines = 0; + this.statementCount = 0; + this.startOfLine = 0; + this.previousLine = 0; + this._genPrefix = genPrefix; + this.keywords = new pyjslib_List(["a", "this", "bind", "has", "is", "of", "true", "false"]); + this.keywordsSet = 0; + this._anonymousNodes = new pyjslib_Dict([]); + this._variables = new pyjslib_Dict([]); + this._parentVariables = new pyjslib_Dict([]); + this._reason = why; + this._reason2 = null; + if (diag_tracking) { + this._reason2 = why_BecauseOfData(store.sym(thisDoc), this._reason); + } + if (baseURI) { + this._baseURI = baseURI; + } + else { + if (thisDoc) { + this._baseURI = thisDoc; + } + else { + this._baseURI = null; + } + } + assertFudge(!(this._baseURI) || (this._baseURI.indexOf(":") >= 0)); + if (!(this._genPrefix)) { + if (this._thisDoc) { + this._genPrefix = ( this._thisDoc + "#_g" ) ; + } + else { + this._genPrefix = RDFSink_uniqueURI(); + } + } + if ((openFormula == null)) { + if (this._thisDoc) { + this._formula = store.formula( ( thisDoc + "#_formula" ) ); + } + else { + this._formula = store.formula(); + } + } + else { + this._formula = openFormula; + } + this._context = this._formula; + this._parentContext = null; +} +__SinkParser.prototype.here = function(i) { + return ( ( ( ( this._genPrefix + "_L" ) + this.lines ) + "C" ) + ( ( i - this.startOfLine ) + 1 ) ) ; +}; +__SinkParser.prototype.formula = function() { + return this._formula; +}; +__SinkParser.prototype.loadStream = function(stream) { + return this.loadBuf(stream.read()); +}; +__SinkParser.prototype.loadBuf = function(buf) { + /* + Parses a buffer and returns its top level formula*/ + + this.startDoc(); + this.feed(buf); + return this.endDoc(); +}; +__SinkParser.prototype.feed = function(octets) { + /* + Feed an octet stream tothe parser + + if BadSyntax is raised, the string + passed in the exception object is the + remainder after any statements have been parsed. + So if there is more data to feed to the + parser, it should be straightforward to recover.*/ + + var str = octets.decode("utf-8"); + var i = 0; + while ((i >= 0)) { + var j = this.skipSpace(str, i); + if ((j < 0)) { + return; + } + var i = this.directiveOrStatement(str, j); + if ((i < 0)) { + throw BadSyntax(this._thisDoc, this.lines, str, j, "expected directive or statement"); + } + } +}; +__SinkParser.prototype.directiveOrStatement = function(str, h) { + var i = this.skipSpace(str, h); + if ((i < 0)) { + return i; + } + var j = this.directive(str, i); + if ((j >= 0)) { + return this.checkDot(str, j); + } + var j = this.statement(str, i); + if ((j >= 0)) { + return this.checkDot(str, j); + } + return j; +}; +__SinkParser.prototype.tok = function(tok, str, i) { + /* + Check for keyword. Space must have been stripped on entry and + we must not be at end of file.*/ + var whitespace = "\t\n\v\f\r "; + if ((pyjslib_slice(str, i, ( i + 1 ) ) == "@")) { + var i = ( i + 1 ) ; + } + else { + if (($rdf.Util.ArrayIndexOf(this.keywords,tok) < 0)) { + return -1; + } + } + var k = ( i + pyjslib_len(tok) ) ; + if ((pyjslib_slice(str, i, k) == tok) && (_notQNameChars.indexOf(str.charAt(k)) >= 0)) { + return k; + } + else { + return -1; + } +}; +__SinkParser.prototype.directive = function(str, i) { + var j = this.skipSpace(str, i); + if ((j < 0)) { + return j; + } + var res = new pyjslib_List([]); + var j = this.tok("bind", str, i); + if ((j > 0)) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "keyword bind is obsolete: use @prefix"); + } + var j = this.tok("keywords", str, i); + if ((j > 0)) { + var i = this.commaSeparatedList(str, j, res, false); + if ((i < 0)) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "'@keywords' needs comma separated list of words"); + } + this.setKeywords(pyjslib_slice(res, null, null)); + if ((diag_chatty_flag > 80)) { + diag_progress("Keywords ", this.keywords); + } + return i; + } + var j = this.tok("forAll", str, i); + if ((j > 0)) { + var i = this.commaSeparatedList(str, j, res, true); + if ((i < 0)) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "Bad variable list after @forAll"); + } + + var __x = new pyjslib_Iterator(res); + try { + while (true) { + var x = __x.next(); + + + if ($rdf.Util.ArrayIndexOf(this._variables,x) < 0 || ($rdf.Util.ArrayIndexOf(this._parentVariables,x) >= 0)) { + this._variables[x] = ( this._context.newUniversal(x)); + } + + } + } catch (e) { + if (e != StopIteration) { + throw e; + } + } + + return i; + } + var j = this.tok("forSome", str, i); + if ((j > 0)) { + var i = this.commaSeparatedList(str, j, res, this.uri_ref2); + if ((i < 0)) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "Bad variable list after @forSome"); + } + + var __x = new pyjslib_Iterator(res); + try { + while (true) { + var x = __x.next(); + + + this._context.declareExistential(x); + + } + } catch (e) { + if (e != StopIteration) { + throw e; + } + } + + return i; + } + var j = this.tok("prefix", str, i); + if ((j >= 0)) { + var t = new pyjslib_List([]); + var i = this.qname(str, j, t); + if ((i < 0)) { + throw BadSyntax(this._thisDoc, this.lines, str, j, "expected qname after @prefix"); + } + var j = this.uri_ref2(str, i, t); + if ((j < 0)) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "expected after @prefix _qname_"); + } + var ns = t[1].uri; + if (this._baseURI) { + var ns = uripath_join(this._baseURI, ns); + } + else { + assertFudge((ns.indexOf(":") >= 0), "With no base URI, cannot handle relative URI for NS"); + } + assertFudge((ns.indexOf(":") >= 0)); + this._bindings[t[0][0]] = ( ns); + + this.bind(t[0][0], hexify(ns)); + return j; + } + var j = this.tok("base", str, i); + if ((j >= 0)) { + var t = new pyjslib_List([]); + var i = this.uri_ref2(str, j, t); + if ((i < 0)) { + throw BadSyntax(this._thisDoc, this.lines, str, j, "expected after @base "); + } + var ns = t[0].uri; + if (this._baseURI) { + var ns = uripath_join(this._baseURI, ns); + } + else { + throw BadSyntax(this._thisDoc, this.lines, str, j, ( ( "With no previous base URI, cannot use relative URI in @base <" + ns ) + ">" ) ); + } + assertFudge((ns.indexOf(":") >= 0)); + this._baseURI = ns; + return i; + } + return -1; +}; +__SinkParser.prototype.bind = function(qn, uri) { + if ((qn == "")) { + } + else { + this._store.setPrefixForURI(qn, uri); + } +}; +__SinkParser.prototype.setKeywords = function(k) { + /* + Takes a list of strings*/ + + if ((k == null)) { + this.keywordsSet = 0; + } + else { + this.keywords = k; + this.keywordsSet = 1; + } +}; +__SinkParser.prototype.startDoc = function() { +}; +__SinkParser.prototype.endDoc = function() { + /* + Signal end of document and stop parsing. returns formula*/ + + return this._formula; +}; +__SinkParser.prototype.makeStatement = function(quad) { + quad[0].add(quad[2], quad[1], quad[3], this.source); + this.statementCount += 1; +}; +__SinkParser.prototype.statement = function(str, i) { + var r = new pyjslib_List([]); + var i = this.object(str, i, r); + if ((i < 0)) { + return i; + } + var j = this.property_list(str, i, r[0]); + if ((j < 0)) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "expected propertylist"); + } + return j; +}; +__SinkParser.prototype.subject = function(str, i, res) { + return this.item(str, i, res); +}; +__SinkParser.prototype.verb = function(str, i, res) { + /* + has _prop_ + is _prop_ of + a + = + _prop_ + >- prop -> + <- prop -< + _operator_*/ + + var j = this.skipSpace(str, i); + if ((j < 0)) { + return j; + } + var r = new pyjslib_List([]); + var j = this.tok("has", str, i); + if ((j >= 0)) { + var i = this.prop(str, j, r); + if ((i < 0)) { + throw BadSyntax(this._thisDoc, this.lines, str, j, "expected property after 'has'"); + } + res.push(new pyjslib_Tuple(["->", r[0]])); + return i; + } + var j = this.tok("is", str, i); + if ((j >= 0)) { + var i = this.prop(str, j, r); + if ((i < 0)) { + throw BadSyntax(this._thisDoc, this.lines, str, j, "expected after 'is'"); + } + var j = this.skipSpace(str, i); + if ((j < 0)) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "End of file found, expected property after 'is'"); + return j; + } + var i = j; + var j = this.tok("of", str, i); + if ((j < 0)) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "expected 'of' after 'is' "); + } + res.push(new pyjslib_Tuple(["<-", r[0]])); + return j; + } + var j = this.tok("a", str, i); + if ((j >= 0)) { + res.push(new pyjslib_Tuple(["->", this._store.sym(RDF_type_URI)])); + return j; + } + if ((pyjslib_slice(str, i, ( i + 2 ) ) == "<=")) { + res.push(new pyjslib_Tuple(["<-", this._store.sym( ( Logic_NS + "implies" ) )])); + return ( i + 2 ) ; + } + if ((pyjslib_slice(str, i, ( i + 1 ) ) == "=")) { + if ((pyjslib_slice(str, ( i + 1 ) , ( i + 2 ) ) == ">")) { + res.push(new pyjslib_Tuple(["->", this._store.sym( ( Logic_NS + "implies" ) )])); + return ( i + 2 ) ; + } + res.push(new pyjslib_Tuple(["->", this._store.sym(DAML_sameAs_URI)])); + return ( i + 1 ) ; + } + if ((pyjslib_slice(str, i, ( i + 2 ) ) == ":=")) { + res.push(new pyjslib_Tuple(["->", ( Logic_NS + "becomes" ) ])); + return ( i + 2 ) ; + } + var j = this.prop(str, i, r); + if ((j >= 0)) { + res.push(new pyjslib_Tuple(["->", r[0]])); + return j; + } + if ((pyjslib_slice(str, i, ( i + 2 ) ) == ">-") || (pyjslib_slice(str, i, ( i + 2 ) ) == "<-")) { + throw BadSyntax(this._thisDoc, this.lines, str, j, ">- ... -> syntax is obsolete."); + } + return -1; +}; +__SinkParser.prototype.prop = function(str, i, res) { + return this.item(str, i, res); +}; +__SinkParser.prototype.item = function(str, i, res) { + return this.path(str, i, res); +}; +__SinkParser.prototype.blankNode = function(uri) { + return this._context.bnode(uri, this._reason2); +}; +__SinkParser.prototype.path = function(str, i, res) { + /* + Parse the path production. + */ + + var j = this.nodeOrLiteral(str, i, res); + if ((j < 0)) { + return j; + } + while (("!^.".indexOf(pyjslib_slice(str, j, ( j + 1 ) )) >= 0)) { + var ch = pyjslib_slice(str, j, ( j + 1 ) ); + if ((ch == ".")) { + var ahead = pyjslib_slice(str, ( j + 1 ) , ( j + 2 ) ); + if (!(ahead) || (_notNameChars.indexOf(ahead) >= 0) && (":?<[{(".indexOf(ahead) < 0)) { + break; + } + } + var subj = res.pop(); + var obj = this.blankNode(this.here(j)); + var j = this.node(str, ( j + 1 ) , res); + if ((j < 0)) { + throw BadSyntax(this._thisDoc, this.lines, str, j, "EOF found in middle of path syntax"); + } + var pred = res.pop(); + if ((ch == "^")) { + this.makeStatement(new pyjslib_Tuple([this._context, pred, obj, subj])); + } + else { + this.makeStatement(new pyjslib_Tuple([this._context, pred, subj, obj])); + } + res.push(obj); + } + return j; +}; +__SinkParser.prototype.anonymousNode = function(ln) { + /* + Remember or generate a term for one of these _: anonymous nodes*/ + + var term = this._anonymousNodes[ln]; + if (term) { + return term; + } + var term = this._store.bnode(this._context, this._reason2); + this._anonymousNodes[ln] = ( term); + return term; +}; +__SinkParser.prototype.node = function(str, i, res, subjectAlready) { + if (typeof subjectAlready == 'undefined') subjectAlready=null; + /* + Parse the production. + Space is now skipped once at the beginning + instead of in multipe calls to self.skipSpace(). + */ + + var subj = subjectAlready; + var j = this.skipSpace(str, i); + if ((j < 0)) { + return j; + } + var i = j; + var ch = pyjslib_slice(str, i, ( i + 1 ) ); + if ((ch == "[")) { + var bnodeID = this.here(i); + var j = this.skipSpace(str, ( i + 1 ) ); + if ((j < 0)) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "EOF after '['"); + } + if ((pyjslib_slice(str, j, ( j + 1 ) ) == "=")) { + var i = ( j + 1 ) ; + var objs = new pyjslib_List([]); + var j = this.objectList(str, i, objs); + + if ((j >= 0)) { + var subj = objs[0]; + if ((pyjslib_len(objs) > 1)) { + + var __obj = new pyjslib_Iterator(objs); + try { + while (true) { + var obj = __obj.next(); + + + this.makeStatement(new pyjslib_Tuple([this._context, this._store.sym(DAML_sameAs_URI), subj, obj])); + + } + } catch (e) { + if (e != StopIteration) { + throw e; + } + } + + } + var j = this.skipSpace(str, j); + if ((j < 0)) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "EOF when objectList expected after [ = "); + } + if ((pyjslib_slice(str, j, ( j + 1 ) ) == ";")) { + var j = ( j + 1 ) ; + } + } + else { + throw BadSyntax(this._thisDoc, this.lines, str, i, "objectList expected after [= "); + } + } + if ((subj == null)) { + var subj = this.blankNode(bnodeID); + } + var i = this.property_list(str, j, subj); + if ((i < 0)) { + throw BadSyntax(this._thisDoc, this.lines, str, j, "property_list expected"); + } + var j = this.skipSpace(str, i); + if ((j < 0)) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "EOF when ']' expected after [ "); + } + if ((pyjslib_slice(str, j, ( j + 1 ) ) != "]")) { + throw BadSyntax(this._thisDoc, this.lines, str, j, "']' expected"); + } + res.push(subj); + return ( j + 1 ) ; + } + if ((ch == "{")) { + var ch2 = pyjslib_slice(str, ( i + 1 ) , ( i + 2 ) ); + if ((ch2 == "$")) { + i += 1; + var j = ( i + 1 ) ; + var mylist = new pyjslib_List([]); + var first_run = true; + while (1) { + var i = this.skipSpace(str, j); + if ((i < 0)) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "needed '$}', found end."); + } + if ((pyjslib_slice(str, i, ( i + 2 ) ) == "$}")) { + var j = ( i + 2 ) ; + break; + } + if (!(first_run)) { + if ((pyjslib_slice(str, i, ( i + 1 ) ) == ",")) { + i += 1; + } + else { + throw BadSyntax(this._thisDoc, this.lines, str, i, "expected: ','"); + } + } + else { + var first_run = false; + } + var item = new pyjslib_List([]); + var j = this.item(str, i, item); + if ((j < 0)) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "expected item in set or '$}'"); + } + mylist.push(item[0]); + } + res.push(this._store.newSet(mylist, this._context)); + return j; + } + else { + var j = ( i + 1 ) ; + var oldParentContext = this._parentContext; + this._parentContext = this._context; + var parentAnonymousNodes = this._anonymousNodes; + var grandParentVariables = this._parentVariables; + this._parentVariables = this._variables; + this._anonymousNodes = new pyjslib_Dict([]); + this._variables = this._variables.slice(); + var reason2 = this._reason2; + this._reason2 = becauseSubexpression; + if ((subj == null)) { + var subj = this._store.formula(); + } + this._context = subj; + while (1) { + var i = this.skipSpace(str, j); + if ((i < 0)) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "needed '}', found end."); + } + if ((pyjslib_slice(str, i, ( i + 1 ) ) == "}")) { + var j = ( i + 1 ) ; + break; + } + var j = this.directiveOrStatement(str, i); + if ((j < 0)) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "expected statement or '}'"); + } + } + this._anonymousNodes = parentAnonymousNodes; + this._variables = this._parentVariables; + this._parentVariables = grandParentVariables; + this._context = this._parentContext; + this._reason2 = reason2; + this._parentContext = oldParentContext; + res.push(subj.close()); + return j; + } + } + if ((ch == "(")) { + var thing_type = this._store.list; + var ch2 = pyjslib_slice(str, ( i + 1 ) , ( i + 2 ) ); + if ((ch2 == "$")) { + var thing_type = this._store.newSet; + i += 1; + } + var j = ( i + 1 ) ; + var mylist = new pyjslib_List([]); + while (1) { + var i = this.skipSpace(str, j); + if ((i < 0)) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "needed ')', found end."); + } + if ((pyjslib_slice(str, i, ( i + 1 ) ) == ")")) { + var j = ( i + 1 ) ; + break; + } + var item = new pyjslib_List([]); + var j = this.item(str, i, item); + if ((j < 0)) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "expected item in list or ')'"); + } + mylist.push(item[0]); + } + res.push(thing_type(mylist, this._context)); + return j; + } + var j = this.tok("this", str, i); + if ((j >= 0)) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "Keyword 'this' was ancient N3. Now use @forSome and @forAll keywords."); + res.push(this._context); + return j; + } + var j = this.tok("true", str, i); + if ((j >= 0)) { + res.push(true); + return j; + } + var j = this.tok("false", str, i); + if ((j >= 0)) { + res.push(false); + return j; + } + if ((subj == null)) { + var j = this.uri_ref2(str, i, res); + if ((j >= 0)) { + return j; + } + } + return -1; +}; +__SinkParser.prototype.property_list = function(str, i, subj) { + /* + Parse property list + Leaves the terminating punctuation in the buffer + */ + + while (1) { + var j = this.skipSpace(str, i); + if ((j < 0)) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "EOF found when expected verb in property list"); + return j; + } + if ((pyjslib_slice(str, j, ( j + 2 ) ) == ":-")) { + var i = ( j + 2 ) ; + var res = new pyjslib_List([]); + var j = this.node(str, i, res, subj); + if ((j < 0)) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "bad {} or () or [] node after :- "); + } + var i = j; + continue; + } + var i = j; + var v = new pyjslib_List([]); + var j = this.verb(str, i, v); + if ((j <= 0)) { + return i; + } + var objs = new pyjslib_List([]); + var i = this.objectList(str, j, objs); + if ((i < 0)) { + throw BadSyntax(this._thisDoc, this.lines, str, j, "objectList expected"); + } + + var __obj = new pyjslib_Iterator(objs); + try { + while (true) { + var obj = __obj.next(); + + + var pairFudge = v[0]; + var dir = pairFudge[0]; + var sym = pairFudge[1]; + if ((dir == "->")) { + this.makeStatement(new pyjslib_Tuple([this._context, sym, subj, obj])); + } + else { + this.makeStatement(new pyjslib_Tuple([this._context, sym, obj, subj])); + } + + } + } catch (e) { + if (e != StopIteration) { + throw e; + } + } + + var j = this.skipSpace(str, i); + if ((j < 0)) { + throw BadSyntax(this._thisDoc, this.lines, str, j, "EOF found in list of objects"); + return j; + } + if ((pyjslib_slice(str, i, ( i + 1 ) ) != ";")) { + return i; + } + var i = ( i + 1 ) ; + } +}; +__SinkParser.prototype.commaSeparatedList = function(str, j, res, ofUris) { + /* + return value: -1 bad syntax; >1 new position in str + res has things found appended + + Used to use a final value of the function to be called, e.g. this.bareWord + but passing the function didn't work fo js converion pyjs + */ + + var i = this.skipSpace(str, j); + if ((i < 0)) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "EOF found expecting comma sep list"); + return i; + } + if ((str.charAt(i) == ".")) { + return j; + } + if (ofUris) { + var i = this.uri_ref2(str, i, res); + } + else { + var i = this.bareWord(str, i, res); + } + if ((i < 0)) { + return -1; + } + while (1) { + var j = this.skipSpace(str, i); + if ((j < 0)) { + return j; + } + var ch = pyjslib_slice(str, j, ( j + 1 ) ); + if ((ch != ",")) { + if ((ch != ".")) { + return -1; + } + return j; + } + if (ofUris) { + var i = this.uri_ref2(str, ( j + 1 ) , res); + } + else { + var i = this.bareWord(str, ( j + 1 ) , res); + } + if ((i < 0)) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "bad list content"); + return i; + } + } +}; +__SinkParser.prototype.objectList = function(str, i, res) { + var i = this.object(str, i, res); + if ((i < 0)) { + return -1; + } + while (1) { + var j = this.skipSpace(str, i); + if ((j < 0)) { + throw BadSyntax(this._thisDoc, this.lines, str, j, "EOF found after object"); + return j; + } + if ((pyjslib_slice(str, j, ( j + 1 ) ) != ",")) { + return j; + } + var i = this.object(str, ( j + 1 ) , res); + if ((i < 0)) { + return i; + } + } +}; +__SinkParser.prototype.checkDot = function(str, i) { + var j = this.skipSpace(str, i); + if ((j < 0)) { + return j; + } + if ((pyjslib_slice(str, j, ( j + 1 ) ) == ".")) { + return ( j + 1 ) ; + } + if ((pyjslib_slice(str, j, ( j + 1 ) ) == "}")) { + return j; + } + if ((pyjslib_slice(str, j, ( j + 1 ) ) == "]")) { + return j; + } + throw BadSyntax(this._thisDoc, this.lines, str, j, "expected '.' or '}' or ']' at end of statement"); + return i; +}; +__SinkParser.prototype.uri_ref2 = function(str, i, res) { + /* + Generate uri from n3 representation. + + Note that the RDF convention of directly concatenating + NS and local name is now used though I prefer inserting a '#' + to make the namesapces look more like what XML folks expect. + */ + + var qn = new pyjslib_List([]); + var j = this.qname(str, i, qn); + if ((j >= 0)) { + var pairFudge = qn[0]; + var pfx = pairFudge[0]; + var ln = pairFudge[1]; + if ((pfx == null)) { + assertFudge(0, "not used?"); + var ns = ( this._baseURI + ADDED_HASH ) ; + } + else { + var ns = this._bindings[pfx]; + if (!(ns)) { + if ((pfx == "_")) { + res.push(this.anonymousNode(ln)); + return j; + } + throw BadSyntax(this._thisDoc, this.lines, str, i, ( ( "Prefix " + pfx ) + " not bound." ) ); + } + } + var symb = this._store.sym( ( ns + ln ) ); + if (($rdf.Util.ArrayIndexOf(this._variables, symb) >= 0)) { + res.push(this._variables[symb]); + } + else { + res.push(symb); + } + return j; + } + var i = this.skipSpace(str, i); + if ((i < 0)) { + return -1; + } + if ((str.charAt(i) == "?")) { + var v = new pyjslib_List([]); + var j = this.variable(str, i, v); + if ((j > 0)) { + res.push(v[0]); + return j; + } + return -1; + } + else if ((str.charAt(i) == "<")) { + var i = ( i + 1 ) ; + var st = i; + while ((i < pyjslib_len(str))) { + if ((str.charAt(i) == ">")) { + var uref = pyjslib_slice(str, st, i); + if (this._baseURI) { + var uref = uripath_join(this._baseURI, uref); + } + else { + assertFudge((uref.indexOf(":") >= 0), "With no base URI, cannot deal with relative URIs"); + } + if ((pyjslib_slice(str, ( i - 1 ) , i) == "#") && !((pyjslib_slice(uref, -1, null) == "#"))) { + var uref = ( uref + "#" ) ; + } + var symb = this._store.sym(uref); + if (($rdf.Util.ArrayIndexOf(this._variables,symb) >= 0)) { + res.push(this._variables[symb]); + } + else { + res.push(symb); + } + return ( i + 1 ) ; + } + var i = ( i + 1 ) ; + } + throw BadSyntax(this._thisDoc, this.lines, str, j, "unterminated URI reference"); + } + else if (this.keywordsSet) { + var v = new pyjslib_List([]); + var j = this.bareWord(str, i, v); + if ((j < 0)) { + return -1; + } + if (($rdf.Util.ArrayIndexOf(this.keywords, v[0]) >= 0)) { + throw BadSyntax(this._thisDoc, this.lines, str, i, ( ( "Keyword \"" + v[0] ) + "\" not allowed here." ) ); + } + res.push(this._store.sym( ( this._bindings[""] + v[0] ) )); + return j; + } + else { + return -1; + } +}; +__SinkParser.prototype.skipSpace = function(str, i) { + /* + Skip white space, newlines and comments. + return -1 if EOF, else position of first non-ws character*/ + + var whitespace = ' \n\r\t\f\x0b\xa0\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000'; + for (var j = (i ? i : 0); j < str.length; j++) { + var ch = str.charAt(j); + // console.log(" skipspace j= "+j + " i= " + i + " n= " + str.length); + // console.log(" skipspace ch <" + ch + ">"); + if (whitespace.indexOf(ch) < 0 ) { //not ws + // console.log(" skipspace 2 ch <" + ch + ">"); + if( str.charAt(j)==='#' ) { + for (;; j++) { + // console.log(" skipspace2 j= "+j + " i= " + i + " n= " + str.length); + if (j === str.length) { + return -1; // EOF + } + if (str.charAt(j) === '\n') { + this.lines = this.lines + 1; + break; + } + }; + } else { // Not hash - something interesting + // console.log(" skipspace 3 ch <" + ch + ">"); + return j + } + } else { // Whitespace + // console.log(" skipspace 5 ch <" + ch + ">"); + if (str.charAt(j) === '\n') { + this.lines = this.lines + 1; + } + } + } // next j + return -1; // EOF +}; + +__SinkParser.prototype.variable = function(str, i, res) { + /* + ?abc -> variable(:abc) + */ + + var j = this.skipSpace(str, i); + if ((j < 0)) { + return -1; + } + if ((pyjslib_slice(str, j, ( j + 1 ) ) != "?")) { + return -1; + } + var j = ( j + 1 ) ; + var i = j; + if (("0123456789-".indexOf(str.charAt(j)) >= 0)) { + throw BadSyntax(this._thisDoc, this.lines, str, j, ( ( "Varible name can't start with '" + str.charAt(j) ) + "s'" ) ); + return -1; + } + while ((i < pyjslib_len(str)) && (_notNameChars.indexOf(str.charAt(i)) < 0)) { + var i = ( i + 1 ) ; + } + if ((this._parentContext == null)) { + throw BadSyntax(this._thisDoc, this.lines, str, j, ( "Can't use ?xxx syntax for variable in outermost level: " + pyjslib_slice(str, ( j - 1 ) , i) ) ); + } + res.push(this._store.variable(pyjslib_slice(str, j, i))); + return i; +}; +__SinkParser.prototype.bareWord = function(str, i, res) { + /* + abc -> :abc + */ + + var j = this.skipSpace(str, i); + if ((j < 0)) { + return -1; + } + var ch = str.charAt(j); + if (("0123456789-".indexOf(ch) >= 0)) { + return -1; + } + if ((_notNameChars.indexOf(ch) >= 0)) { + return -1; + } + var i = j; + while ((i < pyjslib_len(str)) && (_notNameChars.indexOf(str.charAt(i)) < 0)) { + var i = ( i + 1 ) ; + } + res.push(pyjslib_slice(str, j, i)); + return i; +}; +__SinkParser.prototype.qname = function(str, i, res) { + /* + + xyz:def -> ('xyz', 'def') + If not in keywords and keywordsSet: def -> ('', 'def') + :def -> ('', 'def') + */ + + var i = this.skipSpace(str, i); + if ((i < 0)) { + return -1; + } + var c = str.charAt(i); + if (("0123456789-+".indexOf(c) >= 0)) { + return -1; + } + if ((_notNameChars.indexOf(c) < 0)) { + var ln = c; + var i = ( i + 1 ) ; + while ((i < pyjslib_len(str))) { + var c = str.charAt(i); + if ((_notNameChars.indexOf(c) < 0)) { + var ln = ( ln + c ) ; + var i = ( i + 1 ) ; + } + else { + break; + } + } + } + else { + var ln = ""; + } + if ((i < pyjslib_len(str)) && (str.charAt(i) == ":")) { + var pfx = ln; + var i = ( i + 1 ) ; + var ln = ""; + while ((i < pyjslib_len(str))) { + var c = str.charAt(i); + if ((_notNameChars.indexOf(c) < 0)) { + var ln = ( ln + c ) ; + var i = ( i + 1 ) ; + } + else { + break; + } + } + res.push(new pyjslib_Tuple([pfx, ln])); + return i; + } + else { + if (ln && this.keywordsSet && ($rdf.Util.ArrayIndexOf(this.keywords, ln) < 0)) { + res.push(new pyjslib_Tuple(["", ln])); + return i; + } + return -1; + } +}; +__SinkParser.prototype.object = function(str, i, res) { + var j = this.subject(str, i, res); + if ((j >= 0)) { + return j; + } + else { + var j = this.skipSpace(str, i); + if ((j < 0)) { + return -1; + } + else { + var i = j; + } + if ((str.charAt(i) == "\"")) { + if ((pyjslib_slice(str, i, ( i + 3 ) ) == "\"\"\"")) { + var delim = "\"\"\""; + } + else { + var delim = "\""; + } + var i = ( i + pyjslib_len(delim) ) ; + var pairFudge = this.strconst(str, i, delim); + var j = pairFudge[0]; + var s = pairFudge[1]; + res.push(this._store.literal(s)); + diag_progress("New string const ", s, j); + return j; + } + else { + return -1; + } + } +}; +__SinkParser.prototype.nodeOrLiteral = function(str, i, res) { + var j = this.node(str, i, res); + if ((j >= 0)) { + return j; + } + else { + var j = this.skipSpace(str, i); + if ((j < 0)) { + return -1; + } + else { + var i = j; + } + var ch = str.charAt(i); + if (("-+0987654321".indexOf(ch) >= 0)) { + + datetime_syntax.lastIndex = 0; + var m = datetime_syntax.exec(str.slice(i)); + if ((m != null)) { + // j = ( i + datetime_syntax.lastIndex ) ; + var val = m[0]; + j = i + val.length; + if ((val.indexOf("T") >= 0)) { + res.push(this._store.literal(val, undefined, this._store.sym(DATETIME_DATATYPE))); + } else { + res.push(this._store.literal(val, undefined, this._store.sym(DATE_DATATYPE))); + } + + } else { + number_syntax.lastIndex = 0; + var m = number_syntax.exec(str.slice(i)); + if ((m == null)) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "Bad number or date syntax"); + } + j = ( i + number_syntax.lastIndex ) ; + var val = pyjslib_slice(str, i, j); + if ((val.indexOf("e") >= 0)) { + res.push(this._store.literal(parseFloat(val), undefined, this._store.sym(FLOAT_DATATYPE))); + } + else if ((pyjslib_slice(str, i, j).indexOf(".") >= 0)) { + res.push(this._store.literal(parseFloat(val), undefined, this._store.sym(DECIMAL_DATATYPE))); + } + else { + res.push(this._store.literal(parseInt(val), undefined, this._store.sym(INTEGER_DATATYPE))); + } + }; + return j; // Where we have got up to + } + if ((str.charAt(i) == "\"")) { + if ((pyjslib_slice(str, i, ( i + 3 ) ) == "\"\"\"")) { + var delim = "\"\"\""; + } + else { + var delim = "\""; + } + var i = ( i + pyjslib_len(delim) ) ; + var dt = null; + var pairFudge = this.strconst(str, i, delim); + var j = pairFudge[0]; + var s = pairFudge[1]; + var lang = null; + if ((pyjslib_slice(str, j, ( j + 1 ) ) == "@")) { + langcode.lastIndex = 0; + + var m = langcode.exec(str.slice( ( j + 1 ) )); + if ((m == null)) { + throw BadSyntax(this._thisDoc, startline, str, i, "Bad language code syntax on string literal, after @"); + } + var i = ( ( langcode.lastIndex + j ) + 1 ) ; + + var lang = pyjslib_slice(str, ( j + 1 ) , i); + var j = i; + } + if ((pyjslib_slice(str, j, ( j + 2 ) ) == "^^")) { + var res2 = new pyjslib_List([]); + var j = this.uri_ref2(str, ( j + 2 ) , res2); + var dt = res2[0]; + } + res.push(this._store.literal(s, lang, dt)); + return j; + } + else { + return -1; + } + } +}; +__SinkParser.prototype.strconst = function(str, i, delim) { + /* + parse an N3 string constant delimited by delim. + return index, val + */ + + var j = i; + var ustr = ""; + var startline = this.lines; + while ((j < pyjslib_len(str))) { + var i = ( j + pyjslib_len(delim) ) ; + if ((pyjslib_slice(str, j, i) == delim)) { + return new pyjslib_Tuple([i, ustr]); + } + if ((str.charAt(j) == "\"")) { + var ustr = ( ustr + "\"" ) ; + var j = ( j + 1 ) ; + continue; + } + interesting.lastIndex = 0; + var m = interesting.exec(str.slice(j)); + if (!(m)) { + throw BadSyntax(this._thisDoc, startline, str, j, ( ( ( "Closing quote missing in string at ^ in " + pyjslib_slice(str, ( j - 20 ) , j) ) + "^" ) + pyjslib_slice(str, j, ( j + 20 ) ) ) ); + } + var i = ( ( j + interesting.lastIndex ) - 1 ) ; + var ustr = ( ustr + pyjslib_slice(str, j, i) ) ; + var ch = str.charAt(i); + if ((ch == "\"")) { + var j = i; + continue; + } + else if ((ch == "\r")) { + var j = ( i + 1 ) ; + continue; + } + else if ((ch == "\n")) { + if ((delim == "\"")) { + throw BadSyntax(this._thisDoc, startline, str, i, "newline found in string literal"); + } + this.lines = ( this.lines + 1 ) ; + var ustr = ( ustr + ch ) ; + var j = ( i + 1 ) ; + this.previousLine = this.startOfLine; + this.startOfLine = j; + } + else if ((ch == "\\")) { + var j = ( i + 1 ) ; + var ch = pyjslib_slice(str, j, ( j + 1 ) ); + if (!(ch)) { + throw BadSyntax(this._thisDoc, startline, str, i, "unterminated string literal (2)"); + } + var k = string_find("abfrtvn\\\"", ch); + if ((k >= 0)) { + var uch = "\a\b\f\r\t\v\n\\\"".charAt(k); + var ustr = ( ustr + uch ) ; + var j = ( j + 1 ) ; + } + else if ((ch == "u")) { + var pairFudge = this.uEscape(str, ( j + 1 ) , startline); + var j = pairFudge[0]; + var ch = pairFudge[1]; + var ustr = ( ustr + ch ) ; + } + else if ((ch == "U")) { + var pairFudge = this.UEscape(str, ( j + 1 ) , startline); + var j = pairFudge[0]; + var ch = pairFudge[1]; + var ustr = ( ustr + ch ) ; + } + else { + throw BadSyntax(this._thisDoc, this.lines, str, i, "bad escape"); + } + } + } + throw BadSyntax(this._thisDoc, this.lines, str, i, "unterminated string literal"); +}; +__SinkParser.prototype.uEscape = function(str, i, startline) { + var j = i; + var count = 0; + var value = 0; + while ((count < 4)) { + var chFudge = pyjslib_slice(str, j, ( j + 1 ) ); + var ch = chFudge.toLowerCase(); + var j = ( j + 1 ) ; + if ((ch == "")) { + throw BadSyntax(this._thisDoc, startline, str, i, "unterminated string literal(3)"); + } + var k = string_find("0123456789abcdef", ch); + if ((k < 0)) { + throw BadSyntax(this._thisDoc, startline, str, i, "bad string literal hex escape"); + } + var value = ( ( value * 16 ) + k ) ; + var count = ( count + 1 ) ; + } + var uch = String.fromCharCode(value); + return new pyjslib_Tuple([j, uch]); +}; +__SinkParser.prototype.UEscape = function(str, i, startline) { + var j = i; + var count = 0; + var value = "\\U"; + while ((count < 8)) { + var chFudge = pyjslib_slice(str, j, ( j + 1 ) ); + var ch = chFudge.toLowerCase(); + var j = ( j + 1 ) ; + if ((ch == "")) { + throw BadSyntax(this._thisDoc, startline, str, i, "unterminated string literal(3)"); + } + var k = string_find("0123456789abcdef", ch); + if ((k < 0)) { + throw BadSyntax(this._thisDoc, startline, str, i, "bad string literal hex escape"); + } + var value = ( value + ch ) ; + var count = ( count + 1 ) ; + } + var uch = stringFromCharCode( ( ( "0x" + pyjslib_slice(value, 2, 10) ) - 0 ) ); + return new pyjslib_Tuple([j, uch]); +}; +function OLD_BadSyntax(uri, lines, str, i, why) { + return new __OLD_BadSyntax(uri, lines, str, i, why); +} +function __OLD_BadSyntax(uri, lines, str, i, why) { + this._str = str.encode("utf-8"); + this._str = str; + this._i = i; + this._why = why; + this.lines = lines; + this._uri = uri; +} +__OLD_BadSyntax.prototype.toString = function() { + var str = this._str; + var i = this._i; + var st = 0; + if ((i > 60)) { + var pre = "..."; + var st = ( i - 60 ) ; + } + else { + var pre = ""; + } + if (( ( pyjslib_len(str) - i ) > 60)) { + var post = "..."; + } + else { + var post = ""; + } + return "Line %i of <%s>: Bad syntax (%s) at ^ in:\n\"%s%s^%s%s\"" % new pyjslib_Tuple([ ( this.lines + 1 ) , this._uri, this._why, pre, pyjslib_slice(str, st, i), pyjslib_slice(str, i, ( i + 60 ) ), post]); +}; +function BadSyntax(uri, lines, str, i, why) { + return ( ( ( ( ( ( ( ( "Line " + ( lines + 1 ) ) + " of <" ) + uri ) + ">: Bad syntax: " ) + why ) + "\nat: \"" ) + pyjslib_slice(str, i, ( i + 30 ) ) ) + "\"" ) ; +} + + +function stripCR(str) { + var res = ""; + + var __ch = new pyjslib_Iterator(str); + try { + while (true) { + var ch = __ch.next(); + + + if ((ch != "\r")) { + var res = ( res + ch ) ; + } + + } + } catch (e) { + if (e != StopIteration) { + throw e; + } + } + + return res; +} + + +function dummyWrite(x) { +} + +return SinkParser; + +}(); +// Identity management and indexing for RDF +// +// This file provides IndexedFormula a formula (set of triples) which +// indexed by predicate, subject and object. +// +// It "smushes" (merges into a single node) things which are identical +// according to owl:sameAs or an owl:InverseFunctionalProperty +// or an owl:FunctionalProperty +// +// +// 2005-10 Written Tim Berners-Lee +// 2007 Changed so as not to munge statements from documents when smushing +// +// + +/*jsl:option explicit*/ // Turn on JavaScriptLint variable declaration checking + +$rdf.IndexedFormula = function() { + +var owl_ns = "http://www.w3.org/2002/07/owl#"; +// var link_ns = "http://www.w3.org/2007/ont/link#"; + +/* hashString functions are used as array indeces. This is done to avoid +** conflict with existing properties of arrays such as length and map. +** See issue 139. +*/ +$rdf.Literal.prototype.hashString = $rdf.Literal.prototype.toNT; +$rdf.Symbol.prototype.hashString = $rdf.Symbol.prototype.toNT; +$rdf.BlankNode.prototype.hashString = $rdf.BlankNode.prototype.toNT; +$rdf.Collection.prototype.hashString = $rdf.Collection.prototype.toNT; + + +//Stores an associative array that maps URIs to functions +$rdf.IndexedFormula = function(features) { + this.statements = []; // As in Formula + this.optional = []; + this.propertyActions = []; // Array of functions to call when getting statement with {s X o} + //maps to [f(F,s,p,o),...] + this.classActions = []; // Array of functions to call when adding { s type X } + this.redirections = []; // redirect to lexically smaller equivalent symbol + this.aliases = []; // reverse mapping to redirection: aliases for this + this.HTTPRedirects = []; // redirections we got from HTTP + this.subjectIndex = []; // Array of statements with this X as subject + this.predicateIndex = []; // Array of statements with this X as subject + this.objectIndex = []; // Array of statements with this X as object + this.whyIndex = []; // Array of statements with X as provenance + this.index = [ this.subjectIndex, this.predicateIndex, this.objectIndex, this.whyIndex ]; + this.namespaces = {} // Dictionary of namespace prefixes + if (features === undefined) features = ["sameAs", + "InverseFunctionalProperty", "FunctionalProperty"]; +// this.features = features + // Callbackify? + function handleRDFType(formula, subj, pred, obj, why) { + if (formula.typeCallback != undefined) + formula.typeCallback(formula, obj, why); + + var x = formula.classActions[obj.hashString()]; + var done = false; + if (x) { + for (var i=0; i'] = [ handleRDFType ]; + + // Assumption: these terms are not redirected @@fixme + if ($rdf.Util.ArrayIndexOf(features,"sameAs") >= 0) + this.propertyActions[''] = [ + function(formula, subj, pred, obj, why) { + // $rdf.log.warn("Equating "+subj.uri+" sameAs "+obj.uri); //@@ + formula.equate(subj,obj); + return true; // true if statement given is NOT needed in the store + }]; //sameAs -> equate & don't add to index + + if ($rdf.Util.ArrayIndexOf(features,"InverseFunctionalProperty") >= 0) + this.classActions["<"+owl_ns+"InverseFunctionalProperty>"] = [ + function(formula, subj, pred, obj, addFn) { + return formula.newPropertyAction(subj, handle_IFP); // yes subj not pred! + }]; //IFP -> handle_IFP, do add to index + + if ($rdf.Util.ArrayIndexOf(features,"FunctionalProperty") >= 0) + this.classActions["<"+owl_ns+"FunctionalProperty>"] = [ + function(formula, subj, proj, obj, addFn) { + return formula.newPropertyAction(subj, handle_FP); + }]; //FP => handleFP, do add to index + + function handle_IFP(formula, subj, pred, obj) { + var s1 = formula.any(undefined, pred, obj); + if (s1 == undefined) return false; // First time with this value + // $rdf.log.warn("Equating "+s1.uri+" and "+subj.uri + " because IFP "+pred.uri); //@@ + formula.equate(s1, subj); + return true; + } //handle_IFP + + function handle_FP(formula, subj, pred, obj) { + var o1 = formula.any(subj, pred, undefined); + if (o1 == undefined) return false; // First time with this value + // $rdf.log.warn("Equating "+o1.uri+" and "+obj.uri + " because FP "+pred.uri); //@@ + formula.equate(o1, obj); + return true ; + } //handle_FP + +} /* end IndexedFormula */ + +$rdf.IndexedFormula.prototype = new $rdf.Formula(); +$rdf.IndexedFormula.prototype.constructor = $rdf.IndexedFormula; +$rdf.IndexedFormula.SuperClass = $rdf.Formula; + +$rdf.IndexedFormula.prototype.newPropertyAction = function newPropertyAction(pred, action) { + //$rdf.log.debug("newPropertyAction: "+pred); + var hash = pred.hashString(); + if (this.propertyActions[hash] == undefined) + this.propertyActions[hash] = []; + this.propertyActions[hash].push(action); + // Now apply the function to to statements already in the store + var toBeFixed = this.statementsMatching(undefined, pred, undefined); + var done = false; + for (var i=0; i'; + return (!!this.subjectIndex[hash] || !!this.objectIndex[hash] + || !!this.predicateIndex[hash]); +} + +// Find an unused id for a file being edited: return a symbol +// (Note: Slow iff a lot of them -- could be O(log(k)) ) +$rdf.IndexedFormula.prototype.nextSymbol = function(doc) { + for(var i=0;;i++) { + var uri = doc.uri + '#n' + i; + if (!this.mentionsURI(uri)) return this.sym(uri); + } +} + + +$rdf.IndexedFormula.prototype.anyStatementMatching = function(subj,pred,obj,why) { + var x = this.statementsMatching(subj,pred,obj,why,true); + if (!x || x == []) return undefined; + return x[0]; +}; + + +// Return statements matching a pattern +// ALL CONVENIENCE LOOKUP FUNCTIONS RELY ON THIS! +$rdf.IndexedFormula.prototype.statementsMatching = function(subj,pred,obj,why,justOne) { + //$rdf.log.debug("Matching {"+subj+" "+pred+" "+obj+"}"); + + var pat = [ subj, pred, obj, why ]; + var pattern = []; + var hash = []; + var wild = []; // wildcards + var given = []; // Not wild + for (var p=0; p<4; p++) { + pattern[p] = this.canon($rdf.term(pat[p])); + if (pattern[p] == undefined) { + wild.push(p); + } else { + given.push(p); + hash[p] = pattern[p].hashString(); + } + } + if (given.length == 0) { + return this.statements; + } + if (given.length == 1) { // Easy too, we have an index for that + var p = given[0]; + var list = this.index[p][hash[p]]; + if(list && justOne) { + if(list.length>1) + list = list.slice(0,1); + } + return list == undefined ? [] : list; + } + + // Now given.length is 2, 3 or 4. + // We hope that the scale-free nature of the data will mean we tend to get + // a short index in there somewhere! + + var best = 1e10; // really bad + var best_i; + for (var i=0; i patch:where {xxx}; patch:delete {yyy}; patch:insert {zzz}. + +$rdf.sparqlUpdateParser = function(str, kb, base) { + var i,j,k; + var keywords = [ 'INSERT', 'DELETE', 'WHERE' ] + var SQNS = $rdf.Namespace('http://www.w3.org/ns/pim/patch#'); + var p = $rdf.N3Parser(kb, kb, base, base, null, null, "", null); + var clauses = {}; + + var badSyntax = function (uri, lines, str, i, why) { + return ("Line " + ( lines + 1 ) + " of <" + uri + ">: Bad syntax:\n " + + why + "\n at: \"" + str.slice(i, (i + 30)) + "\"" ) ; + }; + + var check = function(next, last, message) { + if (next < 0) { + throw badSyntax(p._thisDoc, p.lines, str, j, last, message); + }; + return next; + }; + + + i = 0; + var query = kb.sym(base+ '#query'); // Invent a URI for the query + clauses['query'] = query; // A way of accessing it in its N3 model. + + while (true) { + // console.log("A Now at i = " + i) + var j = p.skipSpace(str, i); + if (j < 0) { + return clauses + } + // console.log("B After space at j= " + j) + if (str[j] === ';') { + i = p.skipSpace(str, j + 1); + if ( i < 0) { + return clauses ; // Allow end in a ; + } + j = i; + } + var found = false; + for (k=0; k< keywords.length; k++) { + var key = keywords[k]; + if (str.slice(j, j + key.length) === key) { + // console.log("C got one " + key); + i = p.skipSpace(str, j+ key.length); + // console.log("D after space at i= " + i); + if (i < 0) { + throw badSyntax(p._thisDoc, p.lines, str, j+ key.length, "found EOF, needed {...} after "+key); + }; + if (((key === 'INSERT') || (key === 'DELETE')) && str.slice(i, i+4) === 'DATA') { // Some wanted 'DATA'. Whatever + j = p.skipSpace(str, i+4); + if (j < 0) { + throw badSyntax(p._thisDoc, p.lines, str, i+4, "needed {...} after INSERT DATA "+key); + }; + i = j; + } + var res2 = []; + j = p.node(str, i, res2); + // console.log("M Now at j= " + j + " i= " + i) + + if (j < 0) { + throw badSyntax(p._thisDoc, p.lines, str, i, + "bad syntax or EOF in {...} after " + key); + } + clauses[key.toLowerCase()] = res2[0]; + // print("res2[0] for "+key+ " is " + res2[0]); // @@ debug @@@@@@ + kb.add(query, SQNS(key.toLowerCase()), res2[0]); + // key is the keyword and res2 has the contents + found = true; + i = j; + } + }; + if (!found && str.slice(j, j+7) === '@prefix') { + var i = p.directive(str, j); + if (i < 0) { + throw badSyntax(p._thisDoc, p.lines, str, i, + "bad syntax or EOF after @prefix "); + } + // console.log("P before dot i= " + i) + i = p.checkDot(str, i); + // console.log("Q after dot i= " + i) + found = true; + } + if (!found) { + // console.log("Bad syntax " + j) + throw badSyntax(p._thisDoc, p.lines, str, j, + "Unknown syntax at start of statememt: '" + str.slice(j).slice(0,20) +"'") + } + + } // while + //return clauses + + +}; // End of spaqlUpdateParser + + +//////////////// Apply a patch + +$rdf.IndexedFormula.prototype.applyPatch = function(patch, target, patchCallback) { // patchCallback(err) + var targetKB = this; + var doPatch = function(onDonePatch) { + // $rdf.log.info("doPatch ...") + + if (patch['delete']) { + // $rdf.log.info("doPatch delete "+patch['delete']) + var ds = patch['delete'] + if (bindings) ds = ds.substitute(bindings); + ds = ds.statements; + var bad = []; + var ds2 = ds.map(function(st){ // Find the actual statemnts in the store + var sts = targetKB.statementsMatching(st.subject, st.predicate, st.object, target); + if (sts.length === 0) { + // $rdf.log.info("NOT FOUND deletable " + st); + bad.push(st); + return null; + } else { + // $rdf.log.info("Found deletable " + st); + return sts[0] + } + }); + if (bad.length) { + return patchCallback("Couldn't find to delete: " + bad[0]) + } + ds2.map(function(st){ + targetKB.remove(st); + }); + }; + + if (patch['insert']) { + // $rdf.log.info("doPatch insert "+patch['insert']) + var ds = patch['insert']; + if (bindings) ds = ds.substitute(bindings); + ds = ds.statements; + ds.map(function(st){st.why = target; + targetKB.add(st.subject, st.predicate, st.object, st.why); + }); + }; + onDonePatch(); + }; + + var bindings = null; + if (patch.where) { + // $rdf.log.info("Processing WHERE: " + patch.where + '\n'); + + var query = new $rdf.Query('patch'); + query.pat = patch.where; + query.pat.statements.map(function(st){st.why = target}); + + var bindingsFound = []; + // $rdf.log.info("Processing WHERE - launching query: " + query.pat); + + targetKB.query(query, function onBinding(binding) { + bindingsFound.push(binding) + }, + targetKB.fetcher, + function onDone() { + if (bindingsFound.length == 0) { + return patchCallback("No match found to be patched:" + patch.where); + } + if (bindingsFound.length > 1) { + return patchCallback("Patch ambiguous. No patch done."); + } + bindings = bindingsFound[0]; + doPatch(patchCallback); + }); + } else { + doPatch(patchCallback) + }; +}; + + + + +// ends +// Matching a formula against another formula +// Assync as well as Synchronously +// +// +// W3C open source licence 2005. +// +// This builds on term.js, match.js (and identity.js?) +// to allow a query of a formula. +// +// Here we introduce for the first time a subclass of term: variable. +// +// SVN ID: $Id: query.js 25116 2008-11-15 16:13:48Z timbl $ + +// Variable +// +// Compare with BlankNode. They are similar, but a variable +// stands for something whose value is to be returned. +// Also, users name variables and want the same name back when stuff is printed + +/*jsl:option explicit*/ // Turn on JavaScriptLint variable declaration checking + + +// The Query object. Should be very straightforward. +// +// This if for tracking queries the user has in the UI. +// +$rdf.Query = function (name, id) { + this.pat = new $rdf.IndexedFormula(); // The pattern to search for + this.vars = []; // Used by UI code but not in query.js +// this.orderBy = []; // Not used yet + this.name = name; + this.id = id; +}; + +/**The QuerySource object stores a set of listeners and a set of queries. + * It keeps the listeners aware of those queries that the source currently + * contains, and it is then up to the listeners to decide what to do with + * those queries in terms of displays. + * Not used 2010-08 -- TimBL + * @constructor + * @author jambo + */ +$rdf.QuerySource = function() { + /**stores all of the queries currently held by this source, indexed by ID number. + */ + this.queries=[]; + /**stores the listeners for a query object. + * @see TabbedContainer + */ + this.listeners=[]; + + /**add a Query object to the query source--It will be given an ID number + * and a name, if it doesn't already have one. This subsequently adds the + * query to all of the listeners the QuerySource knows about. + */ + this.addQuery = function(q) { + var i; + if(q.name === null || q.name === "") { + q.name="Query #"+(this.queries.length+1); + } + q.id=this.queries.length; + this.queries.push(q); + for(i=0; i "+b[v]; + } + } + return str; + }; + + var bindingsDebug = function (nbs) { + var str = "Bindings: "; + var i, n=nbs.length; + for (i=0; i in query: " + body ) + } + match(f, g, bindingsSoFar, level, fetcher, // match not match2 to look up any others necessary. + localCallback, branch); + }); + /* + if( sf ) { + sf.addCallback('done', function(uri) { + if ((kb.canon(kb.sym(uri)).uri !== path) && (uri !== kb.canon(kb.sym(path)))) { + return true; + } + return false; + }); + } + fetcher(requestedTerm, id); + */ + }; + for (i=0; i"); else return term; } + function isSymbol(term) { return (typeof term == 'string' && term.match(/^<[^>]*>$/)); } + function isBnode(term) { return (typeof term == 'string' && (term.match(/^_:/)||term.match(/^$/))); } + function isPrefix(term) { return (typeof term == 'string' && term.match(/:$/)); } + function isPrefixedSymbol(term) { return (typeof term == 'string' && term.match(/^:|^[^_][^:]*:/)); } + function getPrefix(term) { var a = term.split(":"); return a[0]; } + function getSuffix(term) { var a = term.split(":"); return a[1]; } + function removeBrackets(term) { if (isSymbol(term)) {return term.slice(1,term.length-1);} else return term; } + //takes a string and returns an array of strings and Literals in the place of literals + function parseLiterals (str) + { + //var sin = (str.indexOf(/[ \n]\'/)==-1)?null:str.indexOf(/[ \n]\'/), doub = (str.indexOf(/[ \n]\"/)==-1)?null:str.indexOf(/[ \n]\"/); + var sin = (str.indexOf("'")==-1)?null:str.indexOf("'"), doub = (str.indexOf('"')==-1)?null:str.indexOf('"'); + //alert("S: "+sin+" D: "+doub); + if (!sin && !doub) + { + var a = new Array(1); + a[0]=str; + return a; + } + var res = new Array(2), br, ind; + if (!sin || (doub && doub/g,"> ").replace(/{/g," { ").replace(/}/g," } ").replace(/[\t\n\r]/g," ").replace(/; /g," ; ").replace(/\. /g," . ").replace(/, /g," , "); + $rdf.log.info("New str into spaceDelimit: \n"+str); + var res=[]; + var br = str.split(" "); + for (var x in br) + { + if (isRealText(br[x])) + res = res.concat(br[x]); + } + return res; + } + + function replaceKeywords(input) { + var strarr = input; + for (var x=0;x "+b); + var pref = getPrefix(a), symbol = removeBrackets(b); + res[pref]=symbol; + } + } + return res; + } + + function getMatchingBracket(arr,open,close) + { + $rdf.log.info("Looking for a close bracket of type "+close+" in "+arr); + var index = 0; + for (i=0;i "+value.toNT(); }; + this.test = function (term) { + if (term.value.match(/[0-9]+(\.[0-9]+)?([eE][+-]?[0-9]+)?/)) + return (parseFloat(term.value) > parseFloat(value)); + else return (term.toNT() > value.toNT()); + }; + return this; + } + + function constraintLessThan (value) //this is not the recommended usage. Should only work on literal, numeric, dateTime + { + this.describe = function (varstr) { return varstr + " < "+value.toNT(); }; + this.test = function (term) { + //this.describe = function (varstr) { return varstr + " < "+value } + if (term.value.match(/[0-9]+(\.[0-9]+)?([eE][+-]?[0-9]+)?/)) + return (parseFloat(term.value) < parseFloat(value)); + else return (term.toNT() < value.toNT()); + }; + return this; + } + + function constraintEqualTo (value) //This should only work on literals but doesn't. + { + this.describe = function (varstr) { return varstr + " = "+value.toNT(); }; + this.test = function (term) { + return value.sameTerm(term); + }; + return this; + } + + function constraintRegexp (value) //value must be a literal + { + this.describe = function (varstr) { return "REGEXP( '"+value+"' , "+varstr+" )";}; + this.test = function(term) { + var str = value; + //str = str.replace(/^//,"").replace(//$/,"") + var rg = new RegExp(str); + if (term.value) return rg.test(term.value); + else return false; + }; + } + + + function setConstraint(input,pat) + { + if (input.length == 3 && input[0].termType=="variable" && (input[2].termType=="symbol" || input[2].termType=="literal")) + { + if (input[1]=="=") + { + $rdf.log.debug("Constraint added: "+input); + pat.constraints[input[0]]=new constraintEqualTo(input[2]); + } + else if (input[1]==">") + { + $rdf.log.debug("Constraint added: "+input); + pat.constraints[input[0]]=new constraintGreaterThan(input[2]); + } + else if (input[1]=="<") + { + $rdf.log.debug("Constraint added: "+input); + pat.constraints[input[0]]=new constraintLessThan(input[2]); + } + else + $rdf.log.warn("I don't know how to handle the constraint: "+input); + } + else if (input.length == 6 && typeof input[0] == 'string' && input[0].toLowerCase() == 'regexp' && + input[1] == '(' && input[5] == ')' && input[3] == ',' && input[4].termType == 'variable' && + input[2].termType == 'literal') + { + $rdf.log.debug("Constraint added: "+input); + pat.constraints[input[4]]=new constraintRegexp(input[2].value); + } + + //$rdf.log.warn("I don't know how to handle the constraint: "+input); + + //alert("length: "+input.length+" input 0 type: "+input[0].termType+" input 1: "+input[1]+" input[2] type: "+input[2].termType); + } + + + + function setOptional (terms, pat) + { + $rdf.log.debug("Optional query: "+terms+" not yet implemented."); + var opt = kb.formula(); + setWhere (terms, opt); + pat.optional.push(opt); + } + + function setWhere (input,pat) + { + var terms = toTerms(input), end; + $rdf.log.debug("WHERE: "+terms); + //var opt = arrayIndicesOf("OPTIONAL",terms); + while (arrayIndexOf("OPTIONAL",terms)) + { + opt = arrayIndexOf("OPTIONAL",terms); + $rdf.log.debug("OPT: "+opt+" "+terms[opt]+" in "+terms); + if (terms[opt+1]!="{") $rdf.log.warn("Bad optional opening bracket in word "+opt); + end = getMatchingBracket(terms.slice(opt+2),"{","}"); + if (end == -1) { + $rdf.log.error("No matching bracket in word "+opt); + } else { + setOptional(terms.slice(opt+2,opt+2+end),pat); + //alert(pat.statements[0].toNT()); + opt = arrayIndexOf("OPTIONAL",terms); + end = getMatchingBracket(terms.slice(opt+2),"{","}"); + terms.splice(opt,end+3); + } + } + $rdf.log.debug("WHERE after optionals: "+terms); + while (arrayIndexOf("FILTER",terms)) + { + var filt = arrayIndexOf("FILTER",terms); + if (terms[filt+1]!="(") $rdf.log.warn("Bad filter opening bracket in word "+filt); + end = getMatchingBracket(terms.slice(filt+2),"(",")"); + if (end == -1) { + $rdf.log.error("No matching bracket in word "+filt); + } else { + setConstraint(terms.slice(filt+2,filt+2+end),pat); + filt = arrayIndexOf("FILTER",terms); + end = getMatchingBracket(terms.slice(filt+2),"(",")"); + terms.splice(filt,end+3); + } + } + $rdf.log.debug("WHERE after filters and optionals: "+terms); + extractStatements (terms,pat); + } + + function extractStatements (terms, formula) + { + var arrayZero = new Array(1); arrayZero[0]=-1; //this is just to add the beginning of the where to the periods index. + var per = arrayZero.concat(arrayIndicesOf(".",terms)); + var stat = []; + for (var x=0;xwhereLoc) + { + $rdf.log.error("Invalid or nonexistent SELECT and WHERE tags in SPARQL query"); + return false; + } + setVars (sp.slice(selectLoc+1,whereLoc),q); + + setWhere (sp.slice(whereLoc+2,sp.length-1),q.pat); + + if (testMode) return q; + + for (var x in q.pat.statements) + { + var st = q.pat.statements[x]; + if (st.subject.termType == 'symbol' + /*&& sf.isPending(st.subject.uri)*/) { //This doesn't work. + //sf.requestURI(st.subject.uri,"sparql:"+st.subject) Kenny: I remove these two + if($rdf.fetcher) $rdf.fetcher.lookUpThing(st.subject,"sparql:"+st.subject); + } + if (st.object.termType == 'symbol' + /*&& sf.isPending(st.object.uri)*/) { + //sf.requestURI(st.object.uri,"sparql:"+st.object) + if($rdf.fetcher) $rdf.fetcher.lookUpThing(st.object,"sparql:"+st.object); + } + } + //alert(q.pat); + return q; + //checkVars() + + //*******************************************************************// +}; + +$rdf.SPARQLResultsInterpreter = function (xml, callback, doneCallback) +{ + + function isVar(term) { return (typeof term == 'string' && term.match(/^[\?\$]/)); } + function fixSymbolBrackets(term) { if (typeof term == 'string') return term.replace(/^</,"<").replace(/>$/,">"); else return term ;} + function isSymbol(term) { return (typeof term == 'string' && term.match(/^<[^>]*>$/)); } + function isBnode(term) { return (typeof term == 'string' && (term.match(/^_:/)||term.match(/^$/))); } + function isPrefix(term) { return (typeof term == 'string' && term.match(/:$/)) ;} + function isPrefixedSymbol(term) { return (typeof term == 'string' && term.match(/^:|^[^_][^:]*:/)); } + function getPrefix(term) { var a = term.split(":"); return a[0]; } + function getSuffix(term) { var a = term.split(":"); return a[1]; } + function removeBrackets(term) { if (isSymbol(term)) {return term.slice(1,term.length-1);} else return term; } + + function parsePrefix(attribute) + { + if (!attribute.name.match(/^xmlns/)) + return false; + + var pref = attribute.name.replace(/^xmlns/,"").replace(/^:/,"").replace(/ /g,""); + prefixes[pref]=attribute.value; + $rdf.log.info("Prefix: "+pref+"\nValue: "+attribute.value); + } + + function handleP (str) //reconstructs prefixed URIs + { + var pref, suf; + if (isPrefixedSymbol(str)) { + pref = getPrefix(str); + suf = getSuffix(str); + } else { + pref = ""; + suf = str; + } + if (prefixes[pref]) + return prefixes[pref]+suf; + else + $rdf.log.error("Incorrect SPARQL results - bad prefix"); + } + + function xmlMakeTerm(node) + { + //alert("xml Node name: "+node.nodeName+"\nxml Child value: "+node.childNodes[0].nodeValue); + var val=node.childNodes[0]; + for (var x=0; x +// 2007-07-15 +// 2010-08-08 TimBL folded in Kenny's WEBDAV +// 2010-12-07 TimBL addred local file write code + +$rdf.sparqlUpdate = function() { + + var sparql = function(store) { + this.store = store; + this.ifps = {}; + this.fps = {}; + this.ns = {}; + this.ns.link = $rdf.Namespace("http://www.w3.org/2007/ont/link#"); + this.ns.http = $rdf.Namespace("http://www.w3.org/2007/ont/http#"); + this.ns.httph = $rdf.Namespace("http://www.w3.org/2007/ont/httph#"); + this.ns.rdf = $rdf.Namespace("http://www.w3.org/1999/02/22-rdf-syntax-ns#"); + this.ns.rdfs = $rdf.Namespace("http://www.w3.org/2000/01/rdf-schema#"); + this.ns.rdf = $rdf.Namespace("http://www.w3.org/1999/02/22-rdf-syntax-ns#"); + this.ns.owl = $rdf.Namespace("http://www.w3.org/2002/07/owl#"); + } + + + // Returns The method string SPARQL or DAV or LOCALFILE or false if known, undefined if not known. + // + // Files have to have a specific annotaton that they are machine written, for safety. + // We don't actually check for write access on files. + // + sparql.prototype.editable = function(uri, kb) { + if (!uri) return false; // Eg subject is bnode, no known doc to write to + if (!kb) kb = tabulator.kb; + + if (uri.slice(0,8) == 'file:///') { + if (kb.holds(kb.sym(uri), tabulator.ns.rdf('type'), tabulator.ns.link('MachineEditableDocument'))) + return 'LOCALFILE'; + var sts = kb.statementsMatching(kb.sym(uri),undefined,undefined); + + tabulator.log.warn("sparql.editable: Not MachineEditableDocument file "+uri+"\n"); + tabulator.log.warn(sts.map(function(x){return x.toNT();}).join('\n')) + return false; + //@@ Would be nifty of course to see whether we actually have write acess first. + } + + var request; + var definitive = false; + var requests = kb.each(undefined, this.ns.link("requestedURI"), $rdf.uri.docpart(uri)); + for (var r=0; r=0 ) return 'SPARQL'; + if (method.indexOf('DAV') >=0 ) return 'DAV'; +// if (author_via[i].value == "SPARQL" || author_via[i].value == "DAV") + // dump("sparql.editable: Success for "+uri+": "+author_via[i] +"\n"); + //return author_via[i].value; + + } + } + var status = kb.each(response, this.ns.http("status")); + if (status.length) { + for (var i = 0; i < status.length; i++) { + if (status[i] == 200 || status[i] == 404) { + definitive = true; + // return false; // A definitive answer + } + } + } + } else { + tabulator.log.warn("sparql.editable: No response for "+uri+"\n"); + } + } + } + if (requests.length == 0) { + tabulator.log.warn("sparql.editable: No request for "+uri+"\n"); + } else { + if (definitive) return false; // We have got a request and it did NOT say editable => not editable + }; + + tabulator.log.warn("sparql.editable: inconclusive for "+uri+"\n"); + return undefined; // We don't know (yet) as we haven't had a response (yet) + } + + /////////// The identification of bnodes + + + sparql.prototype.anonymize = function (obj) { + return (obj.toNT().substr(0,2) == "_:" && this._mentioned(obj)) + ? "?" + obj.toNT().substr(2) + : obj.toNT(); + } + + sparql.prototype.anonymizeNT = function(stmt) { + return this.anonymize(stmt.subject) + " " + + this.anonymize(stmt.predicate) + " " + + this.anonymize(stmt.object) + " ."; + } + + + + // A list of all bnodes occuring in a statement + sparql.prototype._statement_bnodes = function(st) { + return [st.subject, st.predicate, st.object].filter(function(x){return x.isBlank}); + } + + // A list of all bnodes occuring in a list of statements + sparql.prototype._statement_array_bnodes = function(sts) { + var bnodes = []; + for (var i=0; i 1 if try further indirection. + // Return array of statements (possibly empty), or null if failure + var sts = this.store.statementsMatching(undefined, undefined, x, source); // incoming links + for (var i=0; i\n query="+query+"\n"); + var xhr = $rdf.Util.XMLHTTPFactory(); + + xhr.onreadystatechange = function() { + //dump("SPARQL update ready state for <"+uri+"> readyState="+xhr.readyState+"\n"+query+"\n"); + if (xhr.readyState == 4) { + var success = (!xhr.status || (xhr.status >= 200 && xhr.status < 300)); + if (!success) tabulator.log.error("sparql: update failed for <"+uri+"> status="+ + xhr.status+", "+xhr.statusText+", body length="+xhr.responseText.length+"\n for query: "+query); + else tabulator.log.debug("sparql: update Ok for <"+uri+">"); + callback(uri, success, xhr.responseText, xhr); + } + } + + if(!tabulator.isExtension) { + try { + $rdf.Util.enablePrivilege("UniversalBrowserRead") + } catch(e) { + alert("Failed to get privileges: " + e) + } + } + + xhr.open('PATCH', uri, true); // async=true + xhr.setRequestHeader('Content-type', 'application/sparql-update'); + xhr.send(query); + } + + // This does NOT update the statement. + // It returns an object whcih includes + // function which can be used to change the object of the statement. + // + sparql.prototype.update_statement = function(statement) { + if (statement && statement.why == undefined) return; + + var sparql = this; + var context = this._statement_context(statement); + + return { + statement: statement?[statement.subject, statement.predicate, statement.object, statement.why]:undefined, + statementNT: statement ? this.anonymizeNT(statement):undefined, + where: sparql._context_where(context), + + set_object: function(obj, callback) { + query = this.where; + query += "DELETE DATA { " + this.statementNT + " } ;\n"; + query += "INSERT DATA { " + + this.anonymize(this.statement[0]) + " " + + this.anonymize(this.statement[1]) + " " + + this.anonymize(obj) + " " + " . }\n"; + + sparql._fire(this.statement[3].uri, query, callback); + } + } + } + + sparql.prototype.insert_statement = function(st, callback) { + var st0 = st instanceof Array ? st[0] : st; + var query = this._context_where(this._statement_context(st0)); + + if (st instanceof Array) { + var stText=""; + for (var i=0;i=0) { + var bnodes = [] + if (ds.length) bnodes = this._statement_array_bnodes(ds); + if (is.length) bnodes = bnodes.concat(this._statement_array_bnodes(is)); + var context = this._bnode_context(bnodes, doc); + var whereClause = this._context_where(context); + var query = "" + if (whereClause.length) { // Is there a WHERE clause? + if (ds.length) { + query += "DELETE { "; + for (var i=0; i=0) { + + // The code below is derived from Kenny's UpdateCenter.js + var documentString; + var request = kb.any(doc, this.ns.link("request")); + if (!request) throw "No record of our HTTP GET request for document: "+doc; //should not happen + var response = kb.any(request, this.ns.link("response")); + if (!response) return null; // throw "No record HTTP GET response for document: "+doc; + var content_type = kb.the(response, this.ns.httph("content-type")).value; + + //prepare contents of revised document + var newSts = kb.statementsMatching(undefined, undefined, undefined, doc).slice(); // copy! + for (var i=0;i= 200 && xhr.status < 300)); + if (success) { + for (var i=0; i=0) { + try { + tabulator.log.info("Writing back to local file\n"); + // See http://simon-jung.blogspot.com/2007/10/firefox-extension-file-io.html + //prepare contents of revised document + var newSts = kb.statementsMatching(undefined, undefined, undefined, doc).slice(); // copy! + for (var i=0;i>>\n") + var filename = doc.uri.slice(7); // chop off file:// leaving /path + //tabulator.log.warn("Writeback: Filename: "+filename+"\n") + var file = Components.classes["@mozilla.org/file/local;1"] + .createInstance(Components.interfaces.nsILocalFile); + file.initWithPath(filename); + if(!file.exists()) throw "Rewriting file <"+doc.uri+"> but it does not exist!"; + + //{ + //file.create( Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 420); + //} + //create file output stream and use write/create/truncate mode + //0x02 writing, 0x08 create file, 0x20 truncate length if exist + var stream = Components.classes["@mozilla.org/network/file-output-stream;1"] + .createInstance(Components.interfaces.nsIFileOutputStream); + + stream.init(file, 0x02 | 0x08 | 0x20, 0666, 0); + + //write data to file then close output stream + stream.write(documentString, documentString.length); + stream.close(); + + for (var i=0; i\n"+ + tabulator.Util.stackString(e)) + } + + } else throw "Unhandled edit method: '"+protocol+"' for "+doc; + }; + + // This suitable for an inital creation of a document + // + // data: string, or array of statements + // + sparql.prototype.put = function(doc, data, content_type, callback) { + + var documentString; + var kb = this.store; + + if (typeof data === typeof '') { + documentString = data; + } else { + //serialize to te appropriate format + var sz = $rdf.Serializer(kb); + sz.suggestNamespaces(kb.namespaces); + sz.setBase(doc.uri);//?? beware of this - kenny (why? tim) + switch(content_type){ + case 'application/rdf+xml': + documentString = sz.statementsToXML(data); + break; + case 'text/n3': + case 'text/turtle': + case 'application/x-turtle': // Legacy + case 'application/n3': // Legacy + documentString = sz.statementsToN3(data); + break; + default: + throw "Content-type "+content_type +" not supported for data PUT"; + } + } + var xhr = $rdf.Util.XMLHTTPFactory(); + xhr.onreadystatechange = function (){ + if (xhr.readyState == 4){ + //formula from sparqlUpdate.js, what about redirects? + var success = (!xhr.status || (xhr.status >= 200 && xhr.status < 300)); + callback(doc.uri, success, xhr.responseText, xhr); + } + }; + xhr.open('PUT', doc.uri, true); + xhr.setRequestHeader('Content-type', content_type); + xhr.send(documentString); + }; + + + + return sparql; + +}(); +$rdf.jsonParser = function() { + + return { + parseJSON: function( data, source, store ) { + var subject, predicate, object; + var bnodes = {}; + var why = store.sym(source); + for (x in data) { + if( x.indexOf( "_:") === 0 ) { + if( bnodes[x] ) { + subject = bnodes[x]; + } else { + subject = store.bnode(x); + bnodes[x]=subject; + } + } else { + subject = store.sym(x); + } + var preds = data[x]; + for (y in preds) { + var objects = preds[y]; + predicate = store.sym(y); + for( z in objects ) { + var obj = objects[z]; + if( obj.type === "uri" ) { + object = store.sym(obj.value); + store.add( subject, predicate, object, why ); + } else if( obj.type === "bnode" ) { + if( bnodes[obj.value] ) { + object = bnodes[obj.value]; + } else { + object = store.bnode(obj.value); + bnodes[obj.value] = object; + } + store.add( subject, predicate, object, why ); + } else if( obj.type === "literal" ) { + var datatype; + if( obj.datatype ) { + object = store.literal(obj.value, undefined, store.sym(obj.datatype)); + } else if ( obj.lang ) { + object = store.literal(obj.value, obj.lang); + } else { + object = store.literal(obj.value); + } + store.add( subject, predicate, object, why ); + } else { + throw "error: unexpected termtype: "+z.type; + } + } + } + } + } + } +}(); +/* Serialization of RDF Graphs +** +** Tim Berners-Lee 2006 +** This is or was http://dig.csail.mit.edu/2005/ajar/ajaw/js/rdf/serialize.js +** +** Bug: can't serialize http://data.semanticweb.org/person/abraham-bernstein/rdf +** in XML (from mhausenblas) +*/ + +// @@@ Check the whole toStr thing tosee whetehr it still makes sense -- tbl +// +$rdf.Serializer = function() { + +var __Serializer = function( store ){ + this.flags = ""; + this.base = null; + this.prefixes = []; + this.namespacesUsed = []; + this.keywords = ['a']; // The only one we generate at the moment + this.prefixchars = "abcdefghijklmnopqustuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + this.incoming = null; // Array not calculated yet + this.formulas = []; // remebering original formulae from hashes + this.store = store; + + /* pass */ +} + +__Serializer.prototype.setBase = function(base) + { this.base = base }; + +__Serializer.prototype.setFlags = function(flags) + { this.flags = flags?flags: '' }; + + +__Serializer.prototype.toStr = function(x) { + var s = x.toNT(); + if (x.termType == 'formula') { + this.formulas[s] = x; // remember as reverse does not work + } + return s; +}; + +__Serializer.prototype.fromStr = function(s) { + if (s[0] == '{') { + var x = this.formulas[s]; + if (!x) alert('No formula object for '+s) + return x; + } + return this.store.fromNT(s); +}; + + + + + +/* Accumulate Namespaces +** +** These are only hints. If two overlap, only one gets used +** There is therefore no guarantee in general. +*/ + +__Serializer.prototype.suggestPrefix = function(prefix, uri) { + if (prefix.slice(0,7) === 'default') return; // Try to weed these out + if (prefix.slice(0,2) === 'ns') return; // From others inferior algos + this.prefixes[uri] = prefix; +} + +// Takes a namespace -> prefix map +__Serializer.prototype.suggestNamespaces = function(namespaces) { + for (var px in namespaces) { + this.prefixes[namespaces[px]] = px; + } +} + +// Make up an unused prefix for a random namespace +__Serializer.prototype.makeUpPrefix = function(uri) { + var p = uri; + var namespaces = []; + var pok; + + function canUse(pp) { + if (namespaces[pp]) return false; // already used + if (! __Serializer.prototype.validPrefix.test(pp)) return false; // bad format + if (pp === 'ns') return false; // boring + this.prefixes[uri] = pp; + pok = pp; + return true + } + canUse = canUse.bind(this); + for (var ns in this.prefixes) { + namespaces[this.prefixes[ns]] = ns; // reverse index + } + if ('#/'.indexOf(p[p.length-1]) >= 0) p = p.slice(0, -1); + var slash = p.lastIndexOf('/'); + if (slash >= 0) p = p.slice(slash+1); + var i = 0; + while (i < p.length) + if (this.prefixchars.indexOf(p[i])) i++; else break; + p = p.slice(0,i); + if (p.length < 6 && canUse(p)) return pok; // exact i sbest + if (canUse(p.slice(0,3))) return pok; + if (canUse(p.slice(0,2))) return pok; + if (canUse(p.slice(0,4))) return pok; + if (canUse(p.slice(0,1))) return pok; + if (canUse(p.slice(0,5))) return pok; + if (! __Serializer.prototype.validPrefix.test(p)) { + p = 'n'; // Otherwise the loop below may never termimnate + } + for (var i=0;; i++) if (canUse(p.slice(0,3)+i)) return pok; +} + + + +// Todo: +// - Sort the statements by subject, pred, object +// - do stuff about the docu first and then (or first) about its primary topic. + +__Serializer.prototype.rootSubjects = function(sts) { + var incoming = {}; + var subjects = {}; + var allBnodes = {}; + +/* This scan is to find out which nodes will have to be the roots of trees +** in the serialized form. This will be any symbols, and any bnodes +** which hve more or less than one incoming arc, and any bnodes which have +** one incoming arc but it is an uninterrupted loop of such nodes back to itself. +** This should be kept linear time with repect to the number of statements. +** Note it does not use any indexing of the store. +*/ + + + // $rdf.log.debug('serialize.js Find bnodes with only one incoming arc\n') + for (var i = 0; i?@[\\]^`{|}~"; +__Serializer.prototype._notNameChars = + ( __Serializer.prototype._notQNameChars + ":" ) ; + + +__Serializer.prototype.statementsToN3 = function(sts) { + var indent = 4; + var width = 80; + + var predMap = { + 'http://www.w3.org/2002/07/owl#sameAs': '=', + 'http://www.w3.org/2000/10/swap/log#implies': '=>', + 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type': 'a' + } + + + + + ////////////////////////// Arrange the bits of text + + var spaces=function(n) { + var s=''; + for(var i=0; i=0) { + str = str.slice(0,-1) + branch + '\n'; // slip punct'n on end + lastLength += 1; + continue; + } else if ("])}".indexOf(branch) >=0) { + str = str.slice(0,-1) + ' ' + branch + '\n'; + lastLength += 2; + continue; + } + } + if (lastLength < (indent*level+4)) { // continue + str = str.slice(0,-1) + ' ' + branch + '\n'; + lastLength += branch.length + 1; + } else { + var line = spaces(indent*level) +branch; + str += line +'\n'; + lastLength = line.length; + } + + } else { // not string + } + } + return str; + }; + + ////////////////////////////////////////////// Structure for N3 + + + // Convert a set of statements into a nested tree of lists and strings + function statementListToTree(statements) { + // print('Statement tree for '+statements.length); + var res = []; + var stats = this.rootSubjects(statements); + var roots = stats.roots; + var results = [] + for (var i=0; i.\n'; + for (var ns in this.prefixes) { + if (!this.prefixes.hasOwnProperty(ns)) continue; + if (!this.namespacesUsed[ns]) continue; + str += '@prefix ' + this.prefixes[ns] + ': <' + + $rdf.uri.refTo(this.base, ns) + '>.\n'; + } + return str + '\n'; + } + prefixDirectives = prefixDirectives.bind(this); + + // Body of statementsToN3: + + var tree = statementListToTree(sts); + return prefixDirectives() + treeToString(tree, -1); + +} + + +////////////////////////////////////////////// Atomic Terms + +// Deal with term level things and nesting with no bnode structure + + +__Serializer.prototype.atomicTermToN3 = function atomicTermToN3(expr, stats) { + switch(expr.termType) { + case 'bnode': + case 'variable': return expr.toNT(); + case 'literal': + if (expr.datatype) { + switch (expr.datatype.uri) { + case 'http://www.w3.org/2001/XMLSchema#integer': + return expr.value.toString(); + + //case 'http://www.w3.org/2001/XMLSchema#double': // Must force use of 'e' + + case 'http://www.w3.org/2001/XMLSchema#boolean': + return expr.value? 'true' : 'false'; + } + } + var str = this.stringToN3(expr.value); + if (expr.lang) str+= '@' + expr.lang; + if (expr.datatype) str+= '^^' + this.termToN3(expr.datatype, stats); + return str; + case 'symbol': + return this.symbolToN3(expr); + default: + throw "Internal: atomicTermToN3 cannot handle "+expr+" of termType+"+expr.termType + return ''+expr; + } +}; + + // stringToN3: String escaping for N3 + +__Serializer.prototype.validPrefix = new RegExp(/^[a-zA-Z][a-zA-Z0-9]*$/); + +__Serializer.prototype.forbidden1 = new RegExp(/[\\"\b\f\r\v\t\n\u0080-\uffff]/gm); +__Serializer.prototype.forbidden3 = new RegExp(/[\\"\b\f\r\v\u0080-\uffff]/gm); +__Serializer.prototype.stringToN3 = function stringToN3(str, flags) { + if (!flags) flags = "e"; + var res = '', i=0, j=0; + var delim; + var forbidden; + if (str.length > 20 // Long enough to make sense + && str.slice(-1) != '"' // corner case' + && flags.indexOf('n') <0 // Force single line + && (str.indexOf('\n') >0 || str.indexOf('"') > 0)) { + delim = '"""'; + forbidden = __Serializer.prototype.forbidden3; + } else { + delim = '"'; + forbidden = __Serializer.prototype.forbidden1; + } + for(i=0; i= 0) { + res += "\\" + 'bfrtvn\\"'[k]; + } else { + if (flags.indexOf('e')>=0) { + res += '\\u' + ('000'+ + ch.charCodeAt(0).toString(16).toLowerCase()).slice(-4) + } else { // no 'e' flag + res += ch; + + } + } + } + i = j+1; + } + return delim + res + str.slice(i) + delim +} + + + +// A single symbol, either in <> or namespace notation + + +__Serializer.prototype.symbolToN3 = function symbolToN3(x) { // c.f. symbolString() in notation3.py + var uri = x.uri; + var j = uri.indexOf('#'); + if (j<0 && this.flags.indexOf('/') < 0) { + j = uri.lastIndexOf('/'); + } + if (j >= 0 && this.flags.indexOf('p') < 0) { // Can split at namespace + var canSplit = true; + for (var k=j+1; k=0) { + canSplit = false; break; + } + } + + if (uri.slice(0, j) == this.base) { // base-relative + return '<#' + uri.slice(j+1) + '>'; + } + if (canSplit) { + var localid = uri.slice(j+1); + var namesp = uri.slice(0,j+1); + if (this.defaultNamespace && this.defaultNamespace == namesp + && this.flags.indexOf('d') < 0) {// d -> suppress default + if (this.flags.indexOf('k') >= 0 && + this.keyords.indexOf(localid) <0) + return localid; + return ':' + localid; + } + var prefix = this.prefixes[namesp]; + if (!prefix) prefix = this.makeUpPrefix(namesp); + if (prefix) { + this.namespacesUsed[namesp] = true; + return prefix + ':' + localid; + } + // Fall though if can't do qname + } + } + if (this.flags.indexOf('r') < 0 && this.base) + uri = $rdf.uri.refTo(this.base, uri); + else if (this.flags.indexOf('u') >= 0) + uri = backslashUify(uri); + else uri = hexify(uri); + return '<'+uri+'>'; +} + + +// String ecaping utilities + + +function hexify(str) { // also used in parser + return encodeURI(str); +} + + +function backslashUify(str) { + var res = '', k; + for (var i=0; i65535) + res += '\\U' + ('00000000'+k.toString(16)).slice(-8); // convert to upper? + else if (k>126) + res += '\\u' + ('0000'+k.toString(16)).slice(-4); + else + res += str[i]; + } + return res; +} + + +///////////////////////////// Quad store serialization + + +// @para. write - a function taking a single string to be output +// +__Serializer.prototype.writeStore = function(write) { + + var kb = this.store; + var fetcher = kb.fetcher; + var session = fetcher && fetcher.appNode; + + // Everything we know from experience just write out. + // It is undder the session and the requests. + + var metaSources = kb.statementsMatching(undefined, + kb.sym('http://www.w3.org/2007/ont/link#requestedURI')).map( + function(st){return st.subject}); + if (session) metaSources.push(session); + var metadata = []; + metaSources.map(function(source){ + metadata = metadata.concat(kb.statementsMatching(undefined, undefined, undefined, source)); + }); + write(this.statementsToN3(metadata)); + + var sources = this.store.index[3]; + for (s in sources) { // -> assume we can use -> as short for log:semantics + var source = kb.fromNT(s); + if (session && source.sameTerm(session)) continue; + write('\n'+ this.atomicTermToN3(source)+' ' + + this.atomicTermToN3(kb.sym('http://www.w3.org/2000/10/swap/log#')) + + ' { '+ this.statementsToN3(kb.statementsMatching( + undefined, undefined, undefined, source)) + ' }.\n'); + } +} + + + + + +//////////////////////////////////////////////// XML serialization + +__Serializer.prototype.statementsToXML = function(sts) { + var indent = 4; + var width = 80; + + var namespaceCounts = []; // which have been used + namespaceCounts['http://www.w3.org/1999/02/22-rdf-syntax-ns#'] = true; + + var liPrefix = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#_'; //prefix for ordered list items + + ////////////////////////// Arrange the bits of XML text + + var spaces=function(n) { + var s=''; + for(var i=0; i', + subjectXMLTree(st.object, stats), + '']); + } else { + results = results.concat(['<'+ t +' rdf:nodeID="' + +st.object.toNT().slice(2)+'"/>']); + } + break; + case 'symbol': + results = results.concat(['<'+ t +' rdf:resource="' + + relURI(st.object)+'"/>']); + break; + case 'literal': + results = results.concat(['<'+ t + + (st.object.dt ? ' rdf:datatype="'+escapeForXML(st.object.dt.uri)+'"' : '') + + (st.object.lang ? ' xml:lang="'+st.object.lang+'"' : '') + + '>' + escapeForXML(st.object.value) + + '']); + break; + case 'collection': + results = results.concat(['<'+ t +' rdf:parseType="Collection">', + collectionXMLTree(st.object, stats), + '']); + break; + default: + throw "Can't serialize object of type "+st.object.termType +" into XML"; + } // switch + } + + var tag = type ? qname(type) : 'rdf:Description'; + + var attrs = ''; + if (subject.termType == 'bnode') { + if(!stats.incoming[subject] || stats.incoming[subject].length != 1) { // not an anonymous bnode + attrs = ' rdf:nodeID="'+subject.toNT().slice(2)+'"'; + } + } else { + attrs = ' rdf:about="'+ relURI(subject)+'"'; + } + + return [ '<' + tag + attrs + '>' ].concat([results]).concat([""]); + } + + subjectXMLTree = subjectXMLTree.bind(this); + + function collectionXMLTree(subject, stats) { + var res = [] + for (var i=0; i< subject.elements.length; i++) { + res.push(subjectXMLTree(subject.elements[i], stats)); + } + return res; + } + + // The property tree for a single subject or anonymos node + function propertyXMLTree(subject, stats) { + var results = [] + var sts = stats.subjects[this.toStr(subject)]; // relevant statements + if (sts == undefined) return results; // No relevant statements + sts.sort(); + for (var i=0; i', + '']); + } else { + results = results.concat(['<'+qname(st.predicate)+' rdf:parseType="Resource">', + propertyXMLTree(st.object, stats), + '']); + } + break; + case 'symbol': + results = results.concat(['<'+qname(st.predicate)+' rdf:resource="' + + relURI(st.object)+'"/>']); + break; + case 'literal': + results = results.concat(['<'+qname(st.predicate) + + (st.object.datatype ? ' rdf:datatype="'+escapeForXML(st.object.datatype.uri)+'"' : '') + + (st.object.lang ? ' xml:lang="'+st.object.lang+'"' : '') + + '>' + escapeForXML(st.object.value) + + '']); + break; + case 'collection': + results = results.concat(['<'+qname(st.predicate)+' rdf:parseType="Collection">', + collectionXMLTree(st.object, stats), + '']); + break; + default: + throw "Can't serialize object of type "+st.object.termType +" into XML"; + + } // switch + } + return results; + } + propertyXMLTree = propertyXMLTree.bind(this); + + function qname(term) { + var uri = term.uri; + + var j = uri.indexOf('#'); + if (j<0 && this.flags.indexOf('/') < 0) { + j = uri.lastIndexOf('/'); + } + if (j < 0) throw ("Cannot make qname out of <"+uri+">") + + var canSplit = true; + for (var k=j+1; k=0) { + throw ('Invalid character "'+uri[k] +'" cannot be in XML qname for URI: '+uri); + } + } + var localid = uri.slice(j+1); + var namesp = uri.slice(0,j+1); + if (this.defaultNamespace && this.defaultNamespace == namesp + && this.flags.indexOf('d') < 0) {// d -> suppress default + return localid; + } + var prefix = this.prefixes[namesp]; + if (!prefix) prefix = this.makeUpPrefix(namesp); + namespaceCounts[namesp] = true; + return prefix + ':' + localid; +// throw ('No prefix for namespace "'+namesp +'" for XML qname for '+uri+', namespaces: '+sz.prefixes+' sz='+sz); + } + qname = qname.bind(this); + + // Body of toXML: + + var tree = statementListToXMLTree(sts); + var str = '']; //@@ namespace declrations + return XMLtreeToString(tree2, -1); + + +} // End @@ body + +var Serializer = function( store ) {return new __Serializer( store )}; +return Serializer; + +}(); +/* + * Updates-Via + */ +var $rdf, k, v, + __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __hasProp = {}.hasOwnProperty; + +if (typeof $rdf === "undefined" || $rdf === null) { + $rdf = {}; +} + +$rdf.UpdatesSocket = (function() { + function UpdatesSocket(parent, via) { + var error; + this.parent = parent; + this.via = via; + this.subscribe = __bind(this.subscribe, this); + this.onError = __bind(this.onError, this); + this.onMessage = __bind(this.onMessage, this); + this.onClose = __bind(this.onClose, this); + this.onOpen = __bind(this.onOpen, this); + this._subscribe = __bind(this._subscribe, this); + this._send = __bind(this._send, this); + this.connected = false; + this.pending = {}; + this.subscribed = {}; + this.socket = {}; + try { + this.socket = new WebSocket(via); + this.socket.onopen = this.onOpen; + this.socket.onclose = this.onClose; + this.socket.onmessage = this.onMessage; + this.socket.onerror = this.onError; + } catch (_error) { + error = _error; + this.onError(error); + } + } + + UpdatesSocket.prototype._decode = function(q) { + var elt, i, k, r, v, _ref, _ref1; + r = {}; + _ref = (function() { + var _i, _len, _ref, _results; + _ref = q.split('&'); + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + elt = _ref[_i]; + _results.push(elt.split('=')); + } + return _results; + })(); + for (i in _ref) { + elt = _ref[i]; + _ref1 = [decodeURIComponent(elt[0]), decodeURIComponent(elt[1])], k = _ref1[0], v = _ref1[1]; + if (r[k] == null) { + r[k] = []; + } + r[k].push(v); + } + return r; + }; + + UpdatesSocket.prototype._send = function(method, uri, data) { + var message, _base; + message = [method, uri, data].join(' '); + return typeof (_base = this.socket).send === "function" ? _base.send(message) : void 0; + }; + + UpdatesSocket.prototype._subscribe = function(uri) { + this._send('sub', uri, ''); + return this.subscribed[uri] = true; + }; + + UpdatesSocket.prototype.onOpen = function(e) { + var uri, _results; + this.connected = true; + _results = []; + for (uri in this.pending) { + delete this.pending[uri]; + _results.push(this._subscribe(uri)); + } + return _results; + }; + + UpdatesSocket.prototype.onClose = function(e) { + var uri; + this.connected = false; + for (uri in this.subscribed) { + this.pending[uri] = true; + } + return this.subscribed = {}; + }; + + UpdatesSocket.prototype.onMessage = function(e) { + var message, _base; + message = e.data.split(' '); + if (message[0] === 'ping') { + return typeof (_base = this.socket).send === "function" ? _base.send('pong ' + message.slice(1).join(' ')) : void 0; + } else if (message[0] === 'pub') { + return this.parent.onUpdate(message[1], this._decode(message[2])); + } + }; + + UpdatesSocket.prototype.onError = function(e) { + throw 'onError' + e; + }; + + UpdatesSocket.prototype.subscribe = function(uri) { + if (this.connected) { + return this._subscribe(uri); + } else { + return this.pending[uri] = true; + } + }; + + return UpdatesSocket; + +})(); + +$rdf.UpdatesVia = (function() { + function UpdatesVia(fetcher) { + this.fetcher = fetcher; + this.onUpdate = __bind(this.onUpdate, this); + this.onHeaders = __bind(this.onHeaders, this); + this.register = __bind(this.register, this); + this.graph = {}; + this.via = {}; + this.fetcher.addCallback('headers', this.onHeaders); + } + + UpdatesVia.prototype.register = function(via, uri) { + if (this.via[via] == null) { + this.via[via] = new $rdf.UpdatesSocket(this, via); + } + return this.via[via].subscribe(uri); + }; + + UpdatesVia.prototype.onHeaders = function(d) { + var etag, uri, via; + if (d.headers == null) { + return true; + } + if (typeof WebSocket === "undefined" || WebSocket === null) { + return true; + } + etag = d.headers['etag']; + via = d.headers['updates-via']; + uri = d.uri; + if (etag && via) { + this.graph[uri] = { + etag: etag, + via: via + }; + this.register(via, uri); + } + return true; + }; + + UpdatesVia.prototype.onUpdate = function(uri, d) { + return this.fetcher.refresh($rdf.sym(uri)); + }; + + return UpdatesVia; + +})(); + +if ((typeof module !== "undefined" && module !== null ? module.exports : void 0) != null) { + for (k in $rdf) { + if (!__hasProp.call($rdf, k)) continue; + v = $rdf[k]; + module.exports[k] = v; + } +} +/************************************************************ + * + * Project: rdflib.js, originally part of Tabulator project + * + * File: web.js + * + * Description: contains functions for requesting/fetching/retracting + * This implements quite a lot of the web architecture. + * A fetcher is bound to a specific knowledge base graph, into which + * it loads stuff and into which it writes its metadata + * @@ The metadata should be optionally a separate graph + * + * - implements semantics of HTTP headers, Internet Content Types + * - selects parsers for rdf/xml, n3, rdfa, grddl + * + * Dependencies: + * + * needs: util.js uri.js term.js rdfparser.js rdfa.js n3parser.js + * identity.js sparql.js jsonparser.js + * + * If jQuery is defined, it uses jQuery.ajax, else is independent of jQuery + * + ************************************************************/ + +/** + * Things to test: callbacks on request, refresh, retract + * loading from HTTP, HTTPS, FTP, FILE, others? + * To do: + * Firing up a mail client for mid: (message:) URLs + */ + +if (typeof module !== 'undefined' && module.require) { // Node +// For non-node, jasonld needs to be inlined in init.js etc + $rdf.jsonld = require('jsonld'); + N3 = require('n3'); + asyncLib = require('async'); +} + +$rdf.Fetcher = function(store, timeout, async) { + this.store = store + this.thisURI = "http://dig.csail.mit.edu/2005/ajar/ajaw/rdf/sources.js" + "#SourceFetcher" // -- Kenny + this.timeout = timeout ? timeout : 30000 + this.async = async != null ? async : true + this.appNode = this.store.bnode(); // Denoting this session + this.store.fetcher = this; //Bi-linked + this.requested = {} + this.lookedUp = {} + this.handlers = [] + this.mediatypes = {} + var sf = this + var kb = this.store; + var ns = {} // Convenience namespaces needed in this module: + // These are delibertely not exported as the user application should + // make its own list and not rely on the prefixes used here, + // and not be tempted to add to them, and them clash with those of another + // application. + ns.link = $rdf.Namespace("http://www.w3.org/2007/ont/link#"); + ns.http = $rdf.Namespace("http://www.w3.org/2007/ont/http#"); + ns.httph = $rdf.Namespace("http://www.w3.org/2007/ont/httph#"); + ns.rdf = $rdf.Namespace("http://www.w3.org/1999/02/22-rdf-syntax-ns#"); + ns.rdfs = $rdf.Namespace("http://www.w3.org/2000/01/rdf-schema#"); + ns.dc = $rdf.Namespace("http://purl.org/dc/elements/1.1/"); + + + $rdf.Fetcher.crossSiteProxy = function(uri) { + if ($rdf.Fetcher.crossSiteProxyTemplate) + return $rdf.Fetcher.crossSiteProxyTemplate.replace('{uri}', encodeURIComponent(uri)); + else return undefined; + }; + $rdf.Fetcher.RDFXMLHandler = function(args) { + if (args) { + this.dom = args[0] + } + this.handlerFactory = function(xhr) { + xhr.handle = function(cb) { + //sf.addStatus(xhr.req, 'parsing soon as RDF/XML...'); + var kb = sf.store; + if (!this.dom) this.dom = $rdf.Util.parseXML(xhr.responseText); +/* { + var dparser; + if ((typeof tabulator != 'undefined' && tabulator.isExtension)) { + dparser = Components.classes["@mozilla.org/xmlextras/domparser;1"].getService(Components.interfaces.nsIDOMParser); + } else { + dparser = new DOMParser() + } + //strange things happen when responseText is empty + this.dom = dparser.parseFromString(xhr.responseText, 'application/xml') + } +*/ + var root = this.dom.documentElement; + if (root.nodeName == 'parsererror') { //@@ Mozilla only See issue/issue110 + sf.failFetch(xhr, "Badly formed XML in " + xhr.resource.uri); //have to fail the request + throw new Error("Badly formed XML in " + xhr.resource.uri); //@@ Add details + } + // Find the last URI we actual URI in a series of redirects + // (xhr.resource.uri is the original one) + var lastRequested = kb.any(xhr.req, ns.link('requestedURI')); + if (!lastRequested) { + lastRequested = xhr.resource; + } else { + lastRequested = kb.sym(lastRequested.value); + } + var parser = new $rdf.RDFParser(kb); + // sf.addStatus(xhr.req, 'parsing as RDF/XML...'); + parser.parse(this.dom, lastRequested.uri, lastRequested); + kb.add(lastRequested, ns.rdf('type'), ns.link('RDFDocument'), sf.appNode); + cb(); + } + } + }; + $rdf.Fetcher.RDFXMLHandler.term = this.store.sym(this.thisURI + ".RDFXMLHandler"); + $rdf.Fetcher.RDFXMLHandler.toString = function() { + return "RDFXMLHandler" + }; + $rdf.Fetcher.RDFXMLHandler.register = function(sf) { + sf.mediatypes['application/rdf+xml'] = {} + }; + $rdf.Fetcher.RDFXMLHandler.pattern = new RegExp("application/rdf\\+xml"); + + // This would much better use on-board XSLT engine. @@ + $rdf.Fetcher.doGRDDL = function(kb, doc, xslturi, xmluri) { + sf.requestURI('http://www.w3.org/2005/08/' + 'online_xslt/xslt?' + 'xslfile=' + escape(xslturi) + '&xmlfile=' + escape(xmluri), doc) + }; + + $rdf.Fetcher.XHTMLHandler = function(args) { + if (args) { + this.dom = args[0] + } + this.handlerFactory = function(xhr) { + xhr.handle = function(cb) { + if (!this.dom) { + var dparser; + if (typeof tabulator != 'undefined' && tabulator.isExtension) { + dparser = Components.classes["@mozilla.org/xmlextras/domparser;1"].getService(Components.interfaces.nsIDOMParser); + } else { + dparser = new DOMParser() + } + this.dom = dparser.parseFromString(xhr.responseText, 'application/xml') + } + var kb = sf.store; + + // dc:title + var title = this.dom.getElementsByTagName('title') + if (title.length > 0) { + kb.add(xhr.resource, ns.dc('title'), kb.literal(title[0].textContent), xhr.resource) + // $rdf.log.info("Inferring title of " + xhr.resource) + } + + // link rel + var links = this.dom.getElementsByTagName('link'); + for (var x = links.length - 1; x >= 0; x--) { + sf.linkData(xhr, links[x].getAttribute('rel'), links[x].getAttribute('href')); + } + + //GRDDL + var head = this.dom.getElementsByTagName('head')[0] + if (head) { + var profile = head.getAttribute('profile'); + if (profile && $rdf.uri.protocol(profile) == 'http') { + // $rdf.log.info("GRDDL: Using generic " + "2003/11/rdf-in-xhtml-processor."); + $rdf.Fetcher.doGRDDL(kb, xhr.resource, "http://www.w3.org/2003/11/rdf-in-xhtml-processor", xhr.resource.uri) +/* sf.requestURI('http://www.w3.org/2005/08/' + + 'online_xslt/xslt?' + + 'xslfile=http://www.w3.org' + + '/2003/11/' + + 'rdf-in-xhtml-processor' + + '&xmlfile=' + + escape(xhr.resource.uri), + xhr.resource) + */ + } else { + // $rdf.log.info("GRDDL: No GRDDL profile in " + xhr.resource) + } + } + kb.add(xhr.resource, ns.rdf('type'), ns.link('WebPage'), sf.appNode); + // Do RDFa here + if ($rdf.rdfa && $rdf.rdfa.parse) + $rdf.rdfa.parse(this.dom, kb, xhr.resource.uri); + cb(); // Fire done callbacks + } + } + }; + $rdf.Fetcher.XHTMLHandler.term = this.store.sym(this.thisURI + ".XHTMLHandler"); + $rdf.Fetcher.XHTMLHandler.toString = function() { + return "XHTMLHandler" + }; + $rdf.Fetcher.XHTMLHandler.register = function(sf) { + sf.mediatypes['application/xhtml+xml'] = { + 'q': 0.3 + } + }; + $rdf.Fetcher.XHTMLHandler.pattern = new RegExp("application/xhtml"); + + + /******************************************************/ + + $rdf.Fetcher.XMLHandler = function() { + this.handlerFactory = function(xhr) { + xhr.handle = function(cb) { + var kb = sf.store + var dparser; + if (typeof tabulator != 'undefined' && tabulator.isExtension) { + dparser = Components.classes["@mozilla.org/xmlextras/domparser;1"].getService(Components.interfaces.nsIDOMParser); + } else { + dparser = new DOMParser() + } + var dom = dparser.parseFromString(xhr.responseText, 'application/xml') + + // XML Semantics defined by root element namespace + // figure out the root element + for (var c = 0; c < dom.childNodes.length; c++) { + // is this node an element? + if (dom.childNodes[c].nodeType == 1) { + // We've found the first element, it's the root + var ns = dom.childNodes[c].namespaceURI; + + // Is it RDF/XML? + if (ns != undefined && ns == ns['rdf']) { + sf.addStatus(xhr.req, "Has XML root element in the RDF namespace, so assume RDF/XML.") + sf.switchHandler('RDFXMLHandler', xhr, cb, [dom]) + return + } + // it isn't RDF/XML or we can't tell + // Are there any GRDDL transforms for this namespace? + // @@ assumes ns documents have already been loaded + var xforms = kb.each(kb.sym(ns), kb.sym("http://www.w3.org/2003/g/data-view#namespaceTransformation")); + for (var i = 0; i < xforms.length; i++) { + var xform = xforms[i]; + // $rdf.log.info(xhr.resource.uri + " namespace " + ns + " has GRDDL ns transform" + xform.uri); + $rdf.Fetcher.doGRDDL(kb, xhr.resource, xform.uri, xhr.resource.uri); + } + break + } + } + + // Or it could be XHTML? + // Maybe it has an XHTML DOCTYPE? + if (dom.doctype) { + // $rdf.log.info("We found a DOCTYPE in " + xhr.resource) + if (dom.doctype.name == 'html' && dom.doctype.publicId.match(/^-\/\/W3C\/\/DTD XHTML/) && dom.doctype.systemId.match(/http:\/\/www.w3.org\/TR\/xhtml/)) { + sf.addStatus(xhr.req,"Has XHTML DOCTYPE. Switching to XHTML Handler.\n") + sf.switchHandler('XHTMLHandler', xhr, cb) + return + } + } + + // Or what about an XHTML namespace? + var html = dom.getElementsByTagName('html')[0] + if (html) { + var xmlns = html.getAttribute('xmlns') + if (xmlns && xmlns.match(/^http:\/\/www.w3.org\/1999\/xhtml/)) { + sf.addStatus(xhr.req, "Has a default namespace for " + "XHTML. Switching to XHTMLHandler.\n") + sf.switchHandler('XHTMLHandler', xhr, cb) + return + } + } + + // At this point we should check the namespace document (cache it!) and + // look for a GRDDL transform + // @@ Get namespace document , parse it, look for grddl:namespaceTransform ?y + // Apply ?y to dom + // We give up. What dialect is this? + sf.failFetch(xhr, "Unsupported dialect of XML: not RDF or XHTML namespace, etc.\n"+xhr.responseText.slice(0,80)); + } + } + }; + $rdf.Fetcher.XMLHandler.term = this.store.sym(this.thisURI + ".XMLHandler"); + $rdf.Fetcher.XMLHandler.toString = function() { + return "XMLHandler" + }; + $rdf.Fetcher.XMLHandler.register = function(sf) { + sf.mediatypes['text/xml'] = { + 'q': 0.2 + } + sf.mediatypes['application/xml'] = { + 'q': 0.2 + } + }; + $rdf.Fetcher.XMLHandler.pattern = new RegExp("(text|application)/(.*)xml"); + + $rdf.Fetcher.HTMLHandler = function() { + this.handlerFactory = function(xhr) { + xhr.handle = function(cb) { + var rt = xhr.responseText + // We only handle XHTML so we have to figure out if this is XML + // $rdf.log.info("Sniffing HTML " + xhr.resource + " for XHTML."); + + if (rt.match(/\s*<\?xml\s+version\s*=[^<>]+\?>/)) { + sf.addStatus(xhr.req, "Has an XML declaration. We'll assume " + + "it's XHTML as the content-type was text/html.\n") + sf.switchHandler('XHTMLHandler', xhr, cb) + return + } + + // DOCTYPE + // There is probably a smarter way to do this + if (rt.match(/.*/)) { + sf.addStatus(xhr.req, "Has XHTML DOCTYPE. Switching to XHTMLHandler.\n") + sf.switchHandler('XHTMLHandler', xhr, cb) + return + } + + // xmlns + if (rt.match(/[^(/)) { + sf.addStatus(xhr.req, "Has default namespace for XHTML, so switching to XHTMLHandler.\n") + sf.switchHandler('XHTMLHandler', xhr, cb) + return + } + + + // dc:title //no need to escape '/' here + var titleMatch = (new RegExp("([\\s\\S]+?)", 'im')).exec(rt); + if (titleMatch) { + var kb = sf.store; + kb.add(xhr.resource, ns.dc('title'), kb.literal(titleMatch[1]), xhr.resource); //think about xml:lang later + kb.add(xhr.resource, ns.rdf('type'), ns.link('WebPage'), sf.appNode); + cb(); //doneFetch, not failed + return; + } + + sf.failFetch(xhr, "Sorry, can't yet parse non-XML HTML") + } + } + }; + $rdf.Fetcher.HTMLHandler.term = this.store.sym(this.thisURI + ".HTMLHandler"); + $rdf.Fetcher.HTMLHandler.toString = function() { + return "HTMLHandler" + }; + $rdf.Fetcher.HTMLHandler.register = function(sf) { + sf.mediatypes['text/html'] = { + 'q': 0.3 + } + }; + $rdf.Fetcher.HTMLHandler.pattern = new RegExp("text/html"); + + /***********************************************/ + + $rdf.Fetcher.TextHandler = function() { + this.handlerFactory = function(xhr) { + xhr.handle = function(cb) { + // We only speak dialects of XML right now. Is this XML? + var rt = xhr.responseText + + // Look for an XML declaration + if (rt.match(/\s*<\?xml\s+version\s*=[^<>]+\?>/)) { + sf.addStatus(xhr.req, "Warning: "+xhr.resource + " has an XML declaration. We'll assume " + + "it's XML but its content-type wasn't XML.\n") + sf.switchHandler('XMLHandler', xhr, cb) + return + } + + // Look for an XML declaration + if (rt.slice(0, 500).match(/xmlns:/)) { + sf.addStatus(xhr.req, "May have an XML namespace. We'll assume " + + "it's XML but its content-type wasn't XML.\n") + sf.switchHandler('XMLHandler', xhr, cb) + return + } + + // We give up finding semantics - this is not an error, just no data + sf.addStatus(xhr.req, "Plain text document, no known RDF semantics."); + sf.doneFetch(xhr, [xhr.resource.uri]); +// sf.failFetch(xhr, "unparseable - text/plain not visibly XML") +// dump(xhr.resource + " unparseable - text/plain not visibly XML, starts:\n" + rt.slice(0, 500)+"\n") + + } + } + }; + $rdf.Fetcher.TextHandler.term = this.store.sym(this.thisURI + ".TextHandler"); + $rdf.Fetcher.TextHandler.toString = function() { + return "TextHandler"; + }; + $rdf.Fetcher.TextHandler.register = function(sf) { + sf.mediatypes['text/plain'] = { + 'q': 0.1 + } + } + $rdf.Fetcher.TextHandler.pattern = new RegExp("text/plain"); + + /***********************************************/ + + $rdf.Fetcher.N3Handler = function() { + this.handlerFactory = function(xhr) { + xhr.handle = function(cb) { + // Parse the text of this non-XML file + $rdf.log.debug("web.js: Parsing as N3 " + xhr.resource.uri); // @@@@ comment me out + //sf.addStatus(xhr.req, "N3 not parsed yet...") + var rt = xhr.responseText + var p = $rdf.N3Parser(kb, kb, xhr.resource.uri, xhr.resource.uri, null, null, "", null) + // p.loadBuf(xhr.responseText) + try { + p.loadBuf(xhr.responseText) + + } catch (e) { + var msg = ("Error trying to parse " + xhr.resource + " as Notation3:\n" + e +':\n'+e.stack) + // dump(msg+"\n") + sf.failFetch(xhr, msg) + return; + } + + sf.addStatus(xhr.req, "N3 parsed: " + p.statementCount + " triples in " + p.lines + " lines.") + sf.store.add(xhr.resource, ns.rdf('type'), ns.link('RDFDocument'), sf.appNode); + args = [xhr.resource.uri]; // Other args needed ever? + sf.doneFetch(xhr, args) + } + } + }; + $rdf.Fetcher.N3Handler.term = this.store.sym(this.thisURI + ".N3Handler"); + $rdf.Fetcher.N3Handler.toString = function() { + return "N3Handler"; + } + $rdf.Fetcher.N3Handler.register = function(sf) { + sf.mediatypes['text/n3'] = { + 'q': '1.0' + } // as per 2008 spec + sf.mediatypes['application/x-turtle'] = { + 'q': 1.0 + } // pre 2008 + sf.mediatypes['text/turtle'] = { + 'q': 1.0 + } // pre 2008 + } + $rdf.Fetcher.N3Handler.pattern = new RegExp("(application|text)/(x-)?(rdf\\+)?(n3|turtle)") + + /***********************************************/ + + $rdf.Util.callbackify(this, ['request', 'recv', 'headers', 'load', 'fail', 'refresh', 'retract', 'done']); + + this.addProtocol = function(proto) { + sf.store.add(sf.appNode, ns.link("protocol"), sf.store.literal(proto), this.appNode) + } + + this.addHandler = function(handler) { + sf.handlers.push(handler) + handler.register(sf) + } + + this.switchHandler = function(name, xhr, cb, args) { + var kb = this.store; var handler = null; + for (var i=0; i + var now = new Date(); + status = "[" + now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds() + "." + now.getMilliseconds() + "] " + status; + // + var kb = this.store + var s = kb.the(req, ns.link('status')); + if (s && s.append) { + s.append(kb.literal(status)); + } else { + $rdf.log.warn("web.js: No list to add to: " + s + ',' + status); // @@@ + }; + } + + // Record errors in the system on failure + // Returns xhr so can just do return this.failfetch(...) + this.failFetch = function(xhr, status) { + this.addStatus(xhr.req, status) + kb.add(xhr.resource, ns.link('error'), status) + this.requested[$rdf.uri.docpart(xhr.resource.uri)] = false + if (xhr.userCallback) { + xhr.userCallback(false, "Fetch of <" + xhr.resource.uri + "> failed: "+status, xhr) + }; + this.fireCallbacks('fail', [xhr.requestedURI, status]) + xhr.abort() + return xhr + } + + this.linkData = function(xhr, rel, uri) { + var x = xhr.resource; + if (!uri) return; + // See http://www.w3.org/TR/powder-dr/#httplink for describedby 2008-12-10 + if (rel == 'alternate' || rel == 'seeAlso' || rel == 'meta' || rel == 'describedby') { + // var join = $rdf.uri.join2; // doesn't work, now a method of rdf.uri + var obj = kb.sym($rdf.uri.join(uri, xhr.resource.uri)) + if (obj.uri != xhr.resource) { + kb.add(xhr.resource, ns.rdfs('seeAlso'), obj, xhr.resource); + // $rdf.log.info("Loading " + obj + " from link rel in " + xhr.resource); + } + } + }; + + this.doneFetch = function(xhr, args) { + this.addStatus(xhr.req, 'Done.') + // $rdf.log.info("Done with parse, firing 'done' callbacks for " + xhr.resource) + this.requested[xhr.resource.uri] = 'done'; //Kenny + if (xhr.userCallback) { + xhr.userCallback(true, undefined, xhr); + }; + this.fireCallbacks('done', args) + } + + this.store.add(this.appNode, ns.rdfs('label'), this.store.literal('This Session'), this.appNode); + + ['http', 'https', 'file', 'chrome'].map(this.addProtocol); // ftp? mailto:? + [$rdf.Fetcher.RDFXMLHandler, $rdf.Fetcher.XHTMLHandler, $rdf.Fetcher.XMLHandler, $rdf.Fetcher.HTMLHandler, $rdf.Fetcher.TextHandler, $rdf.Fetcher.N3Handler ].map(this.addHandler) + + + + /** Note two nodes are now smushed + ** + ** If only one was flagged as looked up, then + ** the new node is looked up again, which + ** will make sure all the URIs are dereferenced + */ + this.nowKnownAs = function(was, now) { + if (this.lookedUp[was.uri]) { + if (!this.lookedUp[now.uri]) this.lookUpThing(now, was) // @@@@ Transfer userCallback + } else if (this.lookedUp[now.uri]) { + if (!this.lookedUp[was.uri]) this.lookUpThing(was, now) + } + } + + + + + + // Looks up something. + // + // Looks up all the URIs a things has. + // Parameters: + // + // term: canonical term for the thing whose URI is to be dereferenced + // rterm: the resource which refered to this (for tracking bad links) + // force: Load the data even if loaded before + // oneDone: is called as callback(ok, errorbody, xhr) for each one + // allDone: is called as callback(ok, errorbody) for all of them + // Returns the number of things looked up + // + this.lookUpThing = function(term, rterm, force, oneDone, allDone) { + var uris = kb.uris(term) // Get all URIs + var success = true; + var errors = ''; + var outstanding = {}; + + if (typeof uris !== 'undefined') { + for (var i = 0; i < uris.length; i++) { + var u = uris[i]; + outstanding[u] = true; + this.lookedUp[u] = true; + var sf = this; + + var requestOne = function requestOne(u1){ + sf.requestURI($rdf.uri.docpart(u1), rterm, force, function(ok, body, xhr){ + if (ok) { + if (oneDone) oneDone(true, u1); + } else { + if (oneDone) oneDone(false, body); + success = false; + errors += body + '\n'; + }; + delete outstanding[u]; + for (x in outstanding) return; + if (allDone) allDone(success, errors); + }); + }; + requestOne(u); + } + } + return uris.length + } + + + /* Ask for a doc to be loaded if necessary then call back + ** + ** Changed 2013-08-20: Added (ok, body) params to callback + ** + **/ + this.nowOrWhenFetched = function(uri, referringTerm, userCallback) { + // Sanitize URI (remove #fragment) + uri = (uri.indexOf('#') >= 0)?uri.slice(0, uri.indexOf('#')):uri; + var sta = this.getState(uri); + if (sta == 'fetched') return userCallback(true); + + // If it is 'failed', then shoulkd we try again? I think so so an old error doens't get stuck + //if (sta == 'unrequested') + this.requestURI(uri, referringTerm, false, userCallback); + } + + + + // Look up response header + // + // Returns: a list of header values found in a stored HTTP response + // or [] if response was found but no header found + // or undefined if no response is available. + // + this.getHeader = function(doc, header) { + var kb = this.store; + var requests = kb.each(undefined, ns.link("requestedURI"), doc.uri); + for (var r=0; r= 0) { // hash + throw ("requestURI should not be called with fragid: " + docuri); + } + + var pcol = $rdf.uri.protocol(docuri); + if (pcol == 'tel' || pcol == 'mailto' || pcol == 'urn') return null; // No look-up operation on these, but they are not errors + var force = !! force + var kb = this.store + var args = arguments + var docterm = kb.sym(docuri) + if (!force && typeof(this.requested[docuri]) != "undefined") { + return null + } + + this.fireCallbacks('request', args); //Kenny: fire 'request' callbacks here + // dump( "web.js: Requesting uri: " + docuri + "\n" ); + this.requested[docuri] = true + + if (rterm) { + if (rterm.uri) { // A link betwen URIs not terms + kb.add(docterm.uri, ns.link("requestedBy"), rterm.uri, this.appNode) + } + } + + if (rterm) { + // $rdf.log.info('SF.request: ' + docuri + ' refd by ' + rterm.uri) + } + else { + // $rdf.log.info('SF.request: ' + docuri + ' no referring doc') + }; + + + var useJQuery = typeof jQuery != 'undefined'; + if (!useJQuery) { + var xhr = $rdf.Util.XMLHTTPFactory(); + var req = xhr.req = kb.bnode(); + xhr.resource = docterm; + xhr.requestedURI = args[0]; + } else { + var req = kb.bnode(); + } + var requestHandlers = kb.collection(); + var sf = this; + + var now = new Date(); + var timeNow = "[" + now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds() + "] "; + + kb.add(req, ns.rdfs("label"), kb.literal(timeNow + ' Request for ' + docuri), this.appNode) + kb.add(req, ns.link("requestedURI"), kb.literal(docuri), this.appNode) + kb.add(req, ns.link('status'), kb.collection(), this.appNode) + + // This should not be stored in the store, but in the JS data + /* + if (typeof kb.anyStatementMatching(this.appNode, ns.link("protocol"), $rdf.uri.protocol(docuri)) == "undefined") { + // update the status before we break out + this.failFetch(xhr, "Unsupported protocol: "+$rdf.uri.protocol(docuri)) + return xhr + } + */ + + var onerrorFactory = function(xhr) { return function(event) { + if ($rdf.Fetcher.crossSiteProxyTemplate && document && document.location && !xhr.proxyUsed) { // In mashup situation + var hostpart = $rdf.uri.hostpart; + var here = '' + document.location; + var uri = xhr.resource.uri + if (hostpart(here) && hostpart(uri) && hostpart(here) != hostpart(uri)) { + if (xhr.status === 401 || xhr.status === 403 || xhr.status === 404) { + onreadystatechangeFactory(xhr)(); + } else { + newURI = $rdf.Fetcher.crossSiteProxy(uri); + sf.addStatus(xhr.req, "BLOCKED -> Cross-site Proxy to <" + newURI + ">"); + if (xhr.aborted) return; + + var kb = sf.store; + var oldreq = xhr.req; + kb.add(oldreq, ns.http('redirectedTo'), kb.sym(newURI), oldreq); + + + ////////////// Change the request node to a new one: @@@@@@@@@@@@ Duplicate of what will be done by requestURI below + /* var newreq = xhr.req = kb.bnode() // Make NEW reqest for everything else + kb.add(oldreq, ns.http('redirectedRequest'), newreq, xhr.req); + + var now = new Date(); + var timeNow = "[" + now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds() + "] "; + kb.add(newreq, ns.rdfs("label"), kb.literal(timeNow + ' Request for ' + newURI), this.appNode) + kb.add(newreq, ns.link('status'), kb.collection(), this.appNode); + kb.add(newreq, ns.link("requestedURI"), kb.literal(newURI), this.appNode); + + var response = kb.bnode(); + kb.add(oldreq, ns.link('response'), response); + */ + // kb.add(response, ns.http('status'), kb.literal(xhr.status), response); + // if (xhr.statusText) kb.add(response, ns.http('statusText'), kb.literal(xhr.statusText), response) + + xhr.abort() + xhr.aborted = true + + sf.addStatus(oldreq, 'done - redirected') // why + //the callback throws an exception when called from xhr.onerror (so removed) + //sf.fireCallbacks('done', args) // Are these args right? @@@ Noit done yet! done means success + sf.requested[xhr.resource.uri] = 'redirected'; + + var xhr2 = sf.requestURI(newURI, xhr.resource, force, userCallback); + xhr2.proxyUsed = true; //only try the proxy once + + if (xhr2 && xhr2.req) { + kb.add(xhr.req, + kb.sym('http://www.w3.org/2007/ont/link#redirectedRequest'), + xhr2.req, + sf.appNode); + return; + } + } + } + } else { + if (xhr.withCredentials) { + console.log("@@ Retrying with no credentials for " + xhr.resource) + xhr.abort(); + xhr.withCredentials = false; + sf.addStatus(xhr.req, "Credentials SUPPRESSED to see if that helps"); + xhr.send(); // try again + } else { + sf.failFetch(xhr, "XHR Error: "+event); // Alas we get no error message + } + } + }; } + + // Set up callbacks + var onreadystatechangeFactory = function(xhr) { return function() { + var handleResponse = function() { + if (xhr.handleResponseDone) return; + xhr.handleResponseDone = true; + var handler = null; + var thisReq = xhr.req // Might have changes by redirect + sf.fireCallbacks('recv', args) + var kb = sf.store; + sf.saveResponseMetadata(xhr, kb); + sf.fireCallbacks('headers', [{uri: docuri, headers: xhr.headers}]); + + if (xhr.status >= 400) { // For extra dignostics, keep the reply + // @@@ 401 should cause a retry with credential son + // @@@ cache the credentials flag by host ???? + if (xhr.responseText.length > 10) { + var response = kb.bnode(); + kb.add(response, ns.http('content'), kb.literal(xhr.responseText), response); + if (xhr.statusText) { + kb.add(response, ns.http('statusText'), kb.literal(xhr.statusText), response); + } + // dump("HTTP >= 400 responseText:\n"+xhr.responseText+"\n"); // @@@@ + } + sf.failFetch(xhr, "HTTP error for " +xhr.resource + ": "+ xhr.status + ' ' + xhr.statusText); + return; + } + + var loc = xhr.headers['content-location']; + + // deduce some things from the HTTP transaction + var addType = function(cla) { // add type to all redirected resources too + var prev = thisReq; + if (loc) { + var docURI = kb.any(prev, ns.link('requestedURI')); + if (docURI != loc) { + kb.add(kb.sym(loc), ns.rdf('type'), cla, sf.appNode); + } + } + for (;;) { + var doc = kb.any(prev, ns.link('requestedURI')); + if (doc && doc.value) // convert Literal + kb.add(kb.sym(doc.value), ns.rdf('type'), cla, sf.appNode); + prev = kb.any(undefined, kb.sym('http://www.w3.org/2007/ont/link#redirectedRequest'), prev); + if (!prev) break; + var response = kb.any(prev, kb.sym('http://www.w3.org/2007/ont/link#response')); + if (!response) break; + var redirection = kb.any(response, kb.sym('http://www.w3.org/2007/ont/http#status')); + if (!redirection) break; + if (redirection != '301' && redirection != '302') break; + } + } + if (xhr.status == 200) { + addType(ns.link('Document')); + var ct = xhr.headers['content-type']; + if (ct) { + if (ct.indexOf('image/') == 0 || ct.indexOf('application/pdf') == 0) addType(kb.sym('http://purl.org/dc/terms/Image')); + } + } + + if ($rdf.uri.protocol(xhr.resource.uri) == 'file' || $rdf.uri.protocol(xhr.resource.uri) == 'chrome') { + switch (xhr.resource.uri.split('.').pop()) { + case 'rdf': + case 'owl': + xhr.headers['content-type'] = 'application/rdf+xml'; + break; + case 'n3': + case 'nt': + case 'ttl': + xhr.headers['content-type'] = 'text/n3'; + break; + default: + xhr.headers['content-type'] = 'text/xml'; + } + } + + // If we have alread got the thing at this location, abort + if (loc) { + var udoc = $rdf.uri.join(xhr.resource.uri, loc) + if (!force && udoc != xhr.resource.uri && sf.requested[udoc]) { + // should we smush too? + // $rdf.log.info("HTTP headers indicate we have already" + " retrieved " + xhr.resource + " as " + udoc + ". Aborting.") + sf.doneFetch(xhr, args) + xhr.abort() + return + } + sf.requested[udoc] = true + } + + for (var x = 0; x < sf.handlers.length; x++) { + if (xhr.headers['content-type'] && xhr.headers['content-type'].match(sf.handlers[x].pattern)) { + handler = new sf.handlers[x](); + requestHandlers.append(sf.handlers[x].term) // FYI + break + } + } + + var link; + try { + link = xhr.getResponseHeader('link'); + }catch(e){} + if (link) { + var rel = null; + var arg = link.replace(/ /g, '').split(';'); + for (var i = 1; i < arg.length; i++) { + lr = arg[i].split('='); + if (lr[0] == 'rel') rel = lr[1]; + } + var v = arg[0]; + // eg. Link: <.meta>, rel=meta + if (v.length && v[0] == '<' && v[v.length-1] == '>' && v.slice) + v = v.slice(1, -1); + if (rel) // Treat just like HTML link element + sf.linkData(xhr, rel, v); + } + + + if (handler) { + try { + handler.handlerFactory(xhr); + } catch(e) { // Try to avoid silent errors + sf.failFetch(xhr, "Exception handling content-type " + xhr.headers['content-type'] + ' was: '+e); + }; + } else { + sf.doneFetch(xhr, args); // Not a problem, we just don't extract data. + /* + // sf.failFetch(xhr, "Unhandled content type: " + xhr.headers['content-type']+ + // ", readyState = "+xhr.readyState); + */ + return; + } + }; + + // DONE: 4 + // HEADERS_RECEIVED: 2 + // LOADING: 3 + // OPENED: 1 + // UNSENT: 0 + + // $rdf.log.debug("web.js: XHR " + xhr.resource.uri + ' readyState='+xhr.readyState); // @@@@ comment me out + + switch (xhr.readyState) { + case 0: + var uri = xhr.resource.uri, newURI; + if (this.crossSiteProxyTemplate && document && document.location) { // In mashup situation + var hostpart = $rdf.uri.hostpart; + var here = '' + document.location; + if (hostpart(here) && hostpart(uri) && hostpart(here) != hostpart(uri)) { + newURI = this.crossSiteProxyTemplate.replace('{uri}', encodeURIComponent(uri)); + sf.addStatus(xhr.req, "BLOCKED -> Cross-site Proxy to <" + newURI + ">"); + if (xhr.aborted) return; + + var kb = sf.store; + var oldreq = xhr.req; + kb.add(oldreq, ns.http('redirectedTo'), kb.sym(newURI), oldreq); + + + ////////////// Change the request node to a new one: @@@@@@@@@@@@ Duplicate? + var newreq = xhr.req = kb.bnode() // Make NEW reqest for everything else + kb.add(oldreq, ns.http('redirectedRequest'), newreq, xhr.req); + + var now = new Date(); + var timeNow = "[" + now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds() + "] "; + kb.add(newreq, ns.rdfs("label"), kb.literal(timeNow + ' Request for ' + newURI), this.appNode) + kb.add(newreq, ns.link('status'), kb.collection(), this.appNode); + kb.add(newreq, ns.link("requestedURI"), kb.literal(newURI), this.appNode); + + var response = kb.bnode(); + kb.add(oldreq, ns.link('response'), response); + // kb.add(response, ns.http('status'), kb.literal(xhr.status), response); + // if (xhr.statusText) kb.add(response, ns.http('statusText'), kb.literal(xhr.statusText), response) + + xhr.abort() + xhr.aborted = true + + sf.addStatus(oldreq, 'done') // why + if (xhr.userCallback) { + xhr.userCallback(true); + }; + sf.fireCallbacks('done', args) // Are these args right? @@@ + sf.requested[xhr.resource.uri] = 'redirected'; + + var xhr2 = sf.requestURI(newURI, xhr.resource); + if (xhr2 && xhr2.req) kb.add(xhr.req, + kb.sym('http://www.w3.org/2007/ont/link#redirectedRequest'), + xhr2.req, sf.appNode); return; + } + } + sf.failFetch(xhr, "HTTP Blocked. (ReadyState 0) Cross-site violation for <"+ + docuri+">"); + + break; + + case 3: + // Intermediate state -- 3 may OR MAY NOT be called, selon browser. + // handleResponse(); // In general it you can't do it yet as the headers are in but not the data + break + case 4: + // Final state + handleResponse(); + // Now handle + if (xhr.handle) { + if (sf.requested[xhr.resource.uri] === 'redirected') { + break; + } + sf.fireCallbacks('load', args) + xhr.handle(function() { + sf.doneFetch(xhr, args) + }) + } else { + sf.addStatus(xhr.req, "Fetch OK. No known semantics."); + sf.doneFetch(xhr, args); + //sf.failFetch(xhr, "HTTP failed unusually. (no handler set) (x-site violation? no net?) for <"+ + // docuri+">"); + } + break + } // switch + }; } + + + // Map the URI to a localhost proxy if we are running on localhost + // This is used for working offline, e.g. on planes. + // Is the script istelf is running in localhost, then access all data in a localhost mirror. + // Do not remove without checking with TimBL :) + var uri2 = docuri; + if (typeof tabulator != 'undefined' && tabulator.preferences.get('offlineModeUsingLocalhost')) { + if (uri2.slice(0,7) == 'http://' && uri2.slice(7,17) != 'localhost/') { + uri2 = 'http://localhost/' + uri2.slice(7); + $rdf.log.warn("Localhost kludge for offline use: actually getting <" + uri2 + ">"); + } else { + // $rdf.log.warn("Localhost kludge NOT USED <" + uri2 + ">"); + }; + } else { + // $rdf.log.warn("Localhost kludge OFF offline use: actually getting <" + uri2 + ">"); + } + // 2014 probelm: + // XMLHttpRequest cannot load http://www.w3.org/People/Berners-Lee/card. + // A wildcard '*' cannot be used in the 'Access-Control-Allow-Origin' header when the credentials flag is true. + + // @ Many ontology files under http: and need CORS wildcard -> can't have withCredentials + var withCredentials = ( uri2.slice(0,6) === 'https:'); // @@ Kludge -- need for webid which typically is served from https + + var actualProxyURI = this.proxyIfNecessary(uri2); + // Setup the request + if (typeof jQuery !== 'undefined' && jQuery.ajax) { + var xhr = jQuery.ajax({ + url: actualProxyURI, + accepts: {'*': 'text/turtle,text/n3,application/rdf+xml'}, + processData: false, + xhrFields: { + withCredentials: withCredentials + }, + timeout: sf.timeout, + error: function(xhr, s, e) { + + xhr.req = req; // Add these in case fails before .ajax returns + xhr.userCallback = userCallback; + xhr.resource = docterm; + xhr.requestedURI = uri2; + xhr.withCredentials = withCredentials; // Somehow gets lost by jq + + + if (s == 'timeout') + sf.failFetch(xhr, "requestTimeout"); + else + onerrorFactory(xhr)(e); + }, + success: function(d, s, xhr) { + + xhr.req = req; + xhr.userCallback = userCallback; + xhr.resource = docterm; + xhr.requestedURI = uri2; + + onreadystatechangeFactory(xhr)(); + } + }); + + xhr.req = req; + xhr.userCallback = userCallback; + xhr.resource = docterm; + xhr.requestedURI = uri2; + xhr.actualProxyURI = actualProxyURI; + + + } else { + var xhr = $rdf.Util.XMLHTTPFactory(); + xhr.onerror = onerrorFactory(xhr); + xhr.onreadystatechange = onreadystatechangeFactory(xhr); + xhr.timeout = sf.timeout; + xhr.withCredentials = withCredentials; + xhr.actualProxyURI = actualProxyURI; + + xhr.req = req; + xhr.userCallback = userCallback; + xhr.resource = docterm; + xhr.requestedURI = uri2; + + xhr.ontimeout = function () { + sf.failFetch(xhr, "requestTimeout"); + } + try { + xhr.open('GET', actualProxyURI, this.async); + } catch (er) { + return this.failFetch(xhr, "XHR open for GET failed for <"+uri2+">:\n\t" + er); + } + } + + // Set redirect callback and request headers -- alas Firefox Extension Only + + if (typeof tabulator != 'undefined' && tabulator.isExtension && xhr.channel && + ($rdf.uri.protocol(xhr.resource.uri) == 'http' || + $rdf.uri.protocol(xhr.resource.uri) == 'https')) { + try { + xhr.channel.notificationCallbacks = { + getInterface: function(iid) { + if (iid.equals(Components.interfaces.nsIChannelEventSink)) { + return { + + onChannelRedirect: function(oldC, newC, flags) { + if (xhr.aborted) return; + var kb = sf.store; + var newURI = newC.URI.spec; + var oldreq = xhr.req; + sf.addStatus(xhr.req, "Redirected: " + xhr.status + " to <" + newURI + ">"); + kb.add(oldreq, ns.http('redirectedTo'), kb.sym(newURI), xhr.req); + + + + ////////////// Change the request node to a new one: @@@@@@@@@@@@ Duplicate? + var newreq = xhr.req = kb.bnode() // Make NEW reqest for everything else + // xhr.resource = docterm + // xhr.requestedURI = args[0] + // var requestHandlers = kb.collection() + + // kb.add(kb.sym(newURI), ns.link("request"), req, this.appNode) + kb.add(oldreq, ns.http('redirectedRequest'), newreq, this.appNode); + + var now = new Date(); + var timeNow = "[" + now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds() + "] "; + kb.add(newreq, ns.rdfs("label"), kb.literal(timeNow + ' Request for ' + newURI), this.appNode) + kb.add(newreq, ns.link('status'), kb.collection(), this.appNode) + kb.add(newreq, ns.link("requestedURI"), kb.literal(newURI), this.appNode) + /////////////// + + + //// $rdf.log.info('@@ sources onChannelRedirect'+ + // "Redirected: "+ + // xhr.status + " to <" + newURI + ">"); //@@ + var response = kb.bnode(); + // kb.add(response, ns.http('location'), newURI, response); Not on this response + kb.add(oldreq, ns.link('response'), response); + kb.add(response, ns.http('status'), kb.literal(xhr.status), response); + if (xhr.statusText) kb.add(response, ns.http('statusText'), kb.literal(xhr.statusText), response) + + if (xhr.status - 0 != 303) kb.HTTPRedirects[xhr.resource.uri] = newURI; // same document as + if (xhr.status - 0 == 301 && rterm) { // 301 Moved + var badDoc = $rdf.uri.docpart(rterm.uri); + var msg = 'Warning: ' + xhr.resource + ' has moved to <' + newURI + '>.'; + if (rterm) { + msg += ' Link in <' + badDoc + ' >should be changed'; + kb.add(badDoc, kb.sym('http://www.w3.org/2007/ont/link#warning'), msg, sf.appNode); + } + // dump(msg+"\n"); + } + xhr.abort() + xhr.aborted = true + + sf.addStatus(oldreq, 'done') // why + sf.fireCallbacks('done', args) // Are these args right? @@@ + sf.requested[xhr.resource.uri] = 'redirected'; + + var hash = newURI.indexOf('#'); + if (hash >= 0) { + var msg = ('Warning: ' + xhr.resource + ' HTTP redirects to' + newURI + ' which should not contain a "#" sign'); + // dump(msg+"\n"); + kb.add(xhr.resource, kb.sym('http://www.w3.org/2007/ont/link#warning'), msg) + newURI = newURI.slice(0, hash); + } + var xhr2 = sf.requestURI(newURI, xhr.resource); + if (xhr2 && xhr2.req) kb.add(xhr.req, + kb.sym('http://www.w3.org/2007/ont/link#redirectedRequest'), + xhr2.req, sf.appNode); + + // else dump("No xhr.req available for redirect from "+xhr.resource+" to "+newURI+"\n") + }, + + // See https://developer.mozilla.org/en/XPCOM_Interface_Reference/nsIChannelEventSink + asyncOnChannelRedirect: function(oldC, newC, flags, callback) { + if (xhr.aborted) return; + var kb = sf.store; + var newURI = newC.URI.spec; + var oldreq = xhr.req; + sf.addStatus(xhr.req, "Redirected: " + xhr.status + " to <" + newURI + ">"); + kb.add(oldreq, ns.http('redirectedTo'), kb.sym(newURI), xhr.req); + + + + ////////////// Change the request node to a new one: @@@@@@@@@@@@ Duplicate? + var newreq = xhr.req = kb.bnode() // Make NEW reqest for everything else + // xhr.resource = docterm + // xhr.requestedURI = args[0] + // var requestHandlers = kb.collection() + + // kb.add(kb.sym(newURI), ns.link("request"), req, this.appNode) + kb.add(oldreq, ns.http('redirectedRequest'), newreq, xhr.req); + + var now = new Date(); + var timeNow = "[" + now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds() + "] "; + kb.add(newreq, ns.rdfs("label"), kb.literal(timeNow + ' Request for ' + newURI), this.appNode) + kb.add(newreq, ns.link('status'), kb.collection(), this.appNode) + kb.add(newreq, ns.link("requestedURI"), kb.literal(newURI), this.appNode) + /////////////// + + + //// $rdf.log.info('@@ sources onChannelRedirect'+ + // "Redirected: "+ + // xhr.status + " to <" + newURI + ">"); //@@ + var response = kb.bnode(); + // kb.add(response, ns.http('location'), newURI, response); Not on this response + kb.add(oldreq, ns.link('response'), response); + kb.add(response, ns.http('status'), kb.literal(xhr.status), response); + if (xhr.statusText) kb.add(response, ns.http('statusText'), kb.literal(xhr.statusText), response) + + if (xhr.status - 0 != 303) kb.HTTPRedirects[xhr.resource.uri] = newURI; // same document as + if (xhr.status - 0 == 301 && rterm) { // 301 Moved + var badDoc = $rdf.uri.docpart(rterm.uri); + var msg = 'Warning: ' + xhr.resource + ' has moved to <' + newURI + '>.'; + if (rterm) { + msg += ' Link in <' + badDoc + ' >should be changed'; + kb.add(badDoc, kb.sym('http://www.w3.org/2007/ont/link#warning'), msg, sf.appNode); + } + // dump(msg+"\n"); + } + xhr.abort() + xhr.aborted = true + + + sf.addStatus(oldreq, 'done') // why + + if (xhr.userCallback) { + xhr.userCallback(true); + }; + sf.fireCallbacks('done', args) // Are these args right? @@@ + sf.requested[xhr.resource.uri] = 'redirected'; + + var hash = newURI.indexOf('#'); + if (hash >= 0) { + var msg = ('Warning: ' + xhr.resource + ' HTTP redirects to' + newURI + ' which should not contain a "#" sign'); + // dump(msg+"\n"); + kb.add(xhr.resource, kb.sym('http://www.w3.org/2007/ont/link#warning'), msg) + newURI = newURI.slice(0, hash); + } + var xhr2 = sf.requestURI(newURI, xhr.resource); + if (xhr2 && xhr2.req) kb.add(xhr.req, + kb.sym('http://www.w3.org/2007/ont/link#redirectedRequest'), + xhr2.req, sf.appNode); + + // else dump("No xhr.req available for redirect from "+xhr.resource+" to "+newURI+"\n") + } // asyncOnChannelRedirect + } + } + return Components.results.NS_NOINTERFACE + } + } + } catch (err) { + return sf.failFetch(xhr, + "@@ Couldn't set callback for redirects: " + err); + } + + } + + try { + var acceptstring = "" + for (var type in this.mediatypes) { + var attrstring = "" + if (acceptstring != "") { + acceptstring += ", " + } + acceptstring += type + for (var attr in this.mediatypes[type]) { + acceptstring += ';' + attr + '=' + this.mediatypes[type][attr] + } + } + xhr.setRequestHeader('Accept', acceptstring) + // $rdf.log.info('Accept: ' + acceptstring) + + // See http://dig.csail.mit.edu/issues/tabulator/issue65 + //if (requester) { xhr.setRequestHeader('Referer',requester) } + } catch (err) { + throw ("Can't set Accept header: " + err) + } + + // Fire + + if (!useJQuery) { + try { + xhr.send(null) + } catch (er) { + return this.failFetch(xhr, "XHR send failed:" + er); + } + setTimeout(function() { + if (xhr.readyState != 4 && sf.isPending(xhr.resource.uri)) { + sf.failFetch(xhr, "requestTimeout") + } + }, this.timeout); + this.addStatus(xhr.req, "HTTP Request sent."); + + } else { + this.addStatus(xhr.req, "HTTP Request sent (using jQuery)"); + } + + return xhr + } + +// this.requested[docuri]) != "undefined" + + this.objectRefresh = function(term) { + var uris = kb.uris(term) // Get all URIs + if (typeof uris != 'undefined') { + for (var i = 0; i < uris.length; i++) { + this.refresh(this.store.sym($rdf.uri.docpart(uris[i]))); + //what about rterm? + } + } + } + + this.unload = function(term) { + this.store.removeMany(undefined, undefined, undefined, term) + delete this.requested[term.uri]; // So it can be loaded again + } + + this.refresh = function(term) { // sources_refresh + this.unload(term); + this.fireCallbacks('refresh', arguments) + this.requestURI(term.uri, undefined, true) + } + + this.retract = function(term) { // sources_retract + this.store.removeMany(undefined, undefined, undefined, term) + if (term.uri) { + delete this.requested[$rdf.uri.docpart(term.uri)] + } + this.fireCallbacks('retract', arguments) + } + + this.getState = function(docuri) { // docState + if (typeof this.requested[docuri] != "undefined") { + if (this.requested[docuri]) { + if (this.isPending(docuri)) { + return "requested" + } else { + return "fetched" + } + } else { + return "failed" + } + } else { + return "unrequested" + } + } + + //doing anyStatementMatching is wasting time + this.isPending = function(docuri) { // sources_pending + //if it's not pending: false -> flailed 'done' -> done 'redirected' -> redirected + return this.requested[docuri] == true; + } + + var updatesVia = new $rdf.UpdatesVia(this); +}; + +$rdf.fetcher = function(store, timeout, async) { return new $rdf.Fetcher(store, timeout, async) }; + +// Parse a string and put the result into the graph kb +$rdf.parse = function parse(str, kb, base, contentType) { + try { + /* + parseXML = function(str) { + var dparser; + if ((typeof tabulator != 'undefined' && tabulator.isExtension)) { + dparser = Components.classes["@mozilla.org/xmlextras/domparser;1"].getService( + Components.interfaces.nsIDOMParser); + } else if (typeof module != 'undefined' ){ // Node.js + var jsdom = require('jsdom'); + return jsdom.jsdom(str, undefined, {} );// html, level, options + } else { + dparser = new DOMParser() + } + return dparser.parseFromString(str, 'application/xml'); + } + */ + if (contentType == 'text/n3' || contentType == 'text/turtle') { + var p = $rdf.N3Parser(kb, kb, base, base, null, null, "", null) + p.loadBuf(str) + return; + } + + if (contentType == 'application/rdf+xml') { + var parser = new $rdf.RDFParser(kb); + parser.parse($rdf.Util.parseXML(str), base, kb.sym(base)); + return; + } + + if (contentType == 'application/rdfa') { // @@ not really a valid mime type + if ($rdf.rdfa && $rdf.rdfa.parse) + $rdf.rdfa.parse($rdf.Util.parseXML(str), kb, base); + return; + } + + if (contentType == 'application/sparql-update') { // @@ we handle a subset + spaqlUpdateParser(store, str, base) + + if ($rdf.rdfa && $rdf.rdfa.parse) + $rdf.rdfa.parse($rdf.Util.parseXML(str), kb, base); + return; + } + + + } catch(e) { + throw "Error trying to parse <"+base+"> as "+contentType+":\n"+e +':\n'+e.stack; + } + throw "Don't know how to parse "+contentType+" yet"; + +}; + +// Serialize to the appropriate format +// +$rdf.serialize = function(target, kb, base, contentType, callback) { + var documentString; + var sz = $rdf.Serializer(kb); + var newSts = kb.statementsMatching(undefined, undefined, undefined, target); + sz.suggestNamespaces(kb.namespaces); + sz.setBase(base); + switch(contentType){ + case 'application/rdf+xml': + documentString = sz.statementsToXML(newSts); + break; + case 'text/n3': + case 'text/turtle': + case 'application/x-turtle': // Legacy + case 'application/n3': // Legacy + documentString = sz.statementsToN3(newSts); + break; + case 'application/json+ld': + var n3String = sz.statementsToN3(newSts); + convertToJson(n3String, callback); + break; + case 'application/n-quads': + case 'application/nquads': // @@@ just outpout the quads? Does not work for collections + var n3String = sz.statementsToN3(newSts); + documentString = convertToNQuads(n3String, callback); + break; + default: + throw "serialise: Content-type "+content_type +" not supported for data write"; + } + return documentString; +}; + +////////////////// JSON-LD code currently requires Node +if (typeof module !== 'undefined' && module.require) { // Node + var asyncLib = require('async'); + var jsonld = require('jsonld'); + var N3 = require('n3'); + + var convertToJson = function(n3String, jsonCallback) { + var jsonString = undefined; + var n3Parser = N3.Parser(); + var n3Writer = N3.Writer({ + format: 'N-Quads' + }); + asyncLib.waterfall([ + function(callback) { + n3Parser.parse(n3String, callback); + }, + function(triple, prefix, callback) { + if (triple !== null) { + n3Writer.addTriple(triple); + } + if (typeof callback === 'function') { + n3Writer.end(callback); + } + }, + function(result, callback) { + try { + jsonld.fromRDF(result, { + format: 'application/nquads' + }, callback); + } catch (err) { + callback(err); + } + }, + function(json, callback) { + jsonString = JSON.stringify(json); + jsonCallback(null, jsonString); + } + ], function(err, result) { + jsonCallback(err, jsonString); + }); + } + + var convertToNQuads = function(n3String, nquadCallback) { + var nquadString = undefined; + var n3Parser = N3.Parser(); + var n3Writer = N3.Writer({ + format: 'N-Quads' + }); + asyncLib.waterfall([ + function(callback) { + n3Parser.parse(n3String, callback); + }, + function(triple, prefix, callback) { + if (triple !== null) { + n3Writer.addTriple(triple); + } + if (typeof callback === 'function') { + n3Writer.end(callback); + } + }, + function(result, callback) { + nquadString = result; + nquadCallback(null, nquadString); + }, + ], function(err, result) { + nquadCallback(err, nquadString); + }); + } + +} +// ends + +// Handle node, amd, and global systems +if (typeof exports !== 'undefined') { + if (typeof module !== 'undefined' && module.exports) { + exports = module.exports = $rdf; + } + exports.$rdf = $rdf; +} +else { + if (typeof define === 'function' && define.amd) { + define([], function() { + return $rdf; + }); + } + + // Leak a global regardless of module system + root['$rdf'] = $rdf; +} +})(this); diff --git a/ontologyTest.html b/ontologyTest.html new file mode 100644 index 0000000..1bc415c --- /dev/null +++ b/ontologyTest.html @@ -0,0 +1,747 @@ + + + + + + + + + +
+ + +
+ +
+
+
+
+
+ + + \ No newline at end of file