--- a/playground/jsonld.js Fri Jan 25 10:40:35 2013 -0500
+++ b/playground/jsonld.js Fri Jan 25 15:36:28 2013 -0500
@@ -50,6 +50,8 @@
* [strict] use strict mode (default: true).
* [optimize] true to optimize the compaction (default: false).
* [graph] true to always output a top-level graph (default: false).
+ * [skipExpansion] true to assume the input is expanded and skip
+ * expansion, false not to, defaults to false.
* [resolver(url, callback(err, jsonCtx))] the URL resolver to use.
* @param callback(err, compacted, ctx) called once the operation completes.
*/
@@ -81,12 +83,22 @@
if(!('graph' in options)) {
options.graph = false;
}
+ if(!('skipExpansion' in options)) {
+ options.skipExpansion = false;
+ }
if(!('resolver' in options)) {
options.resolver = jsonld.urlResolver;
}
+ var expand = function(input, options, callback) {
+ if(options.skipExpansion) {
+ return callback(null, input);
+ }
+ jsonld.expand(input, options, callback);
+ };
+
// expand input then do compaction
- jsonld.expand(input, options, function(err, expanded) {
+ expand(input, options, function(err, expanded) {
if(err) {
return callback(new JsonLdError(
'Could not expand input before compaction.',
@@ -109,9 +121,8 @@
}
// do compaction
- input = expanded;
var compacted = new Processor().compact(
- activeCtx, null, input, options);
+ activeCtx, null, expanded, options);
cleanup(null, compacted, activeCtx, options);
}
catch(ex) {
@@ -316,8 +327,9 @@
return callback(null, flattened);
}
- // compact result (force @graph option to true)
+ // compact result (force @graph option to true, skip expansion)
options.graph = true;
+ options.skipExpansion = true;
jsonld.compact(flattened, ctx, options, function(err, compacted, ctx) {
if(err) {
return callback(new JsonLdError(
@@ -400,8 +412,9 @@
return callback(ex);
}
- // compact result (force @graph option to true)
+ // compact result (force @graph option to true, skip expansion)
opts.graph = true;
+ opts.skipExpansion = true;
jsonld.compact(framed, ctx, opts, function(err, compacted, ctx) {
if(err) {
return callback(new JsonLdError(
@@ -462,8 +475,9 @@
return callback(ex);
}
- // compact result (force @graph option to true)
+ // compact result (force @graph option to true, skip expansion)
options.graph = true;
+ options.skipExpansion = true;
jsonld.compact(flattened, ctx, options, function(err, compacted, ctx) {
if(err) {
return callback(new JsonLdError(
@@ -799,6 +813,47 @@
};
/**
+ * Creates an active context cache.
+ *
+ * @param size the maximum size of the cache.
+ */
+jsonld.ActiveContextCache = function(size) {
+ this.order = [];
+ this.cache = {};
+ this.size = size || 100;
+};
+jsonld.ActiveContextCache.prototype.get = function(activeCtx, localCtx) {
+ var key1 = JSON.stringify(activeCtx);
+ var key2 = JSON.stringify(localCtx);
+ var level1 = this.cache[key1];
+ if(level1 && key2 in level1) {
+ return level1[key2];
+ }
+ return null;
+};
+jsonld.ActiveContextCache.prototype.set = function(
+ activeCtx, localCtx, result) {
+ if(this.order.length === this.size) {
+ var entry = this.order.shift();
+ delete this.cache[entry.activeCtx][entry.localCtx];
+ }
+ var key1 = JSON.stringify(activeCtx);
+ var key2 = JSON.stringify(localCtx);
+ this.order.push({activeCtx: key1, localCtx: key2});
+ if(!(key1 in this.cache)) {
+ this.cache[key1] = {};
+ }
+ this.cache[key1][key2] = result;
+};
+
+/**
+ * Default JSON-LD cache.
+ */
+jsonld.cache = {
+ activeCtx: new jsonld.ActiveContextCache()
+};
+
+/**
* URL resolvers.
*/
jsonld.urlResolvers = {};
@@ -2293,8 +2348,18 @@
* @return the new active context.
*/
Processor.prototype.processContext = function(activeCtx, localCtx, options) {
+ var rval = null;
+
+ // get context from cache if available
+ if(jsonld.cache.activeCtx) {
+ rval = jsonld.cache.activeCtx.get(activeCtx, localCtx);
+ if(rval) {
+ return rval;
+ }
+ }
+
// initialize the resulting context
- var rval = activeCtx.clone();
+ rval = activeCtx.clone();
// normalize local context to an array of @context objects
if(_isObject(localCtx) && '@context' in localCtx &&
@@ -2376,6 +2441,11 @@
}
}
+ // cache result
+ if(jsonld.cache.activeCtx) {
+ jsonld.cache.activeCtx.set(activeCtx, localCtx, rval);
+ }
+
return rval;
};
@@ -3295,7 +3365,10 @@
if('@default' in next) {
preserve = _clone(next['@default']);
}
- output[prop] = {'@preserve': preserve};
+ if(!_isArray(preserve)) {
+ preserve = [preserve];
+ }
+ output[prop] = [{'@preserve': [preserve]}];
}
}
@@ -4420,35 +4493,27 @@
},
namer: namer,
inverse: null,
- getInverse: function() {
- if(this.inverse) {
- return this.inverse;
- }
- this.inverse = _createInverseContext(this);
- return this.inverse;
- },
- clone: function() {
- var child = {};
- child['@base'] = this['@base'];
- child.keywords = _clone(this.keywords);
- child.mappings = _clone(this.mappings);
- child.namer = this.namer;
- child.clone = this.clone;
- child.inverse = null;
- child.getInverse = this.getInverse;
- return child;
- }
+ getInverse: _createInverseContext,
+ clone: _cloneActiveContext
};
/**
- * Generates an inverse context for use in the compaction algorithm.
+ * Generates an inverse context for use in the compaction algorithm, if
+ * not already generated for the given active context.
*
* @param activeCtx the active context to create the inverse context from.
*
* @return the inverse context.
*/
function _createInverseContext(activeCtx) {
- var inverse = {};
+ if(!activeCtx) {
+ activeCtx = this;
+ }
+ // lazily create inverse
+ if(activeCtx.inverse) {
+ return activeCtx.inverse;
+ }
+ var inverse = activeCtx.inverse = {};
// handle default language
var defaultLanguage = activeCtx['@language'] || '@none';
@@ -4559,6 +4624,23 @@
}
}
}
+
+ /**
+ * Clones an active context, creating a child active context.
+ *
+ * @return a clone (child) of the active context.
+ */
+ function _cloneActiveContext() {
+ var child = {};
+ child['@base'] = this['@base'];
+ child.keywords = _clone(this.keywords);
+ child.mappings = _clone(this.mappings);
+ child.namer = this.namer;
+ child.clone = this.clone;
+ child.inverse = null;
+ child.getInverse = this.getInverse;
+ return child;
+ }
}
/**
--- a/test-suite/tests/frame-0015-out.jsonld Fri Jan 25 10:40:35 2013 -0500
+++ b/test-suite/tests/frame-0015-out.jsonld Fri Jan 25 15:36:28 2013 -0500
@@ -84,13 +84,13 @@
"@type": "sp:VitalSigns",
"sp:belongsTo": "http://localhost:7000/records/999888",
"sp:bloodPressure": {
- "@id": "_:t0",
+ "@id": "_:t2",
"@type": "sp:BloodPressure",
"sp:systolic": {
- "@id": "_:t1",
+ "@id": "_:t0",
"@type": "sp:VitalSign",
"sp:vitalName": {
- "@id": "_:t2",
+ "@id": "_:t1",
"dcterms:title": "Systolic blood pressure",
"@type": "sp:CodedValue",
"sp:code": "http://loinc.org/codes/8480-6"
@@ -109,15 +109,15 @@
"sp:hasStatement": "http://localhost:7000/records/999888/vital_signs/c9ddca3e-3df8-4f13-9a16-eecd80aa8ff6"
},
"sp:bloodPressure": {
- "@id": "_:t0",
+ "@id": "_:t2",
"@type": "sp:BloodPressure",
"sp:systolic": {
- "@id": "_:t1",
+ "@id": "_:t0",
"@type": "sp:VitalSign",
"sp:unit": "mm[Hg]",
"sp:value": "111.226458141",
"sp:vitalName": {
- "@id": "_:t2",
+ "@id": "_:t1",
"@type": "sp:CodedValue",
"dcterms:title": "Systolic blood pressure",
"sp:code": "http://loinc.org/codes/8480-6"