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