Comparing version
# jsonld ChangeLog | ||
## 0.5.15 - 2017-10-16 | ||
### Changed | ||
- **BREAKING** Use RDF JS (rdf.js.org) interfaces for internal | ||
representation of dataset and quads. This should only break | ||
code that was using undocumented internal datastructures, | ||
backwards-compat code exists to handle external RDF parsers. | ||
- Update `rdf-canonize` to dependency with native support. | ||
## 0.5.14 - 2017-10-11 | ||
@@ -4,0 +13,0 @@ |
@@ -55,4 +55,5 @@ /* | ||
for (let name in dataset) { | ||
const graph = dataset[name]; | ||
for (const quad of dataset) { | ||
// TODO: change 'name' to 'graph' | ||
const name = quad.graph.termType === 'DefaultGraph' ? '@default' : quad.graph.value; | ||
if (!(name in graphMap)) { | ||
@@ -64,54 +65,52 @@ graphMap[name] = {}; | ||
} | ||
const nodeMap = graphMap[name]; | ||
for (let ti = 0; ti < graph.length; ++ti) { | ||
const triple = graph[ti]; | ||
// get subject, predicate, object | ||
const s = triple.subject.value; | ||
const p = triple.predicate.value; | ||
const o = triple.object; | ||
// get subject, predicate, object | ||
const s = quad.subject.value; | ||
const p = quad.predicate.value; | ||
const o = quad.object; | ||
if (!(s in nodeMap)) { | ||
nodeMap[s] = { '@id': s }; | ||
} | ||
const node = nodeMap[s]; | ||
if (!(s in nodeMap)) { | ||
nodeMap[s] = { '@id': s }; | ||
} | ||
const node = nodeMap[s]; | ||
const objectIsId = o.type === 'IRI' || o.type === 'blank node'; | ||
if (objectIsId && !(o.value in nodeMap)) { | ||
nodeMap[o.value] = { '@id': o.value }; | ||
} | ||
const objectIsNode = o.termType.endsWith('Node'); | ||
if (objectIsNode && !(o.value in nodeMap)) { | ||
nodeMap[o.value] = { '@id': o.value }; | ||
} | ||
if (p === RDF_TYPE && !useRdfType && objectIsId) { | ||
util.addValue(node, '@type', o.value, { propertyIsArray: true }); | ||
continue; | ||
} | ||
if (p === RDF_TYPE && !useRdfType && objectIsNode) { | ||
util.addValue(node, '@type', o.value, { propertyIsArray: true }); | ||
continue; | ||
} | ||
const value = _RDFToObject(o, useNativeTypes); | ||
util.addValue(node, p, value, { propertyIsArray: true }); | ||
const value = _RDFToObject(o, useNativeTypes); | ||
util.addValue(node, p, value, { propertyIsArray: true }); | ||
// object may be an RDF list/partial list node but we can't know easily | ||
// until all triples are read | ||
if (objectIsId) { | ||
if (o.value === RDF_NIL) { | ||
// track rdf:nil uniquely per graph | ||
const object = nodeMap[o.value]; | ||
if (!('usages' in object)) { | ||
object.usages = []; | ||
} | ||
object.usages.push({ | ||
node: node, | ||
property: p, | ||
value: value | ||
}); | ||
} else if (o.value in referencedOnce) { | ||
// object referenced more than once | ||
referencedOnce[o.value] = false; | ||
} else { | ||
// keep track of single reference | ||
referencedOnce[o.value] = { | ||
node: node, | ||
property: p, | ||
value: value | ||
}; | ||
// object may be an RDF list/partial list node but we can't know easily | ||
// until all triples are read | ||
if (objectIsNode) { | ||
if (o.value === RDF_NIL) { | ||
// track rdf:nil uniquely per graph | ||
const object = nodeMap[o.value]; | ||
if (!('usages' in object)) { | ||
object.usages = []; | ||
} | ||
object.usages.push({ | ||
node: node, | ||
property: p, | ||
value: value | ||
}); | ||
} else if (o.value in referencedOnce) { | ||
// object referenced more than once | ||
referencedOnce[o.value] = false; | ||
} else { | ||
// keep track of single reference | ||
referencedOnce[o.value] = { | ||
node: node, | ||
property: p, | ||
value: value | ||
}; | ||
} | ||
@@ -121,2 +120,67 @@ } | ||
/* | ||
for(let name in dataset) { | ||
const graph = dataset[name]; | ||
if(!(name in graphMap)) { | ||
graphMap[name] = {}; | ||
} | ||
if(name !== '@default' && !(name in defaultGraph)) { | ||
defaultGraph[name] = {'@id': name}; | ||
} | ||
const nodeMap = graphMap[name]; | ||
for(let ti = 0; ti < graph.length; ++ti) { | ||
const triple = graph[ti]; | ||
// get subject, predicate, object | ||
const s = triple.subject.value; | ||
const p = triple.predicate.value; | ||
const o = triple.object; | ||
if(!(s in nodeMap)) { | ||
nodeMap[s] = {'@id': s}; | ||
} | ||
const node = nodeMap[s]; | ||
const objectIsId = (o.type === 'IRI' || o.type === 'blank node'); | ||
if(objectIsId && !(o.value in nodeMap)) { | ||
nodeMap[o.value] = {'@id': o.value}; | ||
} | ||
if(p === RDF_TYPE && !useRdfType && objectIsId) { | ||
util.addValue(node, '@type', o.value, {propertyIsArray: true}); | ||
continue; | ||
} | ||
const value = _RDFToObject(o, useNativeTypes); | ||
util.addValue(node, p, value, {propertyIsArray: true}); | ||
// object may be an RDF list/partial list node but we can't know easily | ||
// until all triples are read | ||
if(objectIsId) { | ||
if(o.value === RDF_NIL) { | ||
// track rdf:nil uniquely per graph | ||
const object = nodeMap[o.value]; | ||
if(!('usages' in object)) { | ||
object.usages = []; | ||
} | ||
object.usages.push({ | ||
node: node, | ||
property: p, | ||
value: value | ||
}); | ||
} else if(o.value in referencedOnce) { | ||
// object referenced more than once | ||
referencedOnce[o.value] = false; | ||
} else { | ||
// keep track of single reference | ||
referencedOnce[o.value] = { | ||
node: node, | ||
property: p, | ||
value: value | ||
}; | ||
} | ||
} | ||
} | ||
}*/ | ||
// convert linked lists to @list arrays | ||
@@ -133,4 +197,3 @@ for (let name in graphMap) { | ||
const nil = graphObject[RDF_NIL]; | ||
for (let i = 0; i < nil.usages.length; ++i) { | ||
let usage = nil.usages[i]; | ||
for (let usage of nil.usages) { | ||
let node = usage.node; | ||
@@ -161,3 +224,3 @@ let property = usage.property; | ||
// if node is not a blank node, then list head found | ||
if (node['@id'].indexOf('_:') !== 0) { | ||
if (!graphTypes.isBlankNode(node)) { | ||
break; | ||
@@ -185,4 +248,4 @@ } | ||
head['@list'] = list.reverse(); | ||
for (let j = 0; j < listNodes.length; ++j) { | ||
delete graphObject[listNodes[j]]; | ||
for (const listNode of listNodes) { | ||
delete graphObject[listNode]; | ||
} | ||
@@ -196,4 +259,3 @@ } | ||
const subjects = Object.keys(defaultGraph).sort(); | ||
for (let i = 0; i < subjects.length; ++i) { | ||
const subject = subjects[i]; | ||
for (const subject of subjects) { | ||
const node = defaultGraph[subject]; | ||
@@ -203,8 +265,8 @@ if (subject in graphMap) { | ||
const graphObject = graphMap[subject]; | ||
const subjects_ = Object.keys(graphObject).sort(); | ||
for (let si = 0; si < subjects_.length; ++si) { | ||
const node_ = graphObject[subjects_[si]]; | ||
const graphSubjects = Object.keys(graphObject).sort(); | ||
for (const graphSubject of graphSubjects) { | ||
const node = graphObject[graphSubject]; | ||
// only add full subjects to top-level | ||
if (!graphTypes.isSubjectReference(node_)) { | ||
graph.push(node_); | ||
if (!graphTypes.isSubjectReference(node)) { | ||
graph.push(node); | ||
} | ||
@@ -236,4 +298,4 @@ } | ||
function _RDFToObject(o, useNativeTypes) { | ||
// convert IRI/blank node object to JSON-LD | ||
if (o.type === 'IRI' || o.type === 'blank node') { | ||
// convert NamedNode/BlankNode object to JSON-LD | ||
if (o.termType.endsWith('Node')) { | ||
return { '@id': o.value }; | ||
@@ -249,3 +311,3 @@ } | ||
} else { | ||
let type = o.datatype; | ||
let type = o.datatype.value; | ||
if (!type) { | ||
@@ -252,0 +314,0 @@ type = XSD_STRING; |
@@ -640,2 +640,4 @@ 'use strict'; | ||
// TODO: call `normalizeAsyncFn` on parser fn | ||
// rdfParser can be callback, promise-based, or synchronous | ||
@@ -658,3 +660,10 @@ let parsedDataset; | ||
return _fromRDF((yield parsedDataset), options); | ||
parsedDataset = yield parsedDataset; | ||
// back-compat with old parsers that produced legacy dataset format | ||
if (!Array.isArray(parsedDataset)) { | ||
parsedDataset = NQuads.legacyDatasetToQuads(dataset); | ||
} | ||
return _fromRDF(parsedDataset, options); | ||
}); | ||
@@ -661,0 +670,0 @@ |
@@ -58,11 +58,22 @@ /* | ||
const dataset = {}; | ||
const dataset = []; | ||
const graphNames = Object.keys(nodeMap).sort(); | ||
for (let i = 0; i < graphNames.length; ++i) { | ||
const graphName = graphNames[i]; | ||
// skip relative IRIs | ||
if (graphName === '@default' || _isAbsoluteIri(graphName)) { | ||
dataset[graphName] = _graphToRDF(nodeMap[graphName], issuer, options); | ||
for (const graphName of graphNames) { | ||
let graphTerm; | ||
if (graphName === '@default') { | ||
graphTerm = { termType: 'DefaultGraph', value: '' }; | ||
} else if (_isAbsoluteIri(graphName)) { | ||
if (graphName.startsWith('_:')) { | ||
graphTerm = { termType: 'BlankNode' }; | ||
} else { | ||
graphTerm = { termType: 'NamedNode' }; | ||
} | ||
graphTerm.value = graphName; | ||
} else { | ||
// skip relative IRIs (not valid RDF) | ||
continue; | ||
} | ||
_graphToRDF(dataset, nodeMap[graphName], graphTerm, issuer, options); | ||
} | ||
return dataset; | ||
@@ -72,5 +83,7 @@ }; | ||
/** | ||
* Creates an array of RDF triples for the given graph. | ||
* Adds RDF quads for a particular graph to the given dataset. | ||
* | ||
* @param graph the graph to create RDF triples for. | ||
* @param dataset the dataset to append RDF quads to. | ||
* @param graph the graph to create RDF quads for. | ||
* @param graphTerm the graph term for each quad. | ||
* @param issuer a IdentifierIssuer for assigning blank node names. | ||
@@ -81,5 +94,3 @@ * @param options the RDF serialization options. | ||
*/ | ||
function _graphToRDF(graph, issuer, options) { | ||
const rval = []; | ||
function _graphToRDF(dataset, graph, graphTerm, issuer, options) { | ||
const ids = Object.keys(graph).sort(); | ||
@@ -90,4 +101,3 @@ for (let i = 0; i < ids.length; ++i) { | ||
const properties = Object.keys(node).sort(); | ||
for (let pi = 0; pi < properties.length; ++pi) { | ||
let property = properties[pi]; | ||
for (let property of properties) { | ||
const items = node[property]; | ||
@@ -100,11 +110,10 @@ if (property === '@type') { | ||
for (let ii = 0; ii < items.length; ++ii) { | ||
const item = items[ii]; | ||
for (const item of items) { | ||
// RDF subject | ||
const subject = {}; | ||
subject.type = id.indexOf('_:') === 0 ? 'blank node' : 'IRI'; | ||
subject.value = id; | ||
const subject = { | ||
termType: id.startsWith('_:') ? 'BlankNode' : 'NamedNode', | ||
value: id | ||
}; | ||
// skip relative IRI subjects | ||
// skip relative IRI subjects (not valid RDF) | ||
if (!_isAbsoluteIri(id)) { | ||
@@ -115,7 +124,8 @@ continue; | ||
// RDF predicate | ||
const predicate = {}; | ||
predicate.type = property.indexOf('_:') === 0 ? 'blank node' : 'IRI'; | ||
predicate.value = property; | ||
const predicate = { | ||
termType: property.startsWith('_:') ? 'BlankNode' : 'NamedNode', | ||
value: property | ||
}; | ||
// skip relative IRI predicates | ||
// skip relative IRI predicates (not valid RDF) | ||
if (!_isAbsoluteIri(property)) { | ||
@@ -126,3 +136,3 @@ continue; | ||
// skip blank node predicates unless producing generalized RDF | ||
if (predicate.type === 'blank node' && !options.produceGeneralizedRdf) { | ||
if (predicate.termType === 'BlankNode' && !options.produceGeneralizedRdf) { | ||
continue; | ||
@@ -133,3 +143,3 @@ } | ||
if (graphTypes.isList(item)) { | ||
_listToRDF(item['@list'], issuer, subject, predicate, rval); | ||
_listToRDF(item['@list'], issuer, subject, predicate, dataset, graphTerm); | ||
} else { | ||
@@ -140,3 +150,8 @@ // convert value or node object to triple | ||
if (object) { | ||
rval.push({ subject: subject, predicate: predicate, object: object }); | ||
dataset.push({ | ||
subject: subject, | ||
predicate: predicate, | ||
object: object, | ||
graph: graphTerm | ||
}); | ||
} | ||
@@ -147,8 +162,6 @@ } | ||
} | ||
return rval; | ||
} | ||
/** | ||
* Converts a @list value into linked list of blank node RDF triples | ||
* Converts a @list value into linked list of blank node RDF quads | ||
* (an RDF collection). | ||
@@ -160,15 +173,19 @@ * | ||
* @param predicate the predicate for the head of the list. | ||
* @param triples the array of triples to append to. | ||
* @param dataset the array of quads to append to. | ||
* @param graphTerm the graph term for each quad. | ||
*/ | ||
function _listToRDF(list, issuer, subject, predicate, triples) { | ||
const first = { type: 'IRI', value: RDF_FIRST }; | ||
const rest = { type: 'IRI', value: RDF_REST }; | ||
const nil = { type: 'IRI', value: RDF_NIL }; | ||
function _listToRDF(list, issuer, subject, predicate, dataset, graphTerm) { | ||
const first = { termType: 'NamedNode', value: RDF_FIRST }; | ||
const rest = { termType: 'NamedNode', value: RDF_REST }; | ||
const nil = { termType: 'NamedNode', value: RDF_NIL }; | ||
for (let i = 0; i < list.length; ++i) { | ||
const item = list[i]; | ||
for (const item of list) { | ||
const blankNode = { termType: 'BlankNode', value: issuer.getId() }; | ||
dataset.push({ | ||
subject: subject, | ||
predicate: predicate, | ||
object: blankNode, | ||
graph: graphTerm | ||
}); | ||
const blankNode = { type: 'blank node', value: issuer.getId() }; | ||
triples.push({ subject: subject, predicate: predicate, object: blankNode }); | ||
subject = blankNode; | ||
@@ -180,3 +197,8 @@ predicate = first; | ||
if (object) { | ||
triples.push({ subject: subject, predicate: predicate, object: object }); | ||
dataset.push({ | ||
subject: subject, | ||
predicate: predicate, | ||
object: object, | ||
graph: graphTerm | ||
}); | ||
} | ||
@@ -187,3 +209,8 @@ | ||
triples.push({ subject: subject, predicate: predicate, object: nil }); | ||
dataset.push({ | ||
subject: subject, | ||
predicate: predicate, | ||
object: nil, | ||
graph: graphTerm | ||
}); | ||
} | ||
@@ -204,3 +231,7 @@ | ||
if (graphTypes.isValue(item)) { | ||
object.type = 'literal'; | ||
object.termType = 'Literal'; | ||
object.value = undefined; | ||
object.datatype = { | ||
termType: 'NamedNode' | ||
}; | ||
let value = item['@value']; | ||
@@ -212,3 +243,3 @@ const datatype = item['@type'] || null; | ||
object.value = value.toString(); | ||
object.datatype = datatype || XSD_BOOLEAN; | ||
object.datatype.value = datatype || XSD_BOOLEAN; | ||
} else if (types.isDouble(value) || datatype === XSD_DOUBLE) { | ||
@@ -220,13 +251,13 @@ if (!types.isDouble(value)) { | ||
object.value = value.toExponential(15).replace(/(\d)0*e\+?/, '$1E'); | ||
object.datatype = datatype || XSD_DOUBLE; | ||
object.datatype.value = datatype || XSD_DOUBLE; | ||
} else if (types.isNumber(value)) { | ||
object.value = value.toFixed(0); | ||
object.datatype = datatype || XSD_INTEGER; | ||
object.datatype.value = datatype || XSD_INTEGER; | ||
} else if ('@language' in item) { | ||
object.value = value; | ||
object.datatype = datatype || RDF_LANGSTRING; | ||
object.datatype.value = datatype || RDF_LANGSTRING; | ||
object.language = item['@language']; | ||
} else { | ||
object.value = value; | ||
object.datatype = datatype || XSD_STRING; | ||
object.datatype.value = datatype || XSD_STRING; | ||
} | ||
@@ -236,8 +267,8 @@ } else { | ||
const id = types.isObject(item) ? item['@id'] : item; | ||
object.type = id.indexOf('_:') === 0 ? 'blank node' : 'IRI'; | ||
object.termType = id.startsWith('_:') ? 'BlankNode' : 'NamedNode'; | ||
object.value = id; | ||
} | ||
// skip relative IRIs | ||
if (object.type === 'IRI' && !_isAbsoluteIri(object.value)) { | ||
// skip relative IRIs, not valid RDF | ||
if (object.termType === 'NamedNode' && !_isAbsoluteIri(object.value)) { | ||
return null; | ||
@@ -244,0 +275,0 @@ } |
@@ -47,2 +47,67 @@ /* | ||
for(const quad of dataset) { | ||
// TODO: change 'name' to 'graph' | ||
const name = (quad.graph.termType === 'DefaultGraph') ? | ||
'@default': quad.graph.value; | ||
if(!(name in graphMap)) { | ||
graphMap[name] = {}; | ||
} | ||
if(name !== '@default' && !(name in defaultGraph)) { | ||
defaultGraph[name] = {'@id': name}; | ||
} | ||
const nodeMap = graphMap[name]; | ||
// get subject, predicate, object | ||
const s = quad.subject.value; | ||
const p = quad.predicate.value; | ||
const o = quad.object; | ||
if(!(s in nodeMap)) { | ||
nodeMap[s] = {'@id': s}; | ||
} | ||
const node = nodeMap[s]; | ||
const objectIsNode = o.termType.endsWith('Node'); | ||
if(objectIsNode && !(o.value in nodeMap)) { | ||
nodeMap[o.value] = {'@id': o.value}; | ||
} | ||
if(p === RDF_TYPE && !useRdfType && objectIsNode) { | ||
util.addValue(node, '@type', o.value, {propertyIsArray: true}); | ||
continue; | ||
} | ||
const value = _RDFToObject(o, useNativeTypes); | ||
util.addValue(node, p, value, {propertyIsArray: true}); | ||
// object may be an RDF list/partial list node but we can't know easily | ||
// until all triples are read | ||
if(objectIsNode) { | ||
if(o.value === RDF_NIL) { | ||
// track rdf:nil uniquely per graph | ||
const object = nodeMap[o.value]; | ||
if(!('usages' in object)) { | ||
object.usages = []; | ||
} | ||
object.usages.push({ | ||
node: node, | ||
property: p, | ||
value: value | ||
}); | ||
} else if(o.value in referencedOnce) { | ||
// object referenced more than once | ||
referencedOnce[o.value] = false; | ||
} else { | ||
// keep track of single reference | ||
referencedOnce[o.value] = { | ||
node: node, | ||
property: p, | ||
value: value | ||
}; | ||
} | ||
} | ||
} | ||
/* | ||
for(let name in dataset) { | ||
@@ -110,3 +175,3 @@ const graph = dataset[name]; | ||
} | ||
} | ||
}*/ | ||
@@ -124,4 +189,3 @@ // convert linked lists to @list arrays | ||
const nil = graphObject[RDF_NIL]; | ||
for(let i = 0; i < nil.usages.length; ++i) { | ||
let usage = nil.usages[i]; | ||
for(let usage of nil.usages) { | ||
let node = usage.node; | ||
@@ -158,3 +222,3 @@ let property = usage.property; | ||
// if node is not a blank node, then list head found | ||
if(node['@id'].indexOf('_:') !== 0) { | ||
if(!graphTypes.isBlankNode(node)) { | ||
break; | ||
@@ -182,4 +246,4 @@ } | ||
head['@list'] = list.reverse(); | ||
for(let j = 0; j < listNodes.length; ++j) { | ||
delete graphObject[listNodes[j]]; | ||
for(const listNode of listNodes) { | ||
delete graphObject[listNode]; | ||
} | ||
@@ -193,4 +257,3 @@ } | ||
const subjects = Object.keys(defaultGraph).sort(); | ||
for(let i = 0; i < subjects.length; ++i) { | ||
const subject = subjects[i]; | ||
for(const subject of subjects) { | ||
const node = defaultGraph[subject]; | ||
@@ -200,8 +263,8 @@ if(subject in graphMap) { | ||
const graphObject = graphMap[subject]; | ||
const subjects_ = Object.keys(graphObject).sort(); | ||
for(let si = 0; si < subjects_.length; ++si) { | ||
const node_ = graphObject[subjects_[si]]; | ||
const graphSubjects = Object.keys(graphObject).sort(); | ||
for(const graphSubject of graphSubjects) { | ||
const node = graphObject[graphSubject]; | ||
// only add full subjects to top-level | ||
if(!graphTypes.isSubjectReference(node_)) { | ||
graph.push(node_); | ||
if(!graphTypes.isSubjectReference(node)) { | ||
graph.push(node); | ||
} | ||
@@ -228,4 +291,4 @@ } | ||
function _RDFToObject(o, useNativeTypes) { | ||
// convert IRI/blank node object to JSON-LD | ||
if(o.type === 'IRI' || o.type === 'blank node') { | ||
// convert NamedNode/BlankNode object to JSON-LD | ||
if(o.termType.endsWith('Node')) { | ||
return {'@id': o.value}; | ||
@@ -241,3 +304,3 @@ } | ||
} else { | ||
let type = o.datatype; | ||
let type = o.datatype.value; | ||
if(!type) { | ||
@@ -244,0 +307,0 @@ type = XSD_STRING; |
@@ -588,2 +588,4 @@ /** | ||
// TODO: call `normalizeAsyncFn` on parser fn | ||
// rdfParser can be callback, promise-based, or synchronous | ||
@@ -606,3 +608,10 @@ let parsedDataset; | ||
return _fromRDF(await parsedDataset, options); | ||
parsedDataset = await parsedDataset; | ||
// back-compat with old parsers that produced legacy dataset format | ||
if(!Array.isArray(parsedDataset)) { | ||
parsedDataset = NQuads.legacyDatasetToQuads(dataset); | ||
} | ||
return _fromRDF(parsedDataset, options); | ||
}); | ||
@@ -609,0 +618,0 @@ |
135
lib/toRdf.js
@@ -52,11 +52,22 @@ /* | ||
const dataset = {}; | ||
const dataset = []; | ||
const graphNames = Object.keys(nodeMap).sort(); | ||
for(let i = 0; i < graphNames.length; ++i) { | ||
const graphName = graphNames[i]; | ||
// skip relative IRIs | ||
if(graphName === '@default' || _isAbsoluteIri(graphName)) { | ||
dataset[graphName] = _graphToRDF(nodeMap[graphName], issuer, options); | ||
for(const graphName of graphNames) { | ||
let graphTerm; | ||
if(graphName === '@default') { | ||
graphTerm = {termType: 'DefaultGraph', value: ''}; | ||
} else if(_isAbsoluteIri(graphName)) { | ||
if(graphName.startsWith('_:')) { | ||
graphTerm = {termType: 'BlankNode'}; | ||
} else { | ||
graphTerm = {termType: 'NamedNode'}; | ||
} | ||
graphTerm.value = graphName; | ||
} else { | ||
// skip relative IRIs (not valid RDF) | ||
continue; | ||
} | ||
_graphToRDF(dataset, nodeMap[graphName], graphTerm, issuer, options); | ||
} | ||
return dataset; | ||
@@ -66,5 +77,7 @@ }; | ||
/** | ||
* Creates an array of RDF triples for the given graph. | ||
* Adds RDF quads for a particular graph to the given dataset. | ||
* | ||
* @param graph the graph to create RDF triples for. | ||
* @param dataset the dataset to append RDF quads to. | ||
* @param graph the graph to create RDF quads for. | ||
* @param graphTerm the graph term for each quad. | ||
* @param issuer a IdentifierIssuer for assigning blank node names. | ||
@@ -75,5 +88,3 @@ * @param options the RDF serialization options. | ||
*/ | ||
function _graphToRDF(graph, issuer, options) { | ||
const rval = []; | ||
function _graphToRDF(dataset, graph, graphTerm, issuer, options) { | ||
const ids = Object.keys(graph).sort(); | ||
@@ -84,4 +95,3 @@ for(let i = 0; i < ids.length; ++i) { | ||
const properties = Object.keys(node).sort(); | ||
for(let pi = 0; pi < properties.length; ++pi) { | ||
let property = properties[pi]; | ||
for(let property of properties) { | ||
const items = node[property]; | ||
@@ -94,11 +104,10 @@ if(property === '@type') { | ||
for(let ii = 0; ii < items.length; ++ii) { | ||
const item = items[ii]; | ||
for(const item of items) { | ||
// RDF subject | ||
const subject = {}; | ||
subject.type = (id.indexOf('_:') === 0) ? 'blank node' : 'IRI'; | ||
subject.value = id; | ||
const subject = { | ||
termType: id.startsWith('_:') ? 'BlankNode' : 'NamedNode', | ||
value: id | ||
}; | ||
// skip relative IRI subjects | ||
// skip relative IRI subjects (not valid RDF) | ||
if(!_isAbsoluteIri(id)) { | ||
@@ -109,7 +118,8 @@ continue; | ||
// RDF predicate | ||
const predicate = {}; | ||
predicate.type = (property.indexOf('_:') === 0) ? 'blank node' : 'IRI'; | ||
predicate.value = property; | ||
const predicate = { | ||
termType: property.startsWith('_:') ? 'BlankNode' : 'NamedNode', | ||
value: property | ||
}; | ||
// skip relative IRI predicates | ||
// skip relative IRI predicates (not valid RDF) | ||
if(!_isAbsoluteIri(property)) { | ||
@@ -120,3 +130,4 @@ continue; | ||
// skip blank node predicates unless producing generalized RDF | ||
if(predicate.type === 'blank node' && !options.produceGeneralizedRdf) { | ||
if(predicate.termType === 'BlankNode' && | ||
!options.produceGeneralizedRdf) { | ||
continue; | ||
@@ -127,3 +138,4 @@ } | ||
if(graphTypes.isList(item)) { | ||
_listToRDF(item['@list'], issuer, subject, predicate, rval); | ||
_listToRDF( | ||
item['@list'], issuer, subject, predicate, dataset, graphTerm); | ||
} else { | ||
@@ -134,3 +146,8 @@ // convert value or node object to triple | ||
if(object) { | ||
rval.push({subject: subject, predicate: predicate, object: object}); | ||
dataset.push({ | ||
subject: subject, | ||
predicate: predicate, | ||
object: object, | ||
graph: graphTerm | ||
}); | ||
} | ||
@@ -141,8 +158,6 @@ } | ||
} | ||
return rval; | ||
} | ||
/** | ||
* Converts a @list value into linked list of blank node RDF triples | ||
* Converts a @list value into linked list of blank node RDF quads | ||
* (an RDF collection). | ||
@@ -154,15 +169,19 @@ * | ||
* @param predicate the predicate for the head of the list. | ||
* @param triples the array of triples to append to. | ||
* @param dataset the array of quads to append to. | ||
* @param graphTerm the graph term for each quad. | ||
*/ | ||
function _listToRDF(list, issuer, subject, predicate, triples) { | ||
const first = {type: 'IRI', value: RDF_FIRST}; | ||
const rest = {type: 'IRI', value: RDF_REST}; | ||
const nil = {type: 'IRI', value: RDF_NIL}; | ||
function _listToRDF(list, issuer, subject, predicate, dataset, graphTerm) { | ||
const first = {termType: 'NamedNode', value: RDF_FIRST}; | ||
const rest = {termType: 'NamedNode', value: RDF_REST}; | ||
const nil = {termType: 'NamedNode', value: RDF_NIL}; | ||
for(let i = 0; i < list.length; ++i) { | ||
const item = list[i]; | ||
for(const item of list) { | ||
const blankNode = {termType: 'BlankNode', value: issuer.getId()}; | ||
dataset.push({ | ||
subject: subject, | ||
predicate: predicate, | ||
object: blankNode, | ||
graph: graphTerm | ||
}); | ||
const blankNode = {type: 'blank node', value: issuer.getId()}; | ||
triples.push({subject: subject, predicate: predicate, object: blankNode}); | ||
subject = blankNode; | ||
@@ -174,3 +193,8 @@ predicate = first; | ||
if(object) { | ||
triples.push({subject: subject, predicate: predicate, object: object}); | ||
dataset.push({ | ||
subject: subject, | ||
predicate: predicate, | ||
object: object, | ||
graph: graphTerm | ||
}); | ||
} | ||
@@ -181,3 +205,8 @@ | ||
triples.push({subject: subject, predicate: predicate, object: nil}); | ||
dataset.push({ | ||
subject: subject, | ||
predicate: predicate, | ||
object: nil, | ||
graph: graphTerm | ||
}); | ||
} | ||
@@ -198,3 +227,7 @@ | ||
if(graphTypes.isValue(item)) { | ||
object.type = 'literal'; | ||
object.termType = 'Literal'; | ||
object.value = undefined; | ||
object.datatype = { | ||
termType: 'NamedNode' | ||
}; | ||
let value = item['@value']; | ||
@@ -206,3 +239,3 @@ const datatype = item['@type'] || null; | ||
object.value = value.toString(); | ||
object.datatype = datatype || XSD_BOOLEAN; | ||
object.datatype.value = datatype || XSD_BOOLEAN; | ||
} else if(types.isDouble(value) || datatype === XSD_DOUBLE) { | ||
@@ -214,13 +247,13 @@ if(!types.isDouble(value)) { | ||
object.value = value.toExponential(15).replace(/(\d)0*e\+?/, '$1E'); | ||
object.datatype = datatype || XSD_DOUBLE; | ||
object.datatype.value = datatype || XSD_DOUBLE; | ||
} else if(types.isNumber(value)) { | ||
object.value = value.toFixed(0); | ||
object.datatype = datatype || XSD_INTEGER; | ||
object.datatype.value = datatype || XSD_INTEGER; | ||
} else if('@language' in item) { | ||
object.value = value; | ||
object.datatype = datatype || RDF_LANGSTRING; | ||
object.datatype.value = datatype || RDF_LANGSTRING; | ||
object.language = item['@language']; | ||
} else { | ||
object.value = value; | ||
object.datatype = datatype || XSD_STRING; | ||
object.datatype.value = datatype || XSD_STRING; | ||
} | ||
@@ -230,8 +263,8 @@ } else { | ||
const id = types.isObject(item) ? item['@id'] : item; | ||
object.type = (id.indexOf('_:') === 0) ? 'blank node' : 'IRI'; | ||
object.termType = id.startsWith('_:') ? 'BlankNode' : 'NamedNode'; | ||
object.value = id; | ||
} | ||
// skip relative IRIs | ||
if(object.type === 'IRI' && !_isAbsoluteIri(object.value)) { | ||
// skip relative IRIs, not valid RDF | ||
if(object.termType === 'NamedNode' && !_isAbsoluteIri(object.value)) { | ||
return null; | ||
@@ -238,0 +271,0 @@ } |
{ | ||
"name": "jsonld", | ||
"version": "0.5.14", | ||
"version": "0.5.15", | ||
"description": "A JSON-LD Processor and API implementation in JavaScript.", | ||
@@ -35,3 +35,3 @@ "homepage": "https://github.com/digitalbazaar/jsonld.js", | ||
"pkginfo": "^0.4.1", | ||
"rdf-canonize": "^0.1.5", | ||
"rdf-canonize": "^0.2.1", | ||
"request": "^2.83.0", | ||
@@ -52,3 +52,3 @@ "semver": "^5.4.1", | ||
"cors": "^2.7.1", | ||
"express": "^4.16.0", | ||
"express": "^4.16.2", | ||
"fs-extra": "^4.0.2", | ||
@@ -73,7 +73,7 @@ "istanbul": "^0.4.3", | ||
"karma-tap-reporter": "0.0.6", | ||
"karma-webpack": "^2.0.4", | ||
"karma-webpack": "^2.0.5", | ||
"mocha": "^3.5.3", | ||
"mocha-lcov-reporter": "^1.3.0", | ||
"regenerator-runtime": "^0.11.0", | ||
"webpack": "^3.6.0", | ||
"webpack": "^3.7.1", | ||
"webpack-merge": "^4.1.0" | ||
@@ -80,0 +80,0 @@ }, |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
1131080
4.54%26570
4.15%+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
Updated