@lblod/graph-rdfa-processor 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,518 @@
1
+ import Node from "./node";
2
+
3
+ export class RDFaGraph {
4
+ constructor() {
5
+ var dataContext = this;
6
+ this.curieParser = {
7
+ trim: function(str) {
8
+ return str.replace(/^\s\s*/, "").replace(/\s\s*$/, "");
9
+ },
10
+ parse: function(value, resolve) {
11
+ value = this.trim(value);
12
+ if (value.charAt(0) == "[" && value.charAt(value.length - 1) == "]") {
13
+ value = value.substring(1, value.length - 1);
14
+ }
15
+ var colon = value.indexOf(":");
16
+ if (colon >= 0) {
17
+ var prefix = value.substring(0, colon);
18
+ if (prefix == "") {
19
+ // default prefix
20
+ var uri = dataContext.prefixes[""];
21
+ return uri ? uri + value.substring(colon + 1) : null;
22
+ } else if (prefix == "_") {
23
+ // blank node
24
+ return "_:" + value.substring(colon + 1);
25
+ } else if (DocumentData.NCNAME.test(prefix)) {
26
+ var uri = dataContext.prefixes[prefix];
27
+ if (uri) {
28
+ return uri + value.substring(colon + 1);
29
+ }
30
+ }
31
+ }
32
+
33
+ return resolve ? dataContext.baseURI.resolve(value) : value;
34
+ },
35
+ };
36
+ this.base = null;
37
+ this.toString = function(requestOptions) {
38
+ var options =
39
+ requestOptions && requestOptions.shorten
40
+ ? { graph: this, shorten: true, prefixesUsed: {} }
41
+ : null;
42
+ if (requestOptions && requestOptions.blankNodePrefix) {
43
+ options.filterBlankNode = function(id) {
44
+ return "_:" + requestOptions.blankNodePrefix + id.substring(2);
45
+ };
46
+ }
47
+ if (requestOptions && requestOptions.numericalBlankNodePrefix) {
48
+ var onlyNumbers = /^[0-9]+$/;
49
+ options.filterBlankNode = function(id) {
50
+ var label = id.substring(2);
51
+ return onlyNumbers.test(label)
52
+ ? "_:" + requestOptions.numericalBlankNodePrefix + label
53
+ : id;
54
+ };
55
+ }
56
+ var s = "";
57
+ for (var subject in this.subjects) {
58
+ var snode = this.subjects[subject];
59
+ s += snode.toString(options);
60
+ s += "\n";
61
+ }
62
+ var prolog =
63
+ requestOptions && requestOptions.baseURI
64
+ ? "@base <" + baseURI + "> .\n"
65
+ : "";
66
+ if (options && options.shorten) {
67
+ for (var prefix in options.prefixesUsed) {
68
+ prolog +=
69
+ "@prefix " + prefix + ": <" + this.prefixes[prefix] + "> .\n";
70
+ }
71
+ }
72
+ return prolog.length == 0 ? s : prolog + "\n" + s;
73
+ };
74
+ this.blankNodeCounter = 0;
75
+ this.clear = function() {
76
+ this.subjects = {};
77
+ this.prefixes = {};
78
+ this.terms = {};
79
+ this.blankNodeCounter = 0;
80
+ };
81
+ this.clear();
82
+ this.prefixes[""] = "http://www.w3.org/1999/xhtml/vocab#";
83
+
84
+ // w3c
85
+ this.prefixes["grddl"] = "http://www.w3.org/2003/g/data-view#";
86
+ this.prefixes["ma"] = "http://www.w3.org/ns/ma-ont#";
87
+ this.prefixes["owl"] = "http://www.w3.org/2002/07/owl#";
88
+ this.prefixes["rdf"] = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
89
+ this.prefixes["rdfa"] = "http://www.w3.org/ns/rdfa#";
90
+ this.prefixes["rdfs"] = "http://www.w3.org/2000/01/rdf-schema#";
91
+ this.prefixes["rif"] = "http://www.w3.org/2007/rif#";
92
+ this.prefixes["skos"] = "http://www.w3.org/2004/02/skos/core#";
93
+ this.prefixes["skosxl"] = "http://www.w3.org/2008/05/skos-xl#";
94
+ this.prefixes["wdr"] = "http://www.w3.org/2007/05/powder#";
95
+ this.prefixes["void"] = "http://rdfs.org/ns/void#";
96
+ this.prefixes["wdrs"] = "http://www.w3.org/2007/05/powder-s#";
97
+ this.prefixes["xhv"] = "http://www.w3.org/1999/xhtml/vocab#";
98
+ this.prefixes["xml"] = "http://www.w3.org/XML/1998/namespace";
99
+ this.prefixes["xsd"] = "http://www.w3.org/2001/XMLSchema#";
100
+ // non-rec w3c
101
+ this.prefixes["sd"] = "http://www.w3.org/ns/sparql-service-description#";
102
+ this.prefixes["org"] = "http://www.w3.org/ns/org#";
103
+ this.prefixes["gldp"] = "http://www.w3.org/ns/people#";
104
+ this.prefixes["cnt"] = "http://www.w3.org/2008/content#";
105
+ this.prefixes["dcat"] = "http://www.w3.org/ns/dcat#";
106
+ this.prefixes["earl"] = "http://www.w3.org/ns/earl#";
107
+ this.prefixes["ht"] = "http://www.w3.org/2006/http#";
108
+ this.prefixes["ptr"] = "http://www.w3.org/2009/pointers#";
109
+ // widely used
110
+ this.prefixes["cc"] = "http://creativecommons.org/ns#";
111
+ this.prefixes["ctag"] = "http://commontag.org/ns#";
112
+ this.prefixes["dc"] = "http://purl.org/dc/terms/";
113
+ this.prefixes["dcterms"] = "http://purl.org/dc/terms/";
114
+ this.prefixes["foaf"] = "http://xmlns.com/foaf/0.1/";
115
+ this.prefixes["gr"] = "http://purl.org/goodrelations/v1#";
116
+ this.prefixes["ical"] = "http://www.w3.org/2002/12/cal/icaltzd#";
117
+ this.prefixes["og"] = "http://ogp.me/ns#";
118
+ this.prefixes["rev"] = "http://purl.org/stuff/rev#";
119
+ this.prefixes["sioc"] = "http://rdfs.org/sioc/ns#";
120
+ this.prefixes["v"] = "http://rdf.data-vocabulary.org/#";
121
+ this.prefixes["vcard"] = "http://www.w3.org/2006/vcard/ns#";
122
+ this.prefixes["schema"] = "http://schema.org/";
123
+
124
+ // terms
125
+ this.terms["describedby"] =
126
+ "http://www.w3.org/2007/05/powder-s#describedby";
127
+ this.terms["license"] = "http://www.w3.org/1999/xhtml/vocab#license";
128
+ this.terms["role"] = "http://www.w3.org/1999/xhtml/vocab#role";
129
+
130
+ Object.defineProperty(this, "tripleCount", {
131
+ enumerable: true,
132
+ configurable: false,
133
+ get: function() {
134
+ var count = 0;
135
+ for (var s in this.subjects) {
136
+ var snode = this.subjects[s];
137
+ for (var p in snode.predicates) {
138
+ count += snode.predicates[p].objects.length;
139
+ }
140
+ }
141
+ return count;
142
+ },
143
+ });
144
+ }
145
+
146
+ newBlankNode() {
147
+ this.blankNodeCounter++;
148
+ return "_:" + this.blankNodeCounter;
149
+ }
150
+
151
+ expand(curie) {
152
+ return this.curieParser.parse(curie, true);
153
+ }
154
+
155
+ shorten(uri, prefixesUsed) {
156
+ for (prefix in this.prefixes) {
157
+ var mapped = this.prefixes[prefix];
158
+ if (uri.indexOf(mapped) == 0) {
159
+ if (prefixesUsed) {
160
+ prefixesUsed[prefix] = mapped;
161
+ }
162
+ return prefix + ":" + uri.substring(mapped.length);
163
+ }
164
+ }
165
+ return null;
166
+ }
167
+
168
+ add(subject, predicate, object, options) {
169
+ if (!subject || !predicate || !object) {
170
+ return;
171
+ }
172
+ subject = this.expand(subject);
173
+ predicate = this.expand(predicate);
174
+ var snode = this.subjects[subject];
175
+ if (!snode) {
176
+ snode = new RDFaSubject(this, subject);
177
+ this.subjects[subject] = snode;
178
+ }
179
+ if (options && options.origin) {
180
+ snode.origins.push(options.origin);
181
+ }
182
+ if (predicate == "http://www.w3.org/1999/02/22-rdf-syntax-ns#type") {
183
+ snode.types.push(object);
184
+ }
185
+ var pnode = snode.predicates[predicate];
186
+ if (!pnode) {
187
+ pnode = new RDFaPredicate(predicate);
188
+ snode.predicates[predicate] = pnode;
189
+ }
190
+
191
+ if (typeof object == "string") {
192
+ pnode.objects.push({
193
+ type: RDFaProcessor.PlainLiteralURI,
194
+ value: object,
195
+ });
196
+ } else {
197
+ pnode.objects.push({
198
+ type: object.type
199
+ ? this.expand(object.type)
200
+ : RDFaProcessor.PlainLiteralURI,
201
+ value: object.value ? object.value : "",
202
+ origin: object.origin,
203
+ language: object.language,
204
+ });
205
+ }
206
+ }
207
+
208
+ addCollection(subject, predicate, objectList, options) {
209
+ if (!subject || !predicate || !objectList) {
210
+ return;
211
+ }
212
+
213
+ var lastSubject = subject;
214
+ var lastPredicate = predicate;
215
+ for (var i = 0; i < objectList.length; i++) {
216
+ var object = {
217
+ type: options && options.type ? options.type : "rdf:PlainLiteral",
218
+ };
219
+ if (options && options.language) {
220
+ object.language = options.language;
221
+ }
222
+ if (options && options.datatype) {
223
+ object.datatype = options.datatype;
224
+ }
225
+ if (typeof objectList[i] == "object") {
226
+ object.value = objectList[i].value ? objectList[i].value : "";
227
+ if (objectList[i].type) {
228
+ object.type = objectList[i].type;
229
+ }
230
+ if (objectList[i].language) {
231
+ object.language = objectList[i].language;
232
+ }
233
+ if (objectList[i].datatype) {
234
+ object.datatype = objectList[i].datatype;
235
+ }
236
+ } else {
237
+ object.value = objectList[i];
238
+ }
239
+ var bnode = this.newBlankNode();
240
+ this.add(lastSubject, lastPredicate, {
241
+ type: "rdf:object",
242
+ value: bnode,
243
+ });
244
+ this.add(bnode, "rdf:first", object);
245
+ lastSubject = bnode;
246
+ lastPredicate = "http://www.w3.org/1999/02/22-rdf-syntax-ns#rest";
247
+ }
248
+ this.add(lastSubject, lastPredicate, {
249
+ type: "rdf:object",
250
+ value: "http://www.w3.org/1999/02/22-rdf-syntax-ns#nil",
251
+ });
252
+ }
253
+
254
+ remove(subject, predicate) {
255
+ if (!subject) {
256
+ this.subjects = {};
257
+ return;
258
+ }
259
+ subject = this.expand(subject);
260
+ var snode = this.subjects[snode];
261
+ if (!snode) {
262
+ return;
263
+ }
264
+ if (!predicate) {
265
+ delete this.subjects[subject];
266
+ return;
267
+ }
268
+ predicate = this.expand(predicate);
269
+ delete snode.predicates[predicate];
270
+ }
271
+ }
272
+
273
+ export class RDFaSubject {
274
+ constructor(graph, subject) {
275
+ this.graph = graph;
276
+ // TODO: subject or id?
277
+ this.subject = subject;
278
+ this.id = subject;
279
+ this.predicates = {};
280
+ this.origins = [];
281
+ this.types = [];
282
+ }
283
+
284
+ toString(options) {
285
+ var s = null;
286
+ if (this.subject.substring(0, 2) == "_:") {
287
+ if (options && options.filterBlankNode) {
288
+ s = options.filterBlankNode(this.subject);
289
+ } else {
290
+ s = this.subject;
291
+ }
292
+ } else if (options && options.shorten) {
293
+ s = this.graph.shorten(this.subject, options.prefixesUsed);
294
+ if (!s) {
295
+ s = "<" + this.subject + ">";
296
+ }
297
+ } else {
298
+ s = "<" + this.subject + ">";
299
+ }
300
+ var first = true;
301
+ for (var predicate in this.predicates) {
302
+ if (!first) {
303
+ s += ";\n";
304
+ } else {
305
+ first = false;
306
+ }
307
+ s += " " + this.predicates[predicate].toString(options);
308
+ }
309
+ s += " .";
310
+ return s;
311
+ }
312
+
313
+ toObject() {
314
+ var o = { subject: this.subject, predicates: {} };
315
+ for (var predicate in this.predicates) {
316
+ var pnode = this.predicates[predicate];
317
+ var p = { predicate: predicate, objects: [] };
318
+ o.predicates[predicate] = p;
319
+ for (var i = 0; i < pnode.objects.length; i++) {
320
+ var object = pnode.objects[i];
321
+ if (object.type == RDFaProcessor.XMLLiteralURI) {
322
+ var serializer = new XMLSerializer();
323
+ var value = "";
324
+ for (var x = 0; x < object.value.length; x++) {
325
+ if (object.value[x].nodeType == Node.ELEMENT_NODE) {
326
+ value += serializer.serializeToString(object.value[x]);
327
+ } else if (object.value[x].nodeType == Node.TEXT_NODE) {
328
+ value += object.value[x].nodeValue;
329
+ }
330
+ }
331
+ p.objects.push({
332
+ type: object.type,
333
+ value: value,
334
+ language: object.language,
335
+ });
336
+ } else if (object.type == RDFaProcessor.HTMLLiteralURI) {
337
+ var value =
338
+ object.value.length == 0
339
+ ? ""
340
+ : object.value[0].parentNode.innerHTML;
341
+ p.objects.push({
342
+ type: object.type,
343
+ value: value,
344
+ language: object.language,
345
+ });
346
+ } else {
347
+ p.objects.push({
348
+ type: object.type,
349
+ value: object.value,
350
+ language: object.language,
351
+ });
352
+ }
353
+ }
354
+ }
355
+ return o;
356
+ }
357
+
358
+ getValues() {
359
+ var values = [];
360
+ for (var i = 0; i < arguments.length; i++) {
361
+ var property = this.graph.curieParser.parse(arguments[i], true);
362
+ var pnode = this.predicates[property];
363
+ if (pnode) {
364
+ for (var j = 0; j < pnode.objects.length; j++) {
365
+ values.push(pnode.objects[j].value);
366
+ }
367
+ }
368
+ }
369
+ return values;
370
+ }
371
+ }
372
+
373
+ export class RDFaPredicate {
374
+ constructor(predicate) {
375
+ this.id = predicate;
376
+ this.predicate = predicate;
377
+ this.objects = [];
378
+ }
379
+
380
+ toString(options) {
381
+ var s = null;
382
+ if (options && options.shorten && options.graph) {
383
+ s = options.graph.shorten(this.predicate, options.prefixesUsed);
384
+ if (!s) {
385
+ s = "<" + this.predicate + ">";
386
+ }
387
+ } else {
388
+ s = "<" + this.predicate + ">";
389
+ }
390
+ s += " ";
391
+ for (var i = 0; i < this.objects.length; i++) {
392
+ if (i > 0) {
393
+ s += ", ";
394
+ }
395
+ if (
396
+ this.objects[i].type ==
397
+ "http://www.w3.org/1999/02/22-rdf-syntax-ns#object"
398
+ ) {
399
+ if (this.objects[i].value.substring(0, 2) == "_:") {
400
+ if (options && options.filterBlankNode) {
401
+ s += options.filterBlankNode(this.objects[i].value);
402
+ } else {
403
+ s += this.objects[i].value;
404
+ }
405
+ } else if (options && options.shorten && options.graph) {
406
+ u = options.graph.shorten(
407
+ this.objects[i].value,
408
+ options.prefixesUsed,
409
+ );
410
+ if (u) {
411
+ s += u;
412
+ } else {
413
+ s += "<" + this.objects[i].value + ">";
414
+ }
415
+ } else {
416
+ s += "<" + this.objects[i].value + ">";
417
+ }
418
+ } else if (
419
+ this.objects[i].type == "http://www.w3.org/2001/XMLSchema#integer" ||
420
+ this.objects[i].type == "http://www.w3.org/2001/XMLSchema#decimal" ||
421
+ this.objects[i].type == "http://www.w3.org/2001/XMLSchema#double" ||
422
+ this.objects[i].type == "http://www.w3.org/2001/XMLSchema#boolean"
423
+ ) {
424
+ s +=
425
+ '"' +
426
+ this.objects[i].value +
427
+ '"' +
428
+ "^^<" +
429
+ this.objects[i].type +
430
+ ">";
431
+ } else if (
432
+ this.objects[i].type ==
433
+ "http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral"
434
+ ) {
435
+ var serializer = new XMLSerializer();
436
+ var value = "";
437
+ for (var x = 0; x < this.objects[i].value.length; x++) {
438
+ if (this.objects[i].value[x].nodeType == Node.ELEMENT_NODE) {
439
+ var prefixMap = RDFaPredicate.getPrefixMap(
440
+ this.objects[i].value[x],
441
+ );
442
+ var prefixes = [];
443
+ for (var prefix in prefixMap) {
444
+ prefixes.push(prefix);
445
+ }
446
+ prefixes.sort();
447
+ var e = this.objects[i].value[x].cloneNode(true);
448
+ for (var p = 0; p < prefixes.length; p++) {
449
+ e.setAttributeNS(
450
+ "http://www.w3.org/2000/xmlns/",
451
+ prefixes[p].length == 0 ? "xmlns" : "xmlns:" + prefixes[p],
452
+ prefixMap[prefixes[p]],
453
+ );
454
+ }
455
+ value += serializer.serializeToString(e);
456
+ } else if (this.objects[i].value[x].nodeType == Node.TEXT_NODE) {
457
+ value += this.objects[i].value[x].nodeValue;
458
+ }
459
+ }
460
+ s +=
461
+ '"""' +
462
+ value.replace(/"""/g, '\\"\\"\\"') +
463
+ '"""^^<http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral>';
464
+ } else if (
465
+ this.objects[i].type ==
466
+ "http://www.w3.org/1999/02/22-rdf-syntax-ns#HTML"
467
+ ) {
468
+ // We can use innerHTML as a shortcut from the parentNode if the list is not empty
469
+ if (this.objects[i].value.length == 0) {
470
+ s += '""""""^^<http://www.w3.org/1999/02/22-rdf-syntax-ns#HTML>';
471
+ } else {
472
+ s +=
473
+ '"""' +
474
+ this.objects[i].value[0].parentNode.innerHTML.replace(
475
+ /"""/g,
476
+ '\\"\\"\\"',
477
+ ) +
478
+ '"""^^<http://www.w3.org/1999/02/22-rdf-syntax-ns#HTML>';
479
+ }
480
+ } else {
481
+ var l = this.objects[i].value.toString();
482
+ if (l.indexOf("\n") >= 0 || l.indexOf("\r") >= 0) {
483
+ s += '"""' + l.replace(/"""/g, '\\"\\"\\"') + '"""';
484
+ } else {
485
+ s += '"' + l.replace(/"/g, '\\"') + '"';
486
+ }
487
+ if (
488
+ this.objects[i].type !=
489
+ "http://www.w3.org/1999/02/22-rdf-syntax-ns#PlainLiteral"
490
+ ) {
491
+ s += "^^<" + this.objects[i].type + ">";
492
+ } else if (this.objects[i].language) {
493
+ s += "@" + this.objects[i].language;
494
+ }
495
+ }
496
+ }
497
+ return s;
498
+ }
499
+ }
500
+
501
+ RDFaPredicate.getPrefixMap = function(e) {
502
+ var prefixMap = {};
503
+ while (e.attributes) {
504
+ for (var i = 0; i < e.attributes.length; i++) {
505
+ if (e.attributes[i].namespaceURI == "http://www.w3.org/2000/xmlns/") {
506
+ var prefix = e.attributes[i].localName;
507
+ if (e.attributes[i].localName == "xmlns") {
508
+ prefix = "";
509
+ }
510
+ if (!(prefix in prefixMap)) {
511
+ prefixMap[prefix] = e.attributes[i].nodeValue;
512
+ }
513
+ }
514
+ }
515
+ e = e.parentNode;
516
+ }
517
+ return prefixMap;
518
+ };