term.js (10168B)
1 // These are the classes corresponding to the RDF and N3 data models 2 // 3 // Designed to look like rdflib and cwm designs. 4 // 5 // Issues: Should the names start with RDF to make them 6 // unique as program-wide symbols? 7 // 8 // W3C open source licence 2005. 9 // 10 // Symbol 11 $rdf.Empty = function () { 12 return this; 13 }; 14 15 $rdf.Empty.prototype.termType = 'empty'; 16 $rdf.Empty.prototype.toString = function () { 17 return "()" 18 }; 19 $rdf.Empty.prototype.toNT = $rdf.Empty.prototype.toString; 20 21 $rdf.Symbol = function (uri) { 22 this.uri = uri; 23 this.value = uri; // -- why? -tim 24 return this; 25 } 26 27 $rdf.Symbol.prototype.termType = 'symbol'; 28 $rdf.Symbol.prototype.toString = function () { 29 return("<" + this.uri + ">"); 30 }; 31 $rdf.Symbol.prototype.toNT = $rdf.Symbol.prototype.toString; 32 33 // Some precalculated symbols 34 $rdf.Symbol.prototype.XSDboolean = new $rdf.Symbol('http://www.w3.org/2001/XMLSchema#boolean'); 35 $rdf.Symbol.prototype.XSDdecimal = new $rdf.Symbol('http://www.w3.org/2001/XMLSchema#decimal'); 36 $rdf.Symbol.prototype.XSDfloat = new $rdf.Symbol('http://www.w3.org/2001/XMLSchema#float'); 37 $rdf.Symbol.prototype.XSDinteger = new $rdf.Symbol('http://www.w3.org/2001/XMLSchema#integer'); 38 $rdf.Symbol.prototype.XSDdateTime = new $rdf.Symbol('http://www.w3.org/2001/XMLSchema#dateTime'); 39 $rdf.Symbol.prototype.integer = new $rdf.Symbol('http://www.w3.org/2001/XMLSchema#integer'); // Used? 40 // Blank Node 41 if(typeof $rdf.NextId != 'undefined') { 42 $rdf.log.error('Attempt to re-zero existing blank node id counter at ' + $rdf.NextId); 43 } else { 44 $rdf.NextId = 0; // Global genid 45 } 46 $rdf.NTAnonymousNodePrefix = "_:n"; 47 48 $rdf.BlankNode = function (id) { 49 /*if (id) 50 this.id = id; 51 else*/ 52 this.id = $rdf.NextId++; 53 this.value = id ? id : this.id.toString(); 54 return this 55 }; 56 57 $rdf.BlankNode.prototype.termType = 'bnode'; 58 $rdf.BlankNode.prototype.toNT = function () { 59 return $rdf.NTAnonymousNodePrefix + this.id 60 }; 61 $rdf.BlankNode.prototype.toString = $rdf.BlankNode.prototype.toNT; 62 63 // Literal 64 $rdf.Literal = function (value, lang, datatype) { 65 this.value = value 66 if(lang == "" || lang == null) this.lang = undefined; 67 else this.lang = lang; // string 68 if(datatype == null) this.datatype = undefined; 69 else this.datatype = datatype; // term 70 return this; 71 } 72 73 $rdf.Literal.prototype.termType = 'literal' 74 $rdf.Literal.prototype.toString = function () { 75 return '' + this.value; 76 }; 77 $rdf.Literal.prototype.toNT = function () { 78 var str = this.value 79 if(typeof str != 'string') { 80 if(typeof str == 'number') return '' + str; 81 throw Error("Value of RDF literal is not string: " + str) 82 } 83 str = str.replace(/\\/g, '\\\\'); // escape backslashes 84 str = str.replace(/\"/g, '\\"'); // escape quotes 85 str = str.replace(/\n/g, '\\n'); // escape newlines 86 str = '"' + str + '"' //'; 87 if(this.datatype) { 88 str = str + '^^' + this.datatype.toNT() 89 } 90 if(this.lang) { 91 str = str + "@" + this.lang; 92 } 93 return str; 94 }; 95 96 $rdf.Collection = function () { 97 this.id = $rdf.NextId++; // Why need an id? For hashstring. 98 this.elements = []; 99 this.closed = false; 100 }; 101 102 $rdf.Collection.prototype.termType = 'collection'; 103 104 $rdf.Collection.prototype.toNT = function () { 105 return $rdf.NTAnonymousNodePrefix + this.id 106 }; 107 108 $rdf.Collection.prototype.toString = function () { 109 var str = '('; 110 for(var i = 0; i < this.elements.length; i++) 111 str += this.elements[i] + ' '; 112 return str + ')'; 113 }; 114 115 $rdf.Collection.prototype.append = function (el) { 116 this.elements.push(el) 117 } 118 $rdf.Collection.prototype.unshift = function (el) { 119 this.elements.unshift(el); 120 } 121 $rdf.Collection.prototype.shift = function () { 122 return this.elements.shift(); 123 } 124 125 $rdf.Collection.prototype.close = function () { 126 this.closed = true 127 } 128 129 130 // Convert Javascript representation to RDF term object 131 // 132 $rdf.term = function (val) { 133 if(typeof val == 'object') 134 if(val instanceof Date) { 135 var d2 = function (x) { 136 return('' + (100 + x)).slice(1, 3) 137 }; // format as just two digits 138 return new $rdf.Literal('' + val.getUTCFullYear() + '-' + d2(val.getUTCMonth() + 1) 139 + '-' + d2(val.getUTCDate()) + 'T' + d2(val.getUTCHours()) + ':' 140 + d2(val.getUTCMinutes()) + ':' + d2(val.getUTCSeconds()) + 'Z', 141 undefined, 142 $rdf.Symbol.prototype.XSDdateTime); 143 144 } else if(val instanceof Array) { 145 var x = new $rdf.Collection(); 146 for(var i = 0; i < val.length; i++) 147 x.append($rdf.term(val[i])); 148 return x; 149 } else 150 return val; 151 if(typeof val == 'string') 152 return new $rdf.Literal(val); 153 if(typeof val == 'number') { 154 var dt; 155 if(('' + val).indexOf('e') >= 0) dt = $rdf.Symbol.prototype.XSDfloat; 156 else if(('' + val).indexOf('.') >= 0) dt = $rdf.Symbol.prototype.XSDdecimal; 157 else dt = $rdf.Symbol.prototype.XSDinteger; 158 return new $rdf.Literal(val, undefined, dt); 159 } 160 if(typeof val == 'boolean') 161 return new $rdf.Literal(val ? "1" : "0", undefined, $rdf.Symbol.prototype.XSDboolean); 162 if(typeof val == 'undefined') 163 return undefined; 164 throw("Can't make term from " + val + " of type " + typeof val); 165 } 166 167 // Statement 168 // 169 // This is a triple with an optional reason. 170 // 171 // The reason can point to provenece or inference 172 // 173 $rdf.Statement = function (subject, predicate, object, why) { 174 this.subject = $rdf.term(subject) 175 this.predicate = $rdf.term(predicate) 176 this.object = $rdf.term(object) 177 if(typeof why != 'undefined') { 178 this.why = why; 179 } 180 return this; 181 } 182 183 $rdf.st = function (subject, predicate, object, why) { 184 return new $rdf.Statement(subject, predicate, object, why); 185 }; 186 187 $rdf.Statement.prototype.toNT = function () { 188 return (this.subject.toNT() + " " + this.predicate.toNT() + " " + this.object.toNT() + " ."); 189 }; 190 191 $rdf.Statement.prototype.toString = $rdf.Statement.prototype.toNT; 192 193 // Formula 194 // 195 // Set of statements. 196 $rdf.Formula = function () { 197 this.statements = [] 198 this.constraints = [] 199 this.initBindings = [] 200 this.optional = [] 201 return this; 202 }; 203 204 205 $rdf.Formula.prototype.termType = 'formula'; 206 $rdf.Formula.prototype.toNT = function () { 207 return "{" + this.statements.join('\n') + "}" 208 }; 209 $rdf.Formula.prototype.toString = $rdf.Formula.prototype.toNT; 210 211 $rdf.Formula.prototype.add = function (subj, pred, obj, why) { 212 this.statements.push(new $rdf.Statement(subj, pred, obj, why)) 213 } 214 215 // Convenience methods on a formula allow the creation of new RDF terms: 216 $rdf.Formula.prototype.sym = function (uri, name) { 217 if(name != null) { 218 throw "This feature (kb.sym with 2 args) is removed. Do not assume prefix mappings." 219 if(!$rdf.ns[uri]) throw 'The prefix "' + uri + '" is not set in the API'; 220 uri = $rdf.ns[uri] + name 221 } 222 return new $rdf.Symbol(uri) 223 } 224 225 $rdf.sym = function (uri) { 226 return new $rdf.Symbol(uri); 227 }; 228 229 $rdf.Formula.prototype.literal = function (val, lang, dt) { 230 return new $rdf.Literal(val.toString(), lang, dt) 231 } 232 $rdf.lit = $rdf.Formula.prototype.literal; 233 234 $rdf.Formula.prototype.bnode = function (id) { 235 return new $rdf.BlankNode(id) 236 } 237 238 $rdf.Formula.prototype.formula = function () { 239 return new $rdf.Formula() 240 } 241 242 $rdf.Formula.prototype.collection = function () { // obsolete 243 return new $rdf.Collection() 244 } 245 246 $rdf.Formula.prototype.list = function (values) { 247 var li = new $rdf.Collection(); 248 if(values) { 249 for(var i = 0; i < values.length; i++) { 250 li.append(values[i]); 251 } 252 } 253 return li; 254 } 255 256 /* Variable 257 ** 258 ** Variables are placeholders used in patterns to be matched. 259 ** In cwm they are symbols which are the formula's list of quantified variables. 260 ** In sparl they are not visibily URIs. Here we compromise, by having 261 ** a common special base URI for variables. Their names are uris, 262 ** but the ? nottaion has an implicit base uri of 'varid:' 263 */ 264 265 $rdf.Variable = function (rel) { 266 this.base = "varid:"; // We deem variabe x to be the symbol varid:x 267 this.uri = $rdf.Util.uri.join(rel, this.base); 268 return this; 269 } 270 271 $rdf.Variable.prototype.termType = 'variable'; 272 $rdf.Variable.prototype.toNT = function () { 273 if(this.uri.slice(0, this.base.length) == this.base) { 274 return '?' + this.uri.slice(this.base.length); 275 } // @@ poor man's refTo 276 return '?' + this.uri; 277 }; 278 279 $rdf.Variable.prototype.toString = $rdf.Variable.prototype.toNT; 280 $rdf.Variable.prototype.classOrder = 7; 281 282 $rdf.variable = $rdf.Formula.prototype.variable = function (name) { 283 return new $rdf.Variable(name); 284 }; 285 286 $rdf.Variable.prototype.hashString = $rdf.Variable.prototype.toNT; 287 288 289 // The namespace function generator 290 $rdf.Namespace = function (nsuri) { 291 return function (ln) { 292 return new $rdf.Symbol(nsuri + (ln === undefined ? '' : ln)) 293 } 294 } 295 296 $rdf.Formula.prototype.ns = function (nsuri) { 297 return function (ln) { 298 return new $rdf.Symbol(nsuri + (ln === undefined ? '' : ln)) 299 } 300 } 301 302 303 // Parse a single token 304 // 305 // The bnode bit should not be used on program-external values; designed 306 // for internal work such as storing a bnode id in an HTML attribute. 307 // This will only parse the strings generated by the vaious toNT() methods. 308 $rdf.Formula.prototype.fromNT = function (str) { 309 var len = str.length 310 var ch = str.slice(0, 1) 311 if(ch == '<') return $rdf.sym(str.slice(1, len - 1)) 312 if(ch == '"') { 313 var lang = undefined; 314 var dt = undefined; 315 var k = str.lastIndexOf('"'); 316 if(k < len - 1) { 317 if(str[k + 1] == '@') lang = str.slice(k + 2, len); 318 else if(str.slice(k + 1, k + 3) == '^^') dt = $rdf.fromNT(str.slice(k + 3, len)); 319 else throw "Can't convert string from NT: " + str 320 } 321 var str = (str.slice(1, k)); 322 str = str.replace(/\\"/g, '"'); // unescape quotes ' 323 str = str.replace(/\\n/g, '\n'); // unescape newlines 324 str = str.replace(/\\\\/g, '\\'); // unescape backslashes 325 return $rdf.lit(str, lang, dt); 326 } 327 if(ch == '_') { 328 var x = new $rdf.BlankNode(); 329 x.id = parseInt(str.slice(3)); 330 $rdf.NextId-- 331 return x 332 } 333 if(ch == '?') { 334 var x = new $rdf.Variable(str.slice(1)); 335 return x; 336 } 337 throw "Can't convert from NT: " + str; 338 339 } 340 $rdf.fromNT = $rdf.Formula.prototype.fromNT; // Not for inexpert user 341 // Convenience - and more conventional name: 342 $rdf.graph = function () { 343 return new $rdf.IndexedFormula(); 344 }; 345 346 // ends