rdflib 2.2.21 → 2.2.22-b51259b5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/dist/rdflib.min.js +1 -1
  2. package/dist/rdflib.min.js.LICENSE.txt +9 -1
  3. package/dist/rdflib.min.js.map +1 -1
  4. package/esm/blank-node.js +61 -114
  5. package/esm/class-order.js +1 -1
  6. package/esm/collection.js +70 -128
  7. package/esm/convert.js +1 -2
  8. package/esm/default-graph.js +14 -48
  9. package/esm/empty.js +8 -39
  10. package/esm/factories/canonical-data-factory.js +33 -65
  11. package/esm/factories/extended-term-factory.js +18 -25
  12. package/esm/factories/factory-types.js +3 -2
  13. package/esm/factories/rdflib-data-factory.js +9 -19
  14. package/esm/fetcher.js +1341 -1854
  15. package/esm/formula.js +639 -846
  16. package/esm/index.js +40 -76
  17. package/esm/jsonldparser.js +24 -49
  18. package/esm/jsonparser.js +1 -8
  19. package/esm/lists.js +47 -110
  20. package/esm/literal.js +120 -189
  21. package/esm/log.js +7 -7
  22. package/esm/n3parser.js +1015 -1412
  23. package/esm/named-node.js +70 -119
  24. package/esm/namespace.js +2 -5
  25. package/esm/node-internal.js +73 -110
  26. package/esm/node.js +2 -7
  27. package/esm/parse.js +12 -19
  28. package/esm/patch-parser.js +10 -30
  29. package/esm/query-to-sparql.js +0 -18
  30. package/esm/query.js +63 -147
  31. package/esm/rdfaparser.js +794 -997
  32. package/esm/rdfxmlparser.js +347 -461
  33. package/esm/serialize.js +9 -27
  34. package/esm/serializer.js +820 -1049
  35. package/esm/sparql-to-query.js +44 -134
  36. package/esm/statement.js +54 -85
  37. package/esm/store.js +830 -1103
  38. package/esm/types.js +22 -21
  39. package/esm/update-manager.js +869 -1106
  40. package/esm/updates-via.js +104 -161
  41. package/esm/uri.js +9 -53
  42. package/esm/utils/default-graph-uri.js +3 -2
  43. package/esm/utils/termValue.js +0 -1
  44. package/esm/utils/terms.js +19 -21
  45. package/esm/utils-js.js +20 -61
  46. package/esm/utils.js +10 -21
  47. package/esm/variable.js +32 -78
  48. package/esm/xsd.js +2 -2
  49. package/lib/blank-node.js +60 -113
  50. package/lib/class-order.js +1 -2
  51. package/lib/collection.js +69 -131
  52. package/lib/convert.js +3 -9
  53. package/lib/default-graph.js +13 -52
  54. package/lib/empty.js +8 -43
  55. package/lib/factories/canonical-data-factory.js +35 -79
  56. package/lib/factories/extended-term-factory.js +18 -32
  57. package/lib/factories/factory-types.d.ts +6 -6
  58. package/lib/factories/factory-types.js +1 -4
  59. package/lib/factories/rdflib-data-factory.js +9 -23
  60. package/lib/fetcher.d.ts +6 -6
  61. package/lib/fetcher.js +1370 -1843
  62. package/lib/formula.js +640 -855
  63. package/lib/index.js +66 -152
  64. package/lib/jsonldparser.js +23 -53
  65. package/lib/jsonparser.js +1 -10
  66. package/lib/lists.js +55 -112
  67. package/lib/literal.js +120 -195
  68. package/lib/log.d.ts +0 -6
  69. package/lib/log.js +7 -8
  70. package/lib/n3parser.js +1030 -1436
  71. package/lib/named-node.js +69 -126
  72. package/lib/namespace.js +2 -7
  73. package/lib/node-internal.js +74 -107
  74. package/lib/node.js +2 -12
  75. package/lib/parse.d.ts +1 -1
  76. package/lib/parse.js +12 -32
  77. package/lib/patch-parser.js +11 -34
  78. package/lib/query-to-sparql.js +0 -23
  79. package/lib/query.js +62 -167
  80. package/lib/rdfaparser.js +796 -1009
  81. package/lib/rdfxmlparser.js +349 -466
  82. package/lib/serialize.js +11 -37
  83. package/lib/serializer.js +823 -1064
  84. package/lib/sparql-to-query.js +42 -167
  85. package/lib/statement.js +55 -91
  86. package/lib/store.d.ts +1 -1
  87. package/lib/store.js +850 -1112
  88. package/lib/tf-types.d.ts +4 -4
  89. package/lib/types.d.ts +8 -8
  90. package/lib/types.js +23 -23
  91. package/lib/update-manager.d.ts +1 -1
  92. package/lib/update-manager.js +865 -1103
  93. package/lib/updates-via.js +105 -164
  94. package/lib/uri.js +8 -61
  95. package/lib/utils/default-graph-uri.js +3 -5
  96. package/lib/utils/termValue.js +0 -2
  97. package/lib/utils/terms.js +19 -40
  98. package/lib/utils-js.js +23 -88
  99. package/lib/utils.js +10 -27
  100. package/lib/variable.js +34 -85
  101. package/lib/xsd-internal.js +0 -3
  102. package/lib/xsd.js +2 -6
  103. package/package.json +35 -35
  104. package/src/fetcher.ts +2 -2
  105. package/src/update-manager.ts +12 -7
  106. package/changes.txt +0 -59
package/esm/serializer.js CHANGED
@@ -1,7 +1,4 @@
1
- import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
2
- import _createClass from "@babel/runtime/helpers/createClass";
3
1
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
4
-
5
2
  /* Serialization of RDF Graphs
6
3
  **
7
4
  ** Tim Berners-Lee 2006
@@ -20,1197 +17,971 @@ export default function createSerializer(store) {
20
17
  return new Serializer(store);
21
18
  }
22
19
  ;
23
- export var Serializer = /*#__PURE__*/function () {
24
- function Serializer(store) {
25
- _classCallCheck(this, Serializer);
26
-
20
+ export class Serializer {
21
+ constructor(store) {
27
22
  _defineProperty(this, "_notQNameChars", '\t\r\n !"#$%&\'()*.,+/;<=>?@[\\]^`{|}~');
28
-
29
23
  _defineProperty(this, "_notNameChars", this._notQNameChars + ':');
30
-
31
24
  _defineProperty(this, "validPrefix", new RegExp(/^[a-zA-Z][a-zA-Z0-9]*$/));
32
-
33
25
  _defineProperty(this, "forbidden1", new RegExp(/[\\"\b\f\r\v\t\n\u0080-\uffff]/gm));
34
-
35
26
  _defineProperty(this, "forbidden3", new RegExp(/[\\"\b\f\r\v\u0080-\uffff]/gm));
36
-
37
27
  this.flags = '';
38
28
  this.base = null;
39
29
  this.prefixes = []; // suggested prefixes
40
-
41
30
  this.namespaces = []; // complementary
42
-
43
- var nsKeys = Object.keys(solidNs());
44
-
45
- for (var i in nsKeys) {
46
- var uri = solidNs()[nsKeys[i]]('');
47
- var prefix = nsKeys[i];
31
+ const nsKeys = Object.keys(solidNs());
32
+ for (const i in nsKeys) {
33
+ const uri = solidNs()[nsKeys[i]]('');
34
+ const prefix = nsKeys[i];
48
35
  this.prefixes[uri] = prefix;
49
36
  this.namespaces[prefix] = uri;
50
37
  }
51
-
52
38
  this.suggestPrefix('rdf', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'); // XML code assumes this!
53
-
54
39
  this.suggestPrefix('xml', 'reserved:reservedForFutureUse'); // XML reserves xml: in the spec.
55
40
 
56
41
  this.namespacesUsed = []; // Count actually used and so needed in @prefixes
57
-
58
42
  this.keywords = ['a']; // The only one we generate at the moment
59
-
60
43
  this.prefixchars = 'abcdefghijklmnopqustuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
61
44
  this.incoming = null; // Array not calculated yet
62
-
63
45
  this.formulas = []; // remembering original formulae from hashes
64
-
65
46
  this.store = store;
66
47
  this.rdfFactory = store.rdfFactory || CanonicalDataFactory;
67
48
  this.xsd = createXSD(this.rdfFactory);
68
49
  }
69
-
70
- _createClass(Serializer, [{
71
- key: "setBase",
72
- value: function setBase(base) {
73
- this.base = base;
74
- return this;
75
- }
76
- }, {
77
- key: "setFlags",
78
- value: function setFlags(flags) {
79
- this.flags = flags || '';
80
- return this;
50
+ setBase(base) {
51
+ this.base = base;
52
+ return this;
53
+ }
54
+ setFlags(flags) {
55
+ this.flags = flags || '';
56
+ return this;
57
+ }
58
+ toStr(x) {
59
+ var s = x.toNT();
60
+ if (x.termType === 'Graph') {
61
+ this.formulas[s] = x; // remember as reverse does not work
81
62
  }
82
- }, {
83
- key: "toStr",
84
- value: function toStr(x) {
85
- var s = x.toNT();
86
-
87
- if (x.termType === 'Graph') {
88
- this.formulas[s] = x; // remember as reverse does not work
89
- }
90
63
 
91
- return s;
64
+ return s;
65
+ }
66
+ fromStr(s) {
67
+ if (s[0] === '{') {
68
+ var x = this.formulas[s];
69
+ if (!x) console.log('No formula object for ' + s);
70
+ return x;
92
71
  }
93
- }, {
94
- key: "fromStr",
95
- value: function fromStr(s) {
96
- if (s[0] === '{') {
97
- var x = this.formulas[s];
98
- if (!x) console.log('No formula object for ' + s);
99
- return x;
100
- }
72
+ return this.store.fromNT(s);
73
+ }
101
74
 
102
- return this.store.fromNT(s);
75
+ /**
76
+ * Defines a set of [prefix, namespace] pairs to be used by this Serializer instance.
77
+ * Overrides previous prefixes if any
78
+ * @param namespaces
79
+ * @return {Serializer}
80
+ */
81
+ setNamespaces(namespaces) {
82
+ for (var px in namespaces) {
83
+ this.setPrefix(px, namespaces[px]);
103
84
  }
104
- /**
105
- * Defines a set of [prefix, namespace] pairs to be used by this Serializer instance.
106
- * Overrides previous prefixes if any
107
- * @param namespaces
108
- * @return {Serializer}
109
- */
110
-
111
- }, {
112
- key: "setNamespaces",
113
- value: function setNamespaces(namespaces) {
114
- for (var px in namespaces) {
115
- this.setPrefix(px, namespaces[px]);
116
- }
85
+ return this;
86
+ }
117
87
 
118
- return this;
88
+ /**
89
+ * Defines a namespace prefix, overriding any existing prefix for that URI
90
+ * @param prefix
91
+ * @param uri
92
+ */
93
+ setPrefix(prefix, uri) {
94
+ if (prefix.slice(0, 7) === 'default') return; // Try to weed these out
95
+ if (prefix.slice(0, 2) === 'ns') return; // From others inferior algos
96
+ if (!prefix || !uri) return; // empty strings not suitable
97
+
98
+ // remove any existing prefix targeting this uri
99
+ // for (let existingPrefix in this.namespaces) {
100
+ // if (this.namespaces[existingPrefix] == uri)
101
+ // delete this.namespaces[existingPrefix];
102
+ // }
103
+
104
+ // remove any existing mapping for this prefix
105
+ for (let existingNs in this.prefixes) {
106
+ if (this.prefixes[existingNs] == prefix) delete this.prefixes[existingNs];
119
107
  }
120
- /**
121
- * Defines a namespace prefix, overriding any existing prefix for that URI
122
- * @param prefix
123
- * @param uri
124
- */
125
-
126
- }, {
127
- key: "setPrefix",
128
- value: function setPrefix(prefix, uri) {
129
- if (prefix.slice(0, 7) === 'default') return; // Try to weed these out
130
-
131
- if (prefix.slice(0, 2) === 'ns') return; // From others inferior algos
132
-
133
- if (!prefix || !uri) return; // empty strings not suitable
134
- // remove any existing prefix targeting this uri
135
- // for (let existingPrefix in this.namespaces) {
136
- // if (this.namespaces[existingPrefix] == uri)
137
- // delete this.namespaces[existingPrefix];
138
- // }
139
- // remove any existing mapping for this prefix
108
+ this.prefixes[uri] = prefix;
109
+ this.namespaces[prefix] = uri;
110
+ }
140
111
 
141
- for (var existingNs in this.prefixes) {
142
- if (this.prefixes[existingNs] == prefix) delete this.prefixes[existingNs];
143
- }
112
+ /* Accumulate Namespaces
113
+ **
114
+ ** These are only hints. If two overlap, only one gets used
115
+ ** There is therefore no guarantee in general.
116
+ */
117
+ suggestPrefix(prefix, uri) {
118
+ if (prefix.slice(0, 7) === 'default') return; // Try to weed these out
119
+ if (prefix.slice(0, 2) === 'ns') return; // From others inferior algos
120
+ if (!prefix || !uri) return; // empty strings not suitable
121
+ if (prefix in this.namespaces || uri in this.prefixes) return; // already used
122
+ this.prefixes[uri] = prefix;
123
+ this.namespaces[prefix] = uri;
124
+ }
144
125
 
145
- this.prefixes[uri] = prefix;
146
- this.namespaces[prefix] = uri;
126
+ // Takes a namespace -> prefix map
127
+ suggestNamespaces(namespaces) {
128
+ for (var px in namespaces) {
129
+ this.suggestPrefix(px, namespaces[px]);
147
130
  }
148
- /* Accumulate Namespaces
149
- **
150
- ** These are only hints. If two overlap, only one gets used
151
- ** There is therefore no guarantee in general.
152
- */
153
-
154
- }, {
155
- key: "suggestPrefix",
156
- value: function suggestPrefix(prefix, uri) {
157
- if (prefix.slice(0, 7) === 'default') return; // Try to weed these out
158
-
159
- if (prefix.slice(0, 2) === 'ns') return; // From others inferior algos
160
-
161
- if (!prefix || !uri) return; // empty strings not suitable
162
-
163
- if (prefix in this.namespaces || uri in this.prefixes) return; // already used
164
-
165
- this.prefixes[uri] = prefix;
166
- this.namespaces[prefix] = uri;
167
- } // Takes a namespace -> prefix map
168
-
169
- }, {
170
- key: "suggestNamespaces",
171
- value: function suggestNamespaces(namespaces) {
172
- for (var px in namespaces) {
173
- this.suggestPrefix(px, namespaces[px]);
131
+ return this;
132
+ }
133
+ checkIntegrity() {
134
+ var p, ns;
135
+ for (p in this.namespaces) {
136
+ if (this.prefixes[this.namespaces[p]] !== p) {
137
+ throw new Error('Serializer integity error 1: ' + p + ', ' + this.namespaces[p] + ', ' + this.prefixes[this.namespaces[p]] + '!');
174
138
  }
175
-
176
- return this;
177
139
  }
178
- }, {
179
- key: "checkIntegrity",
180
- value: function checkIntegrity() {
181
- var p, ns;
182
-
183
- for (p in this.namespaces) {
184
- if (this.prefixes[this.namespaces[p]] !== p) {
185
- throw new Error('Serializer integity error 1: ' + p + ', ' + this.namespaces[p] + ', ' + this.prefixes[this.namespaces[p]] + '!');
186
- }
187
- }
188
-
189
- for (ns in this.prefixes) {
190
- if (this.namespaces[this.prefixes[ns]] !== ns) {
191
- throw new Error('Serializer integity error 2: ' + ns + ', ' + this.prefixs[ns] + ', ' + this.namespaces[this.prefixes[ns]] + '!');
192
- }
193
- }
194
- } // Make up an unused prefix for a random namespace
195
-
196
- }, {
197
- key: "makeUpPrefix",
198
- value: function makeUpPrefix(uri) {
199
- var p = uri;
200
-
201
- function canUseMethod(pp) {
202
- if (!this.validPrefix.test(pp)) return false; // bad format
203
-
204
- if (pp === 'ns') return false; // boring
205
-
206
- if (pp in this.namespaces) return false; // already used
207
-
208
- this.prefixes[uri] = pp;
209
- this.namespaces[pp] = uri;
210
- return pp;
211
- }
212
-
213
- var canUse = canUseMethod.bind(this);
214
- if ('#/'.indexOf(p[p.length - 1]) >= 0) p = p.slice(0, -1);
215
- var slash = p.lastIndexOf('/');
216
- if (slash >= 0) p = p.slice(slash + 1);
217
- var i = 0;
218
-
219
- while (i < p.length) {
220
- if (this.prefixchars.indexOf(p[i])) {
221
- i++;
222
- } else {
223
- break;
224
- }
225
- }
226
-
227
- p = p.slice(0, i);
228
- if (p.length < 6 && canUse(p)) return p; // exact is best
229
-
230
- if (canUse(p.slice(0, 3))) return p.slice(0, 3);
231
- if (canUse(p.slice(0, 2))) return p.slice(0, 2);
232
- if (canUse(p.slice(0, 4))) return p.slice(0, 4);
233
- if (canUse(p.slice(0, 1))) return p.slice(0, 1);
234
- if (canUse(p.slice(0, 5))) return p.slice(0, 5);
235
-
236
- if (!this.validPrefix.test(p)) {
237
- p = 'n'; // Otherwise the loop below may never termimnate
238
- }
239
-
240
- for (var j = 0;; j++) {
241
- if (canUse(p.slice(0, 3) + j)) return p.slice(0, 3) + j;
140
+ for (ns in this.prefixes) {
141
+ if (this.namespaces[this.prefixes[ns]] !== ns) {
142
+ throw new Error('Serializer integity error 2: ' + ns + ', ' + this.prefixs[ns] + ', ' + this.namespaces[this.prefixes[ns]] + '!');
242
143
  }
243
144
  }
244
- }, {
245
- key: "rootSubjects",
246
- value: function rootSubjects(sts) {
247
- var incoming = {};
248
- var subjects = {};
249
- var allBnodes = {};
250
- /* This scan is to find out which nodes will have to be the roots of trees
251
- ** in the serialized form. This will be any symbols, and any bnodes
252
- ** which hve more or less than one incoming arc, and any bnodes which have
253
- ** one incoming arc but it is an uninterrupted loop of such nodes back to itself.
254
- ** This should be kept linear time with repect to the number of statements.
255
- ** Note it does not use any indexing of the store.
256
- */
257
-
258
- for (var i = 0; i < sts.length; i++) {
259
- var st = sts[i];
260
-
261
- var checkMentions = function checkMentions(x) {
262
- if (!incoming.hasOwnProperty(x)) incoming[x] = [];
263
- incoming[x].push(st.subject); // List of things which will cause this to be printed
264
- };
265
-
266
- var st2 = [st.subject, st.predicate, st.object];
267
- st2.map(function (y) {
268
- if (y.termType === 'BlankNode') {
269
- allBnodes[y.toNT()] = true;
270
- } else if (y.termType === 'Collection') {
271
- y.elements.forEach(function (z) {
272
- checkMentions(z); // bnodes in collections important
273
- });
274
- }
275
- });
276
- checkMentions(sts[i].object);
277
- var ss = subjects[this.toStr(st.subject)]; // Statements with this as subject
278
-
279
- if (!ss) ss = [];
280
- ss.push(st);
281
- subjects[this.toStr(st.subject)] = ss; // Make hash. @@ too slow for formula?
282
- }
283
-
284
- var roots = [];
285
-
286
- for (var xNT in subjects) {
287
- if (!subjects.hasOwnProperty(xNT)) continue;
288
- var y = this.fromStr(xNT);
289
-
290
- if (y.termType !== 'BlankNode' || !incoming[y] || incoming[y].length !== 1) {
291
- roots.push(y);
292
- continue;
293
- }
294
- }
295
-
296
- this.incoming = incoming; // Keep for serializing @@ Bug for nested formulas
297
- // Now do the scan using existing roots
298
-
299
- var rootsHash = {};
300
-
301
- for (var k = 0; k < roots.length; k++) {
302
- rootsHash[roots[k].toNT()] = true;
303
- }
304
-
305
- return {
306
- 'roots': roots,
307
- 'subjects': subjects,
308
- 'rootsHash': rootsHash,
309
- 'incoming': incoming
310
- };
311
- } // //////////////////////////////////////////////////////
145
+ }
312
146
 
313
- }, {
314
- key: "toN3",
315
- value: function toN3(f) {
316
- return this.statementsToN3(f.statements);
147
+ // Make up an unused prefix for a random namespace
148
+ makeUpPrefix(uri) {
149
+ var p = uri;
150
+ function canUseMethod(pp) {
151
+ if (!this.validPrefix.test(pp)) return false; // bad format
152
+ if (pp === 'ns') return false; // boring
153
+ if (pp in this.namespaces) return false; // already used
154
+ this.prefixes[uri] = pp;
155
+ this.namespaces[pp] = uri;
156
+ return pp;
317
157
  }
318
- }, {
319
- key: "explicitURI",
320
- value: function explicitURI(uri) {
321
- if (this.flags.indexOf('r') < 0 && this.base) {
322
- uri = Uri.refTo(this.base, uri);
323
- } else if (this.flags.indexOf('u') >= 0) {
324
- // Unicode encoding NTriples style
325
- uri = backslashUify(uri);
158
+ var canUse = canUseMethod.bind(this);
159
+ if ('#/'.indexOf(p[p.length - 1]) >= 0) p = p.slice(0, -1);
160
+ var slash = p.lastIndexOf('/');
161
+ if (slash >= 0) p = p.slice(slash + 1);
162
+ var i = 0;
163
+ while (i < p.length) {
164
+ if (this.prefixchars.indexOf(p[i])) {
165
+ i++;
326
166
  } else {
327
- uri = hexify(uri);
167
+ break;
328
168
  }
329
-
330
- return '<' + uri + '>';
331
169
  }
332
- }, {
333
- key: "statementsToNTriples",
334
- value: function statementsToNTriples(sts) {
335
- var sorted = sts.slice();
336
- sorted.sort();
337
- var str = '';
338
- var rdfns = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
339
- var self = this;
340
- var kb = this.store;
341
- var factory = this.rdfFactory;
342
-
343
- var termToNT = function termToNT(x) {
344
- if (x.termType !== 'Collection') {
345
- return self.atomicTermToN3(x);
346
- }
347
-
348
- var list = x.elements;
349
- var rest = kb.sym(rdfns + 'nill');
350
-
351
- for (var i = list.length - 1; i >= 0; i--) {
352
- var bnode = factory.blankNode();
353
- str += termToNT(bnode) + ' ' + termToNT(kb.sym(rdfns + 'first')) + ' ' + termToNT(list[i]) + '.\n';
354
- str += termToNT(bnode) + ' ' + termToNT(kb.sym(rdfns + 'rest')) + ' ' + termToNT(rest) + '.\n';
355
- rest = bnode;
356
- }
170
+ p = p.slice(0, i);
171
+ if (p.length < 6 && canUse(p)) return p; // exact is best
172
+ if (canUse(p.slice(0, 3))) return p.slice(0, 3);
173
+ if (canUse(p.slice(0, 2))) return p.slice(0, 2);
174
+ if (canUse(p.slice(0, 4))) return p.slice(0, 4);
175
+ if (canUse(p.slice(0, 1))) return p.slice(0, 1);
176
+ if (canUse(p.slice(0, 5))) return p.slice(0, 5);
177
+ if (!this.validPrefix.test(p)) {
178
+ p = 'n'; // Otherwise the loop below may never termimnate
179
+ }
357
180
 
358
- return self.atomicTermToN3(rest);
181
+ for (var j = 0;; j++) if (canUse(p.slice(0, 3) + j)) return p.slice(0, 3) + j;
182
+ }
183
+ rootSubjects(sts) {
184
+ var incoming = {};
185
+ var subjects = {};
186
+ var allBnodes = {};
187
+
188
+ /* This scan is to find out which nodes will have to be the roots of trees
189
+ ** in the serialized form. This will be any symbols, and any bnodes
190
+ ** which hve more or less than one incoming arc, and any bnodes which have
191
+ ** one incoming arc but it is an uninterrupted loop of such nodes back to itself.
192
+ ** This should be kept linear time with repect to the number of statements.
193
+ ** Note it does not use any indexing of the store.
194
+ */
195
+ for (var i = 0; i < sts.length; i++) {
196
+ var st = sts[i];
197
+ var checkMentions = function (x) {
198
+ if (!incoming.hasOwnProperty(x)) incoming[x] = [];
199
+ incoming[x].push(st.subject); // List of things which will cause this to be printed
359
200
  };
360
201
 
361
- for (var i = 0; i < sorted.length; i++) {
362
- var st = sorted[i];
363
- var s = '';
364
- s += termToNT(st.subject) + ' ';
365
- s += termToNT(st.predicate) + ' ';
366
- s += termToNT(st.object) + ' ';
367
-
368
- if (this.flags.indexOf('q') >= 0) {
369
- // Do quads not nrtiples
370
- s += termToNT(st.why) + ' ';
202
+ var st2 = [st.subject, st.predicate, st.object];
203
+ st2.map(function (y) {
204
+ if (y.termType === 'BlankNode') {
205
+ allBnodes[y.toNT()] = true;
206
+ } else if (y.termType === 'Collection') {
207
+ y.elements.forEach(function (z) {
208
+ checkMentions(z); // bnodes in collections important
209
+ });
371
210
  }
211
+ });
372
212
 
373
- s += '.\n';
374
- str += s;
375
- }
376
-
377
- return str;
213
+ checkMentions(sts[i].object);
214
+ var ss = subjects[this.toStr(st.subject)]; // Statements with this as subject
215
+ if (!ss) ss = [];
216
+ ss.push(st);
217
+ subjects[this.toStr(st.subject)] = ss; // Make hash. @@ too slow for formula?
378
218
  }
379
- }, {
380
- key: "statementsToN3",
381
- value: function statementsToN3(sts) {
382
- var indent = 4;
383
- var width = 80;
384
- var kb = this.store; // A URI Map alows us to put the type statemnts at the top.
385
-
386
- var uriMap = {
387
- 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type': 'aaa:00'
388
- };
389
-
390
- var SPO = function SPO(x, y) {
391
- // Do limited canonicalization of bnodes
392
- return Util.heavyCompareSPO(x, y, kb, uriMap);
393
- };
394
-
395
- sts.sort(SPO);
396
-
397
- if (this.base && !this.defaultNamespace) {
398
- this.defaultNamespace = this.base + '#';
399
- }
400
-
401
- var predMap = {};
402
219
 
403
- if (this.flags.indexOf('s') < 0) {
404
- predMap['http://www.w3.org/2002/07/owl#sameAs'] = '=';
220
+ var roots = [];
221
+ for (var xNT in subjects) {
222
+ if (!subjects.hasOwnProperty(xNT)) continue;
223
+ var y = this.fromStr(xNT);
224
+ if (y.termType !== 'BlankNode' || !incoming[y] || incoming[y].length !== 1) {
225
+ roots.push(y);
226
+ continue;
405
227
  }
228
+ }
229
+ this.incoming = incoming; // Keep for serializing @@ Bug for nested formulas
406
230
 
407
- if (this.flags.indexOf('t') < 0) {
408
- predMap['http://www.w3.org/1999/02/22-rdf-syntax-ns#type'] = 'a';
409
- }
410
-
411
- if (this.flags.indexOf('i') < 0) {
412
- predMap['http://www.w3.org/2000/10/swap/log#implies'] = '=>';
413
- } // //////////////////////// Arrange the bits of text
414
-
415
-
416
- var spaces = function spaces(n) {
417
- var s = '';
418
-
419
- for (var i = 0; i < n; i++) {
420
- s += ' ';
421
- }
422
-
423
- return s;
424
- };
425
-
426
- var treeToLine = function treeToLine(tree) {
427
- var str = '';
231
+ // Now do the scan using existing roots
232
+ var rootsHash = {};
233
+ for (var k = 0; k < roots.length; k++) {
234
+ rootsHash[roots[k].toNT()] = true;
235
+ }
236
+ return {
237
+ 'roots': roots,
238
+ 'subjects': subjects,
239
+ 'rootsHash': rootsHash,
240
+ 'incoming': incoming
241
+ };
242
+ }
428
243
 
429
- for (var i = 0; i < tree.length; i++) {
430
- var branch = tree[i];
431
- var s2 = typeof branch === 'string' ? branch : treeToLine(branch); // Note the space before the dot in case statement ends with 123 or colon. which is in fact allowed but be conservative.
244
+ // //////////////////////////////////////////////////////
432
245
 
433
- if (i !== 0) {
434
- var ch = str.slice(-1) || ' ';
246
+ toN3(f) {
247
+ return this.statementsToN3(f.statements);
248
+ }
249
+ explicitURI(uri) {
250
+ if (this.flags.indexOf('r') < 0 && this.base) {
251
+ uri = Uri.refTo(this.base, uri);
252
+ } else if (this.flags.indexOf('u') >= 0) {
253
+ // Unicode encoding NTriples style
254
+ uri = backslashUify(uri);
255
+ } else {
256
+ uri = hexify(uri);
257
+ }
258
+ return '<' + uri + '>';
259
+ }
260
+ statementsToNTriples(sts) {
261
+ var sorted = sts.slice();
262
+ sorted.sort();
263
+ var str = '';
264
+ var rdfns = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
265
+ var self = this;
266
+ var kb = this.store;
267
+ var factory = this.rdfFactory;
268
+ var termToNT = function (x) {
269
+ if (x.termType !== 'Collection') {
270
+ return self.atomicTermToN3(x);
271
+ }
272
+ var list = x.elements;
273
+ var rest = kb.sym(rdfns + 'nill');
274
+ for (var i = list.length - 1; i >= 0; i--) {
275
+ var bnode = factory.blankNode();
276
+ str += termToNT(bnode) + ' ' + termToNT(kb.sym(rdfns + 'first')) + ' ' + termToNT(list[i]) + '.\n';
277
+ str += termToNT(bnode) + ' ' + termToNT(kb.sym(rdfns + 'rest')) + ' ' + termToNT(rest) + '.\n';
278
+ rest = bnode;
279
+ }
280
+ return self.atomicTermToN3(rest);
281
+ };
282
+ for (var i = 0; i < sorted.length; i++) {
283
+ var st = sorted[i];
284
+ var s = '';
285
+ s += termToNT(st.subject) + ' ';
286
+ s += termToNT(st.predicate) + ' ';
287
+ s += termToNT(st.object) + ' ';
288
+ if (this.flags.indexOf('q') >= 0) {
289
+ // Do quads not nrtiples
290
+ s += termToNT(st.why) + ' ';
291
+ }
292
+ s += '.\n';
293
+ str += s;
294
+ }
295
+ return str;
296
+ }
297
+ statementsToN3(sts) {
298
+ var indent = 4;
299
+ var width = 80;
300
+ var kb = this.store;
301
+ // A URI Map alows us to put the type statemnts at the top.
302
+ var uriMap = {
303
+ 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type': 'aaa:00'
304
+ };
305
+ var SPO = function (x, y) {
306
+ // Do limited canonicalization of bnodes
307
+ return Util.heavyCompareSPO(x, y, kb, uriMap);
308
+ };
309
+ sts.sort(SPO);
310
+ if (this.base && !this.defaultNamespace) {
311
+ this.defaultNamespace = this.base + '#';
312
+ }
313
+ var predMap = {};
314
+ if (this.flags.indexOf('s') < 0) {
315
+ predMap['http://www.w3.org/2002/07/owl#sameAs'] = '=';
316
+ }
317
+ if (this.flags.indexOf('t') < 0) {
318
+ predMap['http://www.w3.org/1999/02/22-rdf-syntax-ns#type'] = 'a';
319
+ }
320
+ if (this.flags.indexOf('i') < 0) {
321
+ predMap['http://www.w3.org/2000/10/swap/log#implies'] = '=>';
322
+ }
323
+ // //////////////////////// Arrange the bits of text
435
324
 
436
- if (s2 === ',' || s2 === ';') {// no gap
437
- } else if (s2 === '.' && !'0123456789.:'.includes(ch)) {// no gap except after number and colon
438
- // no gap
439
- } else {
440
- str += ' '; // separate from previous token
441
- }
325
+ var spaces = function (n) {
326
+ var s = '';
327
+ for (var i = 0; i < n; i++) s += ' ';
328
+ return s;
329
+ };
330
+ var treeToLine = function (tree) {
331
+ var str = '';
332
+ for (var i = 0; i < tree.length; i++) {
333
+ var branch = tree[i];
334
+ var s2 = typeof branch === 'string' ? branch : treeToLine(branch);
335
+ // Note the space before the dot in case statement ends with 123 or colon. which is in fact allowed but be conservative.
336
+ if (i !== 0) {
337
+ var ch = str.slice(-1) || ' ';
338
+ if (s2 === ',' || s2 === ';') {
339
+ // no gap
340
+ } else if (s2 === '.' && !'0123456789.:'.includes(ch)) {// no gap except after number and colon
341
+ // no gap
342
+ } else {
343
+ str += ' '; // separate from previous token
442
344
  }
443
-
444
- str += s2;
445
345
  }
446
346
 
447
- return str;
448
- }; // Convert a nested tree of lists and strings to a string
449
-
450
-
451
- var treeToString = function treeToString(tree, level) {
452
- var str = '';
453
- var lastLength = 100000;
454
- if (level === undefined) level = -1;
455
-
456
- for (var i = 0; i < tree.length; i++) {
457
- var branch = tree[i];
458
-
459
- if (typeof branch !== 'string') {
460
- var substr = treeToString(branch, level + 1);
461
-
462
- if (substr.length < 10 * (width - indent * level) && substr.indexOf('"""') < 0) {
463
- // Don't mess up multiline strings
464
- var line = treeToLine(branch);
465
-
466
- if (line.length < width - indent * level) {
467
- branch = line; // Note! treat as string below
347
+ str += s2;
348
+ }
349
+ return str;
350
+ };
468
351
 
469
- substr = '';
470
- }
352
+ // Convert a nested tree of lists and strings to a string
353
+ var treeToString = function (tree, level) {
354
+ var str = '';
355
+ var lastLength = 100000;
356
+ if (level === undefined) level = -1;
357
+ for (var i = 0; i < tree.length; i++) {
358
+ var branch = tree[i];
359
+ if (typeof branch !== 'string') {
360
+ var substr = treeToString(branch, level + 1);
361
+ if (substr.length < 10 * (width - indent * level) && substr.indexOf('"""') < 0) {
362
+ // Don't mess up multiline strings
363
+ var line = treeToLine(branch);
364
+ if (line.length < width - indent * level) {
365
+ branch = line; // Note! treat as string below
366
+ substr = '';
471
367
  }
472
-
473
- if (substr) lastLength = 10000;
474
- str += substr;
475
368
  }
476
-
477
- if (typeof branch === 'string') {
478
- if (branch.length === 1 && str.slice(-1) === '\n') {
479
- if (',.;'.indexOf(branch) >= 0) {
480
- str = str.slice(0, -1); // be conservative and ensure a whitespace between some chars and a final dot, as in treeToLine above
481
-
482
- if (branch == '.' && '0123456789.:'.includes(str.charAt(str.length - 1))) {
483
- str += ' ';
484
- lastLength += 1;
485
- }
486
-
487
- str += branch + '\n'; // slip punct'n on end
488
-
369
+ if (substr) lastLength = 10000;
370
+ str += substr;
371
+ }
372
+ if (typeof branch === 'string') {
373
+ if (branch.length === 1 && str.slice(-1) === '\n') {
374
+ if (',.;'.indexOf(branch) >= 0) {
375
+ str = str.slice(0, -1);
376
+ // be conservative and ensure a whitespace between some chars and a final dot, as in treeToLine above
377
+ if (branch == '.' && '0123456789.:'.includes(str.charAt(str.length - 1))) {
378
+ str += ' ';
489
379
  lastLength += 1;
490
- continue;
491
- }
492
- }
493
-
494
- if (lastLength < indent * level + 4 || // if new line not necessary
495
- lastLength + branch.length + 1 < width && ';.'.indexOf(str[str.length - 2]) < 0) {
496
- // or the string fits on last line
497
- str = str.slice(0, -1) + ' ' + branch + '\n'; // then continue on this line
498
-
499
- lastLength += branch.length + 1;
500
- } else {
501
- var _line = spaces(indent * level) + branch;
502
-
503
- str += _line + '\n';
504
- lastLength = _line.length;
505
-
506
- if (level < 0) {
507
- str += '\n'; // extra blank line
508
-
509
- lastLength = 100000; // don't touch
510
380
  }
381
+ str += branch + '\n'; // slip punct'n on end
382
+ lastLength += 1;
383
+ continue;
511
384
  }
512
385
  }
513
- }
514
-
515
- return str;
516
- }; // //////////////////////////////////////////// Structure for N3
517
- // Convert a set of statements into a nested tree of lists and strings
518
-
519
-
520
- function statementListToTreeMethod(statements) {
521
- var stats = this.rootSubjects(statements);
522
- var roots = stats.roots;
523
- var results = [];
524
-
525
- for (var i = 0; i < roots.length; i++) {
526
- var root = roots[i];
527
- results.push(subjectTree(root, stats));
528
- }
529
-
530
- return results;
531
- }
532
-
533
- var statementListToTree = statementListToTreeMethod.bind(this); // The tree for a subject
534
-
535
- function subjectTree(subject, stats) {
536
- if (subject.termType === 'BlankNode' && !stats.incoming[subject]) {
537
- return objectTree(subject, stats, true).concat(['.']); // Anonymous bnode subject
538
- }
539
-
540
- return [termToN3(subject, stats)].concat([propertyTree(subject, stats)]).concat(['.']);
541
- } // The property tree for a single subject or anonymous node
542
-
543
-
544
- function propertyTreeMethod(subject, stats) {
545
- var results = [];
546
- var lastPred = null;
547
- var sts = stats.subjects[this.toStr(subject)] || []; // relevant statements
548
-
549
- if (typeof sts === 'undefined') {
550
- throw new Error('Cant find statements for ' + subject);
551
- }
552
-
553
- var objects = [];
554
-
555
- for (var i = 0; i < sts.length; i++) {
556
- var st = sts[i];
557
-
558
- if (st.predicate.uri === lastPred) {
559
- objects.push(',');
386
+ if (lastLength < indent * level + 4 ||
387
+ // if new line not necessary
388
+ lastLength + branch.length + 1 < width && ';.'.indexOf(str[str.length - 2]) < 0) {
389
+ // or the string fits on last line
390
+ str = str.slice(0, -1) + ' ' + branch + '\n'; // then continue on this line
391
+ lastLength += branch.length + 1;
560
392
  } else {
561
- if (lastPred) {
562
- results = results.concat([objects]).concat([';']);
563
- objects = [];
393
+ let line = spaces(indent * level) + branch;
394
+ str += line + '\n';
395
+ lastLength = line.length;
396
+ if (level < 0) {
397
+ str += '\n'; // extra blank line
398
+ lastLength = 100000; // don't touch
564
399
  }
565
-
566
- results.push(predMap[st.predicate.uri] ? predMap[st.predicate.uri] : termToN3(st.predicate, stats));
567
400
  }
568
-
569
- lastPred = st.predicate.uri;
570
- objects.push(objectTree(st.object, stats));
571
401
  }
572
-
573
- results = results.concat([objects]);
574
- return results;
575
402
  }
576
403
 
577
- var propertyTree = propertyTreeMethod.bind(this);
578
-
579
- function objectTreeMethod(obj, stats, force) {
580
- if (obj.termType === 'BlankNode' && (force || stats.rootsHash[obj.toNT()] === undefined)) {
581
- // if not a root
582
- if (stats.subjects[this.toStr(obj)]) {
583
- return ['[', propertyTree(obj, stats), ']'];
584
- } else {
585
- return '[]';
586
- }
587
- }
404
+ return str;
405
+ };
406
+
407
+ // //////////////////////////////////////////// Structure for N3
408
+ // Convert a set of statements into a nested tree of lists and strings
409
+ function statementListToTreeMethod(statements) {
410
+ var stats = this.rootSubjects(statements);
411
+ var roots = stats.roots;
412
+ var results = [];
413
+ for (var i = 0; i < roots.length; i++) {
414
+ var root = roots[i];
415
+ results.push(subjectTree(root, stats));
416
+ }
417
+ return results;
418
+ }
419
+ var statementListToTree = statementListToTreeMethod.bind(this);
588
420
 
589
- return termToN3(obj, stats);
421
+ // The tree for a subject
422
+ function subjectTree(subject, stats) {
423
+ if (subject.termType === 'BlankNode' && !stats.incoming[subject]) {
424
+ return objectTree(subject, stats, true).concat(['.']); // Anonymous bnode subject
590
425
  }
591
426
 
592
- var objectTree = objectTreeMethod.bind(this);
593
-
594
- function termToN3Method(expr, stats) {
595
- //
596
- var i, res;
597
-
598
- switch (expr.termType) {
599
- case 'Graph':
600
- res = ['{'];
601
- res = res.concat(statementListToTree(expr.statements));
602
- return res.concat(['}']);
603
-
604
- case 'Collection':
605
- res = ['('];
606
-
607
- for (i = 0; i < expr.elements.length; i++) {
608
- res.push([objectTree(expr.elements[i], stats)]);
609
- }
610
-
611
- res.push(')');
612
- return res;
613
-
614
- default:
615
- return this.atomicTermToN3(expr);
427
+ return [termToN3(subject, stats)].concat([propertyTree(subject, stats)]).concat(['.']);
428
+ }
429
+ // The property tree for a single subject or anonymous node
430
+ function propertyTreeMethod(subject, stats) {
431
+ var results = [];
432
+ var lastPred = null;
433
+ var sts = stats.subjects[this.toStr(subject)] || []; // relevant statements
434
+ if (typeof sts === 'undefined') {
435
+ throw new Error('Cant find statements for ' + subject);
436
+ }
437
+ var objects = [];
438
+ for (var i = 0; i < sts.length; i++) {
439
+ var st = sts[i];
440
+ if (st.predicate.uri === lastPred) {
441
+ objects.push(',');
442
+ } else {
443
+ if (lastPred) {
444
+ results = results.concat([objects]).concat([';']);
445
+ objects = [];
446
+ }
447
+ results.push(predMap[st.predicate.uri] ? predMap[st.predicate.uri] : termToN3(st.predicate, stats));
616
448
  }
449
+ lastPred = st.predicate.uri;
450
+ objects.push(objectTree(st.object, stats));
617
451
  }
618
-
619
- Serializer.prototype.termToN3 = termToN3;
620
- var termToN3 = termToN3Method.bind(this);
621
-
622
- function prefixDirectivesMethod() {
623
- var str = '';
624
-
625
- if (this.defaultNamespace) {
626
- str += '@prefix : ' + this.explicitURI(this.defaultNamespace) + '.\n';
627
- }
628
-
629
- for (var ns in this.prefixes) {
630
- if (!this.prefixes.hasOwnProperty(ns)) continue;
631
- if (!this.namespacesUsed[ns]) continue;
632
- str += '@prefix ' + this.prefixes[ns] + ': ' + this.explicitURI(ns) + '.\n';
452
+ results = results.concat([objects]);
453
+ return results;
454
+ }
455
+ var propertyTree = propertyTreeMethod.bind(this);
456
+ function objectTreeMethod(obj, stats, force) {
457
+ if (obj.termType === 'BlankNode' && (force || stats.rootsHash[obj.toNT()] === undefined)) {
458
+ // if not a root
459
+ if (stats.subjects[this.toStr(obj)]) {
460
+ return ['[', propertyTree(obj, stats), ']'];
461
+ } else {
462
+ return '[]';
633
463
  }
634
-
635
- return str + '\n';
636
464
  }
637
-
638
- var prefixDirectives = prefixDirectivesMethod.bind(this); // Body of statementsToN3:
639
-
640
- var tree = statementListToTree(sts);
641
- return prefixDirectives() + treeToString(tree);
642
- } // //////////////////////////////////////////// Atomic Terms
643
- // Deal with term level things and nesting with no bnode structure
644
-
645
- }, {
646
- key: "atomicTermToN3",
647
- value: function atomicTermToN3(expr, stats) {
465
+ return termToN3(obj, stats);
466
+ }
467
+ var objectTree = objectTreeMethod.bind(this);
468
+ function termToN3Method(expr, stats) {
469
+ //
470
+ var i, res;
648
471
  switch (expr.termType) {
649
- case 'BlankNode':
650
- case 'Variable':
651
- return expr.toNT();
652
-
653
- case 'Literal':
654
- var val = expr.value;
655
-
656
- if (typeof val !== 'string') {
657
- throw new TypeError('Value of RDF literal node must be a string');
658
- } // var val = expr.value.toString() // should be a string already
659
-
660
-
661
- if (expr.datatype && this.flags.indexOf('x') < 0) {
662
- // Supress native numbers
663
- switch (expr.datatype.uri) {
664
- case 'http://www.w3.org/2001/XMLSchema#integer':
665
- return val;
666
-
667
- case 'http://www.w3.org/2001/XMLSchema#decimal':
668
- // In Turtle, must have dot
669
- if (val.indexOf('.') < 0) val += '.0';
670
- return val;
671
-
672
- case 'http://www.w3.org/2001/XMLSchema#double':
673
- {
674
- // Must force use of 'e'
675
- var eNotation = val.toLowerCase().indexOf('e') > 0;
676
- if (val.indexOf('.') < 0 && !eNotation) val += '.0';
677
- if (!eNotation) val += 'e0';
678
- return val;
679
- }
680
-
681
- case 'http://www.w3.org/2001/XMLSchema#boolean':
682
- return expr.value === '1' ? 'true' : 'false';
683
- }
684
- }
685
-
686
- var str = this.stringToN3(expr.value);
687
-
688
- if (expr.language) {
689
- str += '@' + expr.language;
690
- } else if (!expr.datatype.equals(this.xsd.string)) {
691
- str += '^^' + this.atomicTermToN3(expr.datatype, stats);
472
+ case 'Graph':
473
+ res = ['{'];
474
+ res = res.concat(statementListToTree(expr.statements));
475
+ return res.concat(['}']);
476
+ case 'Collection':
477
+ res = ['('];
478
+ for (i = 0; i < expr.elements.length; i++) {
479
+ res.push([objectTree(expr.elements[i], stats)]);
692
480
  }
693
-
694
- return str;
695
-
696
- case 'NamedNode':
697
- return this.symbolToN3(expr);
698
-
699
- case 'DefaultGraph':
700
- return '';
701
-
481
+ res.push(')');
482
+ return res;
702
483
  default:
703
- throw new Error('Internal: atomicTermToN3 cannot handle ' + expr + ' of termType: ' + expr.termType);
484
+ return this.atomicTermToN3(expr);
704
485
  }
705
- } // stringToN3: String escaping for N3
706
-
707
- }, {
708
- key: "stringToN3",
709
- value: function stringToN3(str, flags) {
710
- if (!flags) flags = 'e';
711
- var res = '';
712
- var i, j, k;
713
- var delim;
714
- var forbidden;
715
-
716
- if (str.length > 20 && // Long enough to make sense
717
- str.slice(-1) !== '"' && // corner case'
718
- flags.indexOf('n') < 0 && ( // Force single line
719
- str.indexOf('\n') > 0 || str.indexOf('"') > 0)) {
720
- delim = '"""';
721
- forbidden = this.forbidden3;
722
- } else {
723
- delim = '"';
724
- forbidden = this.forbidden1;
486
+ }
487
+ Serializer.prototype.termToN3 = termToN3;
488
+ var termToN3 = termToN3Method.bind(this);
489
+ function prefixDirectivesMethod() {
490
+ var str = '';
491
+ if (this.defaultNamespace) {
492
+ str += '@prefix : ' + this.explicitURI(this.defaultNamespace) + '.\n';
725
493
  }
494
+ for (var ns in this.prefixes) {
495
+ if (!this.prefixes.hasOwnProperty(ns)) continue;
496
+ if (!this.namespacesUsed[ns]) continue;
497
+ str += '@prefix ' + this.prefixes[ns] + ': ' + this.explicitURI(ns) + '.\n';
498
+ }
499
+ return str + '\n';
500
+ }
501
+ var prefixDirectives = prefixDirectivesMethod.bind(this);
502
+ // Body of statementsToN3:
503
+ var tree = statementListToTree(sts);
504
+ return prefixDirectives() + treeToString(tree);
505
+ }
506
+ // //////////////////////////////////////////// Atomic Terms
507
+
508
+ // Deal with term level things and nesting with no bnode structure
509
+ atomicTermToN3(expr, stats) {
510
+ switch (expr.termType) {
511
+ case 'BlankNode':
512
+ case 'Variable':
513
+ return expr.toNT();
514
+ case 'Literal':
515
+ var val = expr.value;
516
+ if (typeof val !== 'string') {
517
+ throw new TypeError('Value of RDF literal node must be a string');
518
+ }
519
+ // var val = expr.value.toString() // should be a string already
520
+ if (expr.datatype && this.flags.indexOf('x') < 0) {
521
+ // Supress native numbers
522
+ switch (expr.datatype.uri) {
523
+ case 'http://www.w3.org/2001/XMLSchema#integer':
524
+ return val;
525
+ case 'http://www.w3.org/2001/XMLSchema#decimal':
526
+ // In Turtle, must have dot
527
+ if (val.indexOf('.') < 0) val += '.0';
528
+ return val;
529
+ case 'http://www.w3.org/2001/XMLSchema#double':
530
+ {
531
+ // Must force use of 'e'
532
+ const eNotation = val.toLowerCase().indexOf('e') > 0;
533
+ if (val.indexOf('.') < 0 && !eNotation) val += '.0';
534
+ if (!eNotation) val += 'e0';
535
+ return val;
536
+ }
537
+ case 'http://www.w3.org/2001/XMLSchema#boolean':
538
+ return expr.value === '1' ? 'true' : 'false';
539
+ }
540
+ }
541
+ var str = this.stringToN3(expr.value);
542
+ if (expr.language) {
543
+ str += '@' + expr.language;
544
+ } else if (!expr.datatype.equals(this.xsd.string)) {
545
+ str += '^^' + this.atomicTermToN3(expr.datatype, stats);
546
+ }
547
+ return str;
548
+ case 'NamedNode':
549
+ return this.symbolToN3(expr);
550
+ case 'DefaultGraph':
551
+ return '';
552
+ default:
553
+ throw new Error('Internal: atomicTermToN3 cannot handle ' + expr + ' of termType: ' + expr.termType);
554
+ }
555
+ }
726
556
 
727
- for (i = 0; i < str.length;) {
728
- forbidden.lastIndex = 0;
729
- var m = forbidden.exec(str.slice(i));
730
- if (m == null) break;
731
- j = i + forbidden.lastIndex - 1;
732
- res += str.slice(i, j);
733
- var ch = str[j];
734
-
735
- if (ch === '"' && delim === '"""' && str.slice(j, j + 3) !== '"""') {
736
- res += ch;
557
+ // stringToN3: String escaping for N3
558
+
559
+ stringToN3(str, flags) {
560
+ if (!flags) flags = 'e';
561
+ var res = '';
562
+ var i, j, k;
563
+ var delim;
564
+ var forbidden;
565
+ if (str.length > 20 &&
566
+ // Long enough to make sense
567
+ str.slice(-1) !== '"' &&
568
+ // corner case'
569
+ flags.indexOf('n') < 0 && (
570
+ // Force single line
571
+ str.indexOf('\n') > 0 || str.indexOf('"') > 0)) {
572
+ delim = '"""';
573
+ forbidden = this.forbidden3;
574
+ } else {
575
+ delim = '"';
576
+ forbidden = this.forbidden1;
577
+ }
578
+ for (i = 0; i < str.length;) {
579
+ forbidden.lastIndex = 0;
580
+ var m = forbidden.exec(str.slice(i));
581
+ if (m == null) break;
582
+ j = i + forbidden.lastIndex - 1;
583
+ res += str.slice(i, j);
584
+ var ch = str[j];
585
+ if (ch === '"' && delim === '"""' && str.slice(j, j + 3) !== '"""') {
586
+ res += ch;
587
+ } else {
588
+ k = '\b\f\r\t\v\n\\"'.indexOf(ch); // No escaping of bell (7)?
589
+ if (k >= 0) {
590
+ res += '\\' + 'bfrtvn\\"'[k];
737
591
  } else {
738
- k = '\b\f\r\t\v\n\\"'.indexOf(ch); // No escaping of bell (7)?
739
-
740
- if (k >= 0) {
741
- res += '\\' + 'bfrtvn\\"'[k];
592
+ if (flags.indexOf('e') >= 0) {
593
+ // Unicode escaping in strings not unix style
594
+ res += '\\u' + ('000' + ch.charCodeAt(0).toString(16).toLowerCase()).slice(-4);
742
595
  } else {
743
- if (flags.indexOf('e') >= 0) {
744
- // Unicode escaping in strings not unix style
745
- res += "\\u" + ('000' + ch.charCodeAt(0).toString(16).toLowerCase()).slice(-4);
746
- } else {
747
- // no 'e' flag
748
- res += ch;
749
- }
596
+ // no 'e' flag
597
+ res += ch;
750
598
  }
751
599
  }
752
-
753
- i = j + 1;
754
- }
755
-
756
- return delim + res + str.slice(i) + delim;
757
- } // A single symbol, either in <> or namespace notation
758
-
759
- }, {
760
- key: "symbolToN3",
761
- value: function symbolToN3(x) {
762
- // c.f. symbolString() in notation3.py
763
- var uri = x.uri;
764
- var j = uri.indexOf('#');
765
-
766
- if (j < 0 && this.flags.indexOf('/') < 0) {
767
- j = uri.lastIndexOf('/');
768
600
  }
769
-
770
- if (j >= 0 && this.flags.indexOf('p') < 0 && ( // Can split at namespace but only if http[s]: URI or file: or ws[s] (why not others?)
771
- uri.indexOf('http') === 0 || uri.indexOf('ws') === 0 || uri.indexOf('file') === 0)) {
772
- var canSplit = true;
773
-
774
- for (var k = j + 1; k < uri.length; k++) {
775
- if (this._notNameChars.indexOf(uri[k]) >= 0) {
776
- canSplit = false;
777
- break;
778
- }
779
- }
780
- /*
781
- if (uri.slice(0, j + 1) === this.base + '#') { // base-relative
782
- if (canSplit) {
783
- return ':' + uri.slice(j + 1) // assume deafult ns is local
784
- } else {
785
- return '<#' + uri.slice(j + 1) + '>'
786
- }
787
- }
788
- */
789
-
790
-
791
- if (canSplit) {
792
- var localid = uri.slice(j + 1);
793
- var namesp = uri.slice(0, j + 1);
794
-
795
- if (this.defaultNamespace && this.defaultNamespace === namesp && this.flags.indexOf('d') < 0) {
796
- // d -> suppress default
797
- if (this.flags.indexOf('k') >= 0 && this.keyords.indexOf(localid) < 0) {
798
- return localid;
799
- }
800
-
801
- return ':' + localid;
802
- } // this.checkIntegrity() // @@@ Remove when not testing
803
-
804
-
805
- var prefix = this.prefixes[namesp];
806
- if (!prefix) prefix = this.makeUpPrefix(namesp);
807
-
808
- if (prefix) {
809
- this.namespacesUsed[namesp] = true;
810
- return prefix + ':' + localid;
811
- } // Fall though if can't do qname
812
-
601
+ i = j + 1;
602
+ }
603
+ return delim + res + str.slice(i) + delim;
604
+ }
605
+ // A single symbol, either in <> or namespace notation
606
+
607
+ symbolToN3(x) {
608
+ // c.f. symbolString() in notation3.py
609
+ var uri = x.uri;
610
+ var j = uri.indexOf('#');
611
+ if (j < 0 && this.flags.indexOf('/') < 0) {
612
+ j = uri.lastIndexOf('/');
613
+ }
614
+ if (j >= 0 && this.flags.indexOf('p') < 0 && (
615
+ // Can split at namespace but only if http[s]: URI or file: or ws[s] (why not others?)
616
+ uri.indexOf('http') === 0 || uri.indexOf('ws') === 0 || uri.indexOf('file') === 0)) {
617
+ var canSplit = true;
618
+ for (var k = j + 1; k < uri.length; k++) {
619
+ if (this._notNameChars.indexOf(uri[k]) >= 0) {
620
+ canSplit = false;
621
+ break;
813
622
  }
814
623
  }
815
-
816
- return this.explicitURI(uri);
817
- } // /////////////////////////// Quad store serialization
818
- // @para. write - a function taking a single string to be output
819
- //
820
-
821
- }, {
822
- key: "writeStore",
823
- value: function writeStore(write) {
824
- var kb = this.store;
825
- var fetcher = kb.fetcher;
826
- var session = fetcher && fetcher.appNode; // The core data
827
-
828
- var sources = this.store.index[3];
829
-
830
- for (var s in sources) {
831
- // -> assume we can use -> as short for log:semantics
832
- var source = kb.fromNT(s);
833
- if (session && source.equals(session)) continue;
834
- write('\n' + this.atomicTermToN3(source) + ' ' + this.atomicTermToN3(kb.sym('http://www.w3.org/2000/10/swap/log#semantics')) + ' { ' + this.statementsToN3(kb.statementsMatching(undefined, undefined, undefined, source)) + ' }.\n');
835
- } // The metadata from HTTP interactions:
836
-
837
-
838
- kb.statementsMatching(undefined, kb.sym('http://www.w3.org/2007/ont/link#requestedURI')).map(function (st) {
839
- write('\n<' + st.object.value + '> log:metadata {\n');
840
- var sts = kb.statementsMatching(undefined, undefined, undefined, st.subject);
841
- write(this.statementsToN3(this.statementsToN3(sts)));
842
- write('}.\n');
843
- }); // Inferences we have made ourselves not attributable to anyone else
844
-
845
- var metaSources = [];
846
- if (session) metaSources.push(session);
847
- var metadata = [];
848
- metaSources.map(function (source) {
849
- metadata = metadata.concat(kb.statementsMatching(undefined, undefined, undefined, source));
850
- });
851
- write(this.statementsToN3(metadata));
852
- } // ////////////////////////////////////////////// XML serialization
853
-
854
- }, {
855
- key: "statementsToXML",
856
- value: function statementsToXML(sts) {
857
- var indent = 4;
858
- var width = 80;
859
- var namespaceCounts = []; // which have been used
860
-
861
- namespaceCounts['http://www.w3.org/1999/02/22-rdf-syntax-ns#'] = true;
862
- var liPrefix = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#_'; // prefix for ordered list items
863
- // //////////////////////// Arrange the bits of XML text
864
-
865
- var spaces = function spaces(n) {
866
- var s = '';
867
-
868
- for (var i = 0; i < n; i++) {
869
- s += ' ';
870
- }
871
-
872
- return s;
873
- };
874
-
875
- var XMLtreeToLine = function XMLtreeToLine(tree) {
876
- var str = '';
877
-
878
- for (var i = 0; i < tree.length; i++) {
879
- var branch = tree[i];
880
- var s2 = typeof branch === 'string' ? branch : XMLtreeToLine(branch);
881
- str += s2;
882
- }
883
-
884
- return str;
885
- }; // Convert a nested tree of lists and strings to a string
886
-
887
-
888
- var XMLtreeToString = function XMLtreeToString(tree, level) {
889
- var str = '';
890
- var line;
891
- var lastLength = 100000;
892
- if (!level) level = 0;
893
-
894
- for (var i = 0; i < tree.length; i++) {
895
- var branch = tree[i];
896
-
897
- if (typeof branch !== 'string') {
898
- var substr = XMLtreeToString(branch, level + 1);
899
-
900
- if (substr.length < 10 * (width - indent * level) && substr.indexOf('"""') < 0) {
901
- // Don't mess up multiline strings
902
- line = XMLtreeToLine(branch);
903
-
904
- if (line.length < width - indent * level) {
905
- branch = ' ' + line; // @@ Hack: treat as string below
906
-
907
- substr = '';
624
+ /*
625
+ if (uri.slice(0, j + 1) === this.base + '#') { // base-relative
626
+ if (canSplit) {
627
+ return ':' + uri.slice(j + 1) // assume deafult ns is local
628
+ } else {
629
+ return '<#' + uri.slice(j + 1) + '>'
908
630
  }
909
631
  }
910
-
911
- if (substr) lastLength = 10000;
912
- str += substr;
913
- }
914
-
915
- if (typeof branch === 'string') {
916
- if (lastLength < indent * level + 4) {
917
- // continue
918
- str = str.slice(0, -1) + ' ' + branch + '\n';
919
- lastLength += branch.length + 1;
920
- } else {
921
- line = spaces(indent * level) + branch;
922
- str += line + '\n';
923
- lastLength = line.length;
924
- }
925
- } else {// not string
632
+ */
633
+ if (canSplit) {
634
+ var localid = uri.slice(j + 1);
635
+ var namesp = uri.slice(0, j + 1);
636
+ if (this.defaultNamespace && this.defaultNamespace === namesp && this.flags.indexOf('d') < 0) {
637
+ // d -> suppress default
638
+ if (this.flags.indexOf('k') >= 0 && this.keyords.indexOf(localid) < 0) {
639
+ return localid;
926
640
  }
641
+ return ':' + localid;
927
642
  }
928
-
929
- return str;
930
- };
931
-
932
- function statementListToXMLTreeMethod(statements) {
933
- this.suggestPrefix('rdf', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#');
934
- var stats = this.rootSubjects(statements);
935
- var roots = stats.roots;
936
- var results = [];
937
-
938
- for (var i = 0; i < roots.length; i++) {
939
- var root = roots[i];
940
- results.push(subjectXMLTree(root, stats));
643
+ // this.checkIntegrity() // @@@ Remove when not testing
644
+ var prefix = this.prefixes[namesp];
645
+ if (!prefix) prefix = this.makeUpPrefix(namesp);
646
+ if (prefix) {
647
+ this.namespacesUsed[namesp] = true;
648
+ return prefix + ':' + localid;
941
649
  }
942
-
943
- return results;
944
- }
945
-
946
- var statementListToXMLTree = statementListToXMLTreeMethod.bind(this);
947
-
948
- function escapeForXML(str) {
949
- if (typeof str === 'undefined') return '@@@undefined@@@@';
950
- return str.replace(/[&<"]/g, function (m) {
951
- switch (m[0]) {
952
- case '&':
953
- return '&amp;';
954
-
955
- case '<':
956
- return '&lt;';
957
-
958
- case '"':
959
- return '&quot;';
960
- // '
961
- }
962
- });
963
- }
964
-
965
- function relURIMethod(term) {
966
- return escapeForXML(this.base ? Util.uri.refTo(this.base, term.uri) : term.uri);
650
+ // Fall though if can't do qname
967
651
  }
652
+ }
968
653
 
969
- var relURI = relURIMethod.bind(this); // The tree for a subject
970
-
971
- function subjectXMLTreeMethod(subject, stats) {
972
- var results = [];
973
- var type, t, st, pred;
974
- var sts = stats.subjects[this.toStr(subject)]; // relevant statements
975
-
976
- if (typeof sts === 'undefined') {
977
- // empty bnode
978
- return propertyXMLTree(subject, stats);
979
- } // Sort only on the predicate, leave the order at object
980
- // level undisturbed. This leaves multilingual content in
981
- // the order of entry (for partner literals), which helps
982
- // readability.
983
- //
984
- // For the predicate sort, we attempt to split the uri
985
- // as a hint to the sequence
654
+ return this.explicitURI(uri);
655
+ }
986
656
 
657
+ // /////////////////////////// Quad store serialization
987
658
 
988
- sts.sort(function (a, b) {
989
- var ap = a.predicate.uri;
990
- var bp = b.predicate.uri;
659
+ // @para. write - a function taking a single string to be output
660
+ //
661
+ writeStore(write) {
662
+ var kb = this.store;
663
+ var fetcher = kb.fetcher;
664
+ var session = fetcher && fetcher.appNode;
991
665
 
992
- if (ap.substring(0, liPrefix.length) === liPrefix || bp.substring(0, liPrefix.length) === liPrefix) {
993
- // we're only interested in sorting list items
994
- return ap.localeCompare(bp);
995
- }
666
+ // The core data
996
667
 
997
- var as = ap.substring(liPrefix.length);
998
- var bs = bp.substring(liPrefix.length);
999
- var an = parseInt(as, 10);
1000
- var bn = parseInt(bs, 10);
668
+ var sources = this.store.index[3];
669
+ for (var s in sources) {
670
+ // -> assume we can use -> as short for log:semantics
671
+ var source = kb.fromNT(s);
672
+ if (session && source.equals(session)) continue;
673
+ write('\n' + this.atomicTermToN3(source) + ' ' + this.atomicTermToN3(kb.sym('http://www.w3.org/2000/10/swap/log#semantics')) + ' { ' + this.statementsToN3(kb.statementsMatching(undefined, undefined, undefined, source)) + ' }.\n');
674
+ }
1001
675
 
1002
- if (isNaN(an) || isNaN(bn) || an !== as || bn !== bs) {
1003
- // we only care about integers
1004
- return ap.localeCompare(bp);
1005
- }
676
+ // The metadata from HTTP interactions:
1006
677
 
1007
- return an - bn;
1008
- });
678
+ kb.statementsMatching(undefined, kb.sym('http://www.w3.org/2007/ont/link#requestedURI')).map(function (st) {
679
+ write('\n<' + st.object.value + '> log:metadata {\n');
680
+ var sts = kb.statementsMatching(undefined, undefined, undefined, st.subject);
681
+ write(this.statementsToN3(this.statementsToN3(sts)));
682
+ write('}.\n');
683
+ });
1009
684
 
1010
- for (var i = 0; i < sts.length; i++) {
1011
- st = sts[i]; // look for a type
685
+ // Inferences we have made ourselves not attributable to anyone else
1012
686
 
1013
- if (st.predicate.uri === 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' && !type && st.object.termType === 'NamedNode') {
1014
- type = st.object;
1015
- continue; // don't include it as a child element
1016
- } // see whether predicate can be replaced with "li"
687
+ var metaSources = [];
688
+ if (session) metaSources.push(session);
689
+ var metadata = [];
690
+ metaSources.map(function (source) {
691
+ metadata = metadata.concat(kb.statementsMatching(undefined, undefined, undefined, source));
692
+ });
693
+ write(this.statementsToN3(metadata));
694
+ }
1017
695
 
696
+ // ////////////////////////////////////////////// XML serialization
1018
697
 
1019
- pred = st.predicate;
698
+ statementsToXML(sts) {
699
+ var indent = 4;
700
+ var width = 80;
701
+ var namespaceCounts = []; // which have been used
702
+ namespaceCounts['http://www.w3.org/1999/02/22-rdf-syntax-ns#'] = true;
703
+ var liPrefix = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#_'; // prefix for ordered list items
1020
704
 
1021
- if (pred.uri.substr(0, liPrefix.length) === liPrefix) {
1022
- var number = pred.uri.substr(liPrefix.length); // make sure these are actually numeric list items
705
+ // //////////////////////// Arrange the bits of XML text
1023
706
 
1024
- var intNumber = parseInt(number, 10);
707
+ var spaces = function (n) {
708
+ var s = '';
709
+ for (var i = 0; i < n; i++) s += ' ';
710
+ return s;
711
+ };
712
+ var XMLtreeToLine = function (tree) {
713
+ var str = '';
714
+ for (var i = 0; i < tree.length; i++) {
715
+ var branch = tree[i];
716
+ var s2 = typeof branch === 'string' ? branch : XMLtreeToLine(branch);
717
+ str += s2;
718
+ }
719
+ return str;
720
+ };
1025
721
 
1026
- if (number === intNumber.toString()) {
1027
- // was numeric; don't need to worry about ordering since we've already
1028
- // sorted the statements
1029
- pred = this.rdfFactory.namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#li');
722
+ // Convert a nested tree of lists and strings to a string
723
+ var XMLtreeToString = function (tree, level) {
724
+ var str = '';
725
+ var line;
726
+ var lastLength = 100000;
727
+ if (!level) level = 0;
728
+ for (var i = 0; i < tree.length; i++) {
729
+ var branch = tree[i];
730
+ if (typeof branch !== 'string') {
731
+ var substr = XMLtreeToString(branch, level + 1);
732
+ if (substr.length < 10 * (width - indent * level) && substr.indexOf('"""') < 0) {
733
+ // Don't mess up multiline strings
734
+ line = XMLtreeToLine(branch);
735
+ if (line.length < width - indent * level) {
736
+ branch = ' ' + line; // @@ Hack: treat as string below
737
+ substr = '';
1030
738
  }
1031
739
  }
1032
-
1033
- t = qname(pred);
1034
-
1035
- switch (st.object.termType) {
1036
- case 'BlankNode':
1037
- if (stats.incoming[st.object].length === 1) {
1038
- // there should always be something in the incoming array for a bnode
1039
- results = results.concat(['<' + t + ' rdf:parseType="Resource">', subjectXMLTree(st.object, stats), '</' + t + '>']);
1040
- } else {
1041
- results = results.concat(['<' + t + ' rdf:nodeID="' + st.object.toNT().slice(2) + '"/>']);
1042
- }
1043
-
1044
- break;
1045
-
1046
- case 'NamedNode':
1047
- results = results.concat(['<' + t + ' rdf:resource="' + relURI(st.object) + '"/>']);
1048
- break;
1049
-
1050
- case 'Literal':
1051
- results = results.concat(['<' + t + (st.object.datatype.equals(this.xsd.string) ? '' : ' rdf:datatype="' + escapeForXML(st.object.datatype.uri) + '"') + (st.object.language ? ' xml:lang="' + st.object.language + '"' : '') + '>' + escapeForXML(st.object.value) + '</' + t + '>']);
1052
- break;
1053
-
1054
- case 'Collection':
1055
- results = results.concat(['<' + t + ' rdf:parseType="Collection">', collectionXMLTree(st.object, stats), '</' + t + '>']);
1056
- break;
1057
-
1058
- default:
1059
- throw new Error("Can't serialize object of type " + st.object.termType + ' into XML');
1060
- } // switch
1061
-
1062
- }
1063
-
1064
- var tag = type ? qname(type) : 'rdf:Description';
1065
- var attrs = '';
1066
-
1067
- if (subject.termType === 'BlankNode') {
1068
- if (!stats.incoming[subject] || stats.incoming[subject].length !== 1) {
1069
- // not an anonymous bnode
1070
- attrs = ' rdf:nodeID="' + subject.toNT().slice(2) + '"';
740
+ if (substr) lastLength = 10000;
741
+ str += substr;
742
+ }
743
+ if (typeof branch === 'string') {
744
+ if (lastLength < indent * level + 4) {
745
+ // continue
746
+ str = str.slice(0, -1) + ' ' + branch + '\n';
747
+ lastLength += branch.length + 1;
748
+ } else {
749
+ line = spaces(indent * level) + branch;
750
+ str += line + '\n';
751
+ lastLength = line.length;
1071
752
  }
1072
- } else {
1073
- attrs = ' rdf:about="' + relURI(subject) + '"';
753
+ } else {// not string
1074
754
  }
1075
-
1076
- return ['<' + tag + attrs + '>'].concat([results]).concat(['</' + tag + '>']);
1077
- }
1078
-
1079
- var subjectXMLTree = subjectXMLTreeMethod.bind(this);
1080
-
1081
- function collectionXMLTree(subject, stats) {
1082
- var res = [];
1083
-
1084
- for (var i = 0; i < subject.elements.length; i++) {
1085
- res.push(subjectXMLTree(subject.elements[i], stats));
1086
- }
1087
-
1088
- return res;
1089
- } // The property tree for a single subject or anonymos node
1090
-
1091
-
1092
- function propertyXMLTreeMethod(subject, stats) {
1093
- var results = [];
1094
- var sts = stats.subjects[this.toStr(subject)]; // relevant statements
1095
-
1096
- if (!sts) return results; // No relevant statements
1097
-
1098
- sts.sort();
1099
-
1100
- for (var i = 0; i < sts.length; i++) {
1101
- var st = sts[i];
1102
-
1103
- switch (st.object.termType) {
1104
- case 'BlankNode':
1105
- if (stats.rootsHash[st.object.toNT()]) {
1106
- // This bnode has been done as a root -- no content here @@ what bout first time
1107
- results = results.concat(['<' + qname(st.predicate) + ' rdf:nodeID="' + st.object.toNT().slice(2) + '">', '</' + qname(st.predicate) + '>']);
1108
- } else {
1109
- results = results.concat(['<' + qname(st.predicate) + ' rdf:parseType="Resource">', propertyXMLTree(st.object, stats), '</' + qname(st.predicate) + '>']);
1110
- }
1111
-
1112
- break;
1113
-
1114
- case 'NamedNode':
1115
- results = results.concat(['<' + qname(st.predicate) + ' rdf:resource="' + relURI(st.object) + '"/>']);
1116
- break;
1117
-
1118
- case 'Literal':
1119
- results = results.concat(['<' + qname(st.predicate) + (st.object.datatype.equals(this.xsd.string) ? '' : ' rdf:datatype="' + escapeForXML(st.object.datatype.value) + '"') + (st.object.language ? ' xml:lang="' + st.object.language + '"' : '') + '>' + escapeForXML(st.object.value) + '</' + qname(st.predicate) + '>']);
1120
- break;
1121
-
1122
- case 'Collection':
1123
- results = results.concat(['<' + qname(st.predicate) + ' rdf:parseType="Collection">', collectionXMLTree(st.object, stats), '</' + qname(st.predicate) + '>']);
1124
- break;
1125
-
1126
- default:
1127
- throw new Error("Can't serialize object of type " + st.object.termType + ' into XML');
1128
- } // switch
1129
-
1130
- }
1131
-
1132
- return results;
1133
755
  }
1134
-
1135
- var propertyXMLTree = propertyXMLTreeMethod.bind(this);
1136
-
1137
- function qnameMethod(term) {
1138
- var uri = term.uri;
1139
- var j = uri.indexOf('#');
1140
-
1141
- if (j < 0 && this.flags.indexOf('/') < 0) {
1142
- j = uri.lastIndexOf('/');
756
+ return str;
757
+ };
758
+ function statementListToXMLTreeMethod(statements) {
759
+ this.suggestPrefix('rdf', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#');
760
+ var stats = this.rootSubjects(statements);
761
+ var roots = stats.roots;
762
+ var results = [];
763
+ for (var i = 0; i < roots.length; i++) {
764
+ var root = roots[i];
765
+ results.push(subjectXMLTree(root, stats));
766
+ }
767
+ return results;
768
+ }
769
+ var statementListToXMLTree = statementListToXMLTreeMethod.bind(this);
770
+ function escapeForXML(str) {
771
+ if (typeof str === 'undefined') return '@@@undefined@@@@';
772
+ return str.replace(/[&<"]/g, function (m) {
773
+ switch (m[0]) {
774
+ case '&':
775
+ return '&amp;';
776
+ case '<':
777
+ return '&lt;';
778
+ case '"':
779
+ return '&quot;';
780
+ // '
1143
781
  }
782
+ });
783
+ }
1144
784
 
1145
- if (j < 0) throw new Error('Cannot make qname out of <' + uri + '>');
1146
-
1147
- for (var k = j + 1; k < uri.length; k++) {
1148
- if (this._notNameChars.indexOf(uri[k]) >= 0) {
1149
- throw new Error('Invalid character "' + uri[k] + '" cannot be in XML qname for URI: ' + uri);
785
+ function relURIMethod(term) {
786
+ return escapeForXML(this.base ? Util.uri.refTo(this.base, term.uri) : term.uri);
787
+ }
788
+ var relURI = relURIMethod.bind(this);
789
+
790
+ // The tree for a subject
791
+ function subjectXMLTreeMethod(subject, stats) {
792
+ var results = [];
793
+ var type, t, st, pred;
794
+ var sts = stats.subjects[this.toStr(subject)]; // relevant statements
795
+ if (typeof sts === 'undefined') {
796
+ // empty bnode
797
+ return propertyXMLTree(subject, stats);
798
+ }
799
+
800
+ // Sort only on the predicate, leave the order at object
801
+ // level undisturbed. This leaves multilingual content in
802
+ // the order of entry (for partner literals), which helps
803
+ // readability.
804
+ //
805
+ // For the predicate sort, we attempt to split the uri
806
+ // as a hint to the sequence
807
+ sts.sort(function (a, b) {
808
+ var ap = a.predicate.uri;
809
+ var bp = b.predicate.uri;
810
+ if (ap.substring(0, liPrefix.length) === liPrefix || bp.substring(0, liPrefix.length) === liPrefix) {
811
+ // we're only interested in sorting list items
812
+ return ap.localeCompare(bp);
813
+ }
814
+ var as = ap.substring(liPrefix.length);
815
+ var bs = bp.substring(liPrefix.length);
816
+ var an = parseInt(as, 10);
817
+ var bn = parseInt(bs, 10);
818
+ if (isNaN(an) || isNaN(bn) || an !== as || bn !== bs) {
819
+ // we only care about integers
820
+ return ap.localeCompare(bp);
821
+ }
822
+ return an - bn;
823
+ });
824
+ for (var i = 0; i < sts.length; i++) {
825
+ st = sts[i];
826
+ // look for a type
827
+ if (st.predicate.uri === 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' && !type && st.object.termType === 'NamedNode') {
828
+ type = st.object;
829
+ continue; // don't include it as a child element
830
+ }
831
+
832
+ // see whether predicate can be replaced with "li"
833
+ pred = st.predicate;
834
+ if (pred.uri.substr(0, liPrefix.length) === liPrefix) {
835
+ var number = pred.uri.substr(liPrefix.length);
836
+ // make sure these are actually numeric list items
837
+ var intNumber = parseInt(number, 10);
838
+ if (number === intNumber.toString()) {
839
+ // was numeric; don't need to worry about ordering since we've already
840
+ // sorted the statements
841
+ pred = this.rdfFactory.namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#li');
1150
842
  }
1151
843
  }
844
+ t = qname(pred);
845
+ switch (st.object.termType) {
846
+ case 'BlankNode':
847
+ if (stats.incoming[st.object].length === 1) {
848
+ // there should always be something in the incoming array for a bnode
849
+ results = results.concat(['<' + t + ' rdf:parseType="Resource">', subjectXMLTree(st.object, stats), '</' + t + '>']);
850
+ } else {
851
+ results = results.concat(['<' + t + ' rdf:nodeID="' + st.object.toNT().slice(2) + '"/>']);
852
+ }
853
+ break;
854
+ case 'NamedNode':
855
+ results = results.concat(['<' + t + ' rdf:resource="' + relURI(st.object) + '"/>']);
856
+ break;
857
+ case 'Literal':
858
+ results = results.concat(['<' + t + (st.object.datatype.equals(this.xsd.string) ? '' : ' rdf:datatype="' + escapeForXML(st.object.datatype.uri) + '"') + (st.object.language ? ' xml:lang="' + st.object.language + '"' : '') + '>' + escapeForXML(st.object.value) + '</' + t + '>']);
859
+ break;
860
+ case 'Collection':
861
+ results = results.concat(['<' + t + ' rdf:parseType="Collection">', collectionXMLTree(st.object, stats), '</' + t + '>']);
862
+ break;
863
+ default:
864
+ throw new Error("Can't serialize object of type " + st.object.termType + ' into XML');
865
+ } // switch
866
+ }
1152
867
 
1153
- var localid = uri.slice(j + 1);
1154
- var namesp = uri.slice(0, j + 1);
1155
-
1156
- if (this.defaultNamespace && this.defaultNamespace === namesp && this.flags.indexOf('d') < 0) {
1157
- // d -> suppress default
1158
- return localid;
868
+ var tag = type ? qname(type) : 'rdf:Description';
869
+ var attrs = '';
870
+ if (subject.termType === 'BlankNode') {
871
+ if (!stats.incoming[subject] || stats.incoming[subject].length !== 1) {
872
+ // not an anonymous bnode
873
+ attrs = ' rdf:nodeID="' + subject.toNT().slice(2) + '"';
1159
874
  }
1160
-
1161
- var prefix = this.prefixes[namesp];
1162
- if (!prefix) prefix = this.makeUpPrefix(namesp);
1163
- namespaceCounts[namesp] = true;
1164
- return prefix + ':' + localid;
875
+ } else {
876
+ attrs = ' rdf:about="' + relURI(subject) + '"';
1165
877
  }
1166
-
1167
- var qname = qnameMethod.bind(this); // Body of toXML:
1168
-
1169
- var tree = statementListToXMLTree(sts);
1170
- var str = '<rdf:RDF';
1171
-
1172
- if (this.defaultNamespace) {
1173
- str += ' xmlns="' + escapeForXML(this.defaultNamespace) + '"';
878
+ return ['<' + tag + attrs + '>'].concat([results]).concat(['</' + tag + '>']);
879
+ }
880
+ var subjectXMLTree = subjectXMLTreeMethod.bind(this);
881
+ function collectionXMLTree(subject, stats) {
882
+ var res = [];
883
+ for (var i = 0; i < subject.elements.length; i++) {
884
+ res.push(subjectXMLTree(subject.elements[i], stats));
1174
885
  }
886
+ return res;
887
+ }
1175
888
 
1176
- for (var ns in namespaceCounts) {
1177
- if (!namespaceCounts.hasOwnProperty(ns)) continue; // Rel uris in xml ns is not strictly allowed in the XMLNS spec but needed in practice often
1178
-
1179
- var ns2 = this.base && this.flags.includes('z') ? Util.uri.refTo(this.base, ns) : ns;
1180
- str += '\n xmlns:' + this.prefixes[ns] + '="' + escapeForXML(ns2) + '"';
889
+ // The property tree for a single subject or anonymos node
890
+ function propertyXMLTreeMethod(subject, stats) {
891
+ var results = [];
892
+ var sts = stats.subjects[this.toStr(subject)]; // relevant statements
893
+ if (!sts) return results; // No relevant statements
894
+ sts.sort();
895
+ for (var i = 0; i < sts.length; i++) {
896
+ var st = sts[i];
897
+ switch (st.object.termType) {
898
+ case 'BlankNode':
899
+ if (stats.rootsHash[st.object.toNT()]) {
900
+ // This bnode has been done as a root -- no content here @@ what bout first time
901
+ results = results.concat(['<' + qname(st.predicate) + ' rdf:nodeID="' + st.object.toNT().slice(2) + '">', '</' + qname(st.predicate) + '>']);
902
+ } else {
903
+ results = results.concat(['<' + qname(st.predicate) + ' rdf:parseType="Resource">', propertyXMLTree(st.object, stats), '</' + qname(st.predicate) + '>']);
904
+ }
905
+ break;
906
+ case 'NamedNode':
907
+ results = results.concat(['<' + qname(st.predicate) + ' rdf:resource="' + relURI(st.object) + '"/>']);
908
+ break;
909
+ case 'Literal':
910
+ results = results.concat(['<' + qname(st.predicate) + (st.object.datatype.equals(this.xsd.string) ? '' : ' rdf:datatype="' + escapeForXML(st.object.datatype.value) + '"') + (st.object.language ? ' xml:lang="' + st.object.language + '"' : '') + '>' + escapeForXML(st.object.value) + '</' + qname(st.predicate) + '>']);
911
+ break;
912
+ case 'Collection':
913
+ results = results.concat(['<' + qname(st.predicate) + ' rdf:parseType="Collection">', collectionXMLTree(st.object, stats), '</' + qname(st.predicate) + '>']);
914
+ break;
915
+ default:
916
+ throw new Error("Can't serialize object of type " + st.object.termType + ' into XML');
917
+ } // switch
1181
918
  }
1182
919
 
1183
- str += '>';
1184
- var tree2 = [str, tree, '</rdf:RDF>']; // @@ namespace declrations
920
+ return results;
921
+ }
922
+ var propertyXMLTree = propertyXMLTreeMethod.bind(this);
923
+ function qnameMethod(term) {
924
+ var uri = term.uri;
925
+ var j = uri.indexOf('#');
926
+ if (j < 0 && this.flags.indexOf('/') < 0) {
927
+ j = uri.lastIndexOf('/');
928
+ }
929
+ if (j < 0) throw new Error('Cannot make qname out of <' + uri + '>');
930
+ for (var k = j + 1; k < uri.length; k++) {
931
+ if (this._notNameChars.indexOf(uri[k]) >= 0) {
932
+ throw new Error('Invalid character "' + uri[k] + '" cannot be in XML qname for URI: ' + uri);
933
+ }
934
+ }
935
+ var localid = uri.slice(j + 1);
936
+ var namesp = uri.slice(0, j + 1);
937
+ if (this.defaultNamespace && this.defaultNamespace === namesp && this.flags.indexOf('d') < 0) {
938
+ // d -> suppress default
939
+ return localid;
940
+ }
941
+ var prefix = this.prefixes[namesp];
942
+ if (!prefix) prefix = this.makeUpPrefix(namesp);
943
+ namespaceCounts[namesp] = true;
944
+ return prefix + ':' + localid;
945
+ }
946
+ var qname = qnameMethod.bind(this);
1185
947
 
1186
- return XMLtreeToString(tree2, -1);
1187
- } // End @@ body
948
+ // Body of toXML:
1188
949
 
1189
- }]);
950
+ var tree = statementListToXMLTree(sts);
951
+ var str = '<rdf:RDF';
952
+ if (this.defaultNamespace) {
953
+ str += ' xmlns="' + escapeForXML(this.defaultNamespace) + '"';
954
+ }
955
+ for (var ns in namespaceCounts) {
956
+ if (!namespaceCounts.hasOwnProperty(ns)) continue;
957
+ // Rel uris in xml ns is not strictly allowed in the XMLNS spec but needed in practice often
958
+ var ns2 = this.base && this.flags.includes('z') ? Util.uri.refTo(this.base, ns) : ns;
959
+ str += '\n xmlns:' + this.prefixes[ns] + '="' + escapeForXML(ns2) + '"';
960
+ }
961
+ str += '>';
962
+ var tree2 = [str, tree, '</rdf:RDF>']; // @@ namespace declrations
963
+ return XMLtreeToString(tree2, -1);
964
+ } // End @@ body
965
+ }
1190
966
 
1191
- return Serializer;
1192
- }(); // String escaping utilities
967
+ // String escaping utilities
1193
968
 
1194
969
  function hexify(str) {
1195
970
  // also used in parser
1196
971
  return encodeURI(str);
1197
972
  }
1198
-
1199
973
  function backslashUify(str) {
1200
974
  var res = '';
1201
975
  var k;
1202
-
1203
976
  for (var i = 0; i < str.length; i++) {
1204
977
  k = str.charCodeAt(i);
1205
-
1206
978
  if (k > 65535) {
1207
- res += "\\U" + ('00000000' + k.toString(16)).slice(-8); // convert to upper?
979
+ res += '\\U' + ('00000000' + k.toString(16)).slice(-8); // convert to upper?
1208
980
  } else if (k > 126) {
1209
- res += "\\u" + ('0000' + k.toString(16)).slice(-4);
981
+ res += '\\u' + ('0000' + k.toString(16)).slice(-4);
1210
982
  } else {
1211
983
  res += str[i];
1212
984
  }
1213
985
  }
1214
-
1215
986
  return res;
1216
987
  }