sparqljson-parse
Version:
Parses SPARQL JSON query results
171 lines • 7.52 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.SparqlJsonParser = void 0;
const rdf_data_factory_1 = require("rdf-data-factory");
const readable_stream_1 = require("readable-stream");
// tslint:disable-next-line:no-var-requires
const JsonParser = require('@bergos/jsonparse');
/**
* Parser for the SPARQL 1.1 Query Results JSON format.
* @see https://www.w3.org/TR/sparql11-results-json/
*/
class SparqlJsonParser {
constructor(settings) {
var _a;
settings = settings || {};
this.dataFactory = settings.dataFactory || new rdf_data_factory_1.DataFactory();
this.prefixVariableQuestionMark = !!settings.prefixVariableQuestionMark;
this.suppressMissingStreamResultsError = (_a = settings.suppressMissingStreamResultsError) !== null && _a !== void 0 ? _a : true;
}
/**
* Convert a SPARQL JSON bindings response to an array of bindings objects.
* @param sparqlResponse A SPARQL JSON response.
* @return {IBindings[]} An array of bindings.
*/
parseJsonResults(sparqlResponse) {
return sparqlResponse.results.bindings.map((rawBindings) => this.parseJsonBindings(rawBindings));
}
/**
* Convert a SPARQL JSON bindings response stream to a stream of bindings objects.
*
* The bindings stream will emit a 'variables' event that will contain
* the array of variables (as RDF.Variable[]), as defined in the response head.
*
* @param {NodeJS.ReadableStream} sparqlResponseStream A SPARQL JSON response stream.
* @return {NodeJS.ReadableStream} A stream of bindings.
*/
parseJsonResultsStream(sparqlResponseStream) {
const errorListener = (error) => resultStream.emit('error', error);
sparqlResponseStream.on('error', errorListener);
const jsonParser = new JsonParser();
jsonParser.onError = errorListener;
let variablesFound = false;
let resultsFound = false;
jsonParser.onValue = (value) => {
if (jsonParser.key === "vars" && jsonParser.stack.length === 2 && jsonParser.stack[1].key === 'head') {
resultStream.emit('variables', value.map((v) => this.dataFactory.variable(v)));
variablesFound = true;
}
else if (jsonParser.key === "results" && jsonParser.stack.length === 1) {
resultsFound = true;
}
else if (typeof jsonParser.key === 'number' && jsonParser.stack.length === 3 && jsonParser.stack[1].key === 'results' && jsonParser.stack[2].key === 'bindings') {
try {
resultStream.push(this.parseJsonBindings(value));
}
catch (error) {
resultStream.emit("error", error);
}
}
else if (jsonParser.key === "metadata" && jsonParser.stack.length === 1) {
resultStream.emit('metadata', value);
}
};
const resultStream = sparqlResponseStream
.on("end", _ => {
if (!resultsFound && !this.suppressMissingStreamResultsError) {
resultStream.emit("error", new Error("No valid SPARQL query results were found."));
}
else if (!variablesFound) {
resultStream.emit('variables', []);
}
})
.pipe(new readable_stream_1.Transform({
objectMode: true,
transform(chunk, encoding, callback) {
jsonParser.write(chunk);
callback();
}
}));
return resultStream;
}
/**
* Convert a SPARQL JSON result binding to a bindings object.
* @param rawBindings A SPARQL JSON result binding.
* @return {IBindings} A bindings object.
*/
parseJsonBindings(rawBindings) {
const bindings = {};
for (const key in rawBindings) {
const rawValue = rawBindings[key];
bindings[this.prefixVariableQuestionMark ? ('?' + key) : key] = this.parseJsonValue(rawValue);
}
return bindings;
}
/**
* Convert a SPARQL JSON result value to an RDF term.
* @param rawValue A SPARQL JSON result value
* @return {RDF.Term} An RDF term.
*/
parseJsonValue(rawValue) {
let value;
switch (rawValue.type) {
case 'bnode':
value = this.dataFactory.blankNode(rawValue.value);
break;
case 'literal':
if (rawValue['xml:lang']) {
const language = rawValue['xml:lang'];
const direction = rawValue['its:dir'];
value = this.dataFactory.literal(rawValue.value, { language, direction });
}
else if (rawValue.datatype) {
value = this.dataFactory.literal(rawValue.value, this.dataFactory.namedNode(rawValue.datatype));
}
else {
value = this.dataFactory.literal(rawValue.value);
}
break;
case 'typed-literal':
// Virtuoso uses this non-spec-compliant way of defining typed literals
value = this.dataFactory.literal(rawValue.value, this.dataFactory.namedNode(rawValue.datatype));
break;
case 'triple':
const tripleValue = rawValue.value;
if (!tripleValue || !tripleValue.subject || !tripleValue.predicate || !tripleValue.object) {
throw new Error('Invalid quoted triple: ' + JSON.stringify(rawValue));
}
value = this.dataFactory.quad(this.parseJsonValue(tripleValue.subject), this.parseJsonValue(tripleValue.predicate), this.parseJsonValue(tripleValue.object));
break;
default:
value = this.dataFactory.namedNode(rawValue.value);
break;
}
return value;
}
/**
* Convert a SPARQL JSON boolean response to a boolean.
* This will throw an error if the given reponse was not a valid boolean response.
* @param sparqlResponse A SPARQL JSON response.
* @return {IBindings[]} An array of bindings.
*/
parseJsonBoolean(sparqlResponse) {
if ('boolean' in sparqlResponse) {
return sparqlResponse.boolean;
}
throw new Error('No valid ASK response was found.');
}
/**
* Convert a SPARQL JSON boolean response stream to a promise resolving to a boolean.
* This will reject if the given reponse was not a valid boolean response.
* @param {NodeJS.ReadableStream} sparqlResponseStream A SPARQL JSON response stream.
* @return {Promise<boolean>} The response boolean.
*/
parseJsonBooleanStream(sparqlResponseStream) {
return new Promise((resolve, reject) => {
const parser = new JsonParser();
parser.onError = reject;
parser.onValue = (value) => {
if (parser.key === "boolean" && typeof value === 'boolean' && parser.stack.length === 1) {
resolve(value);
}
};
sparqlResponseStream
.on('error', reject)
.on('data', d => parser.write(d))
.on('end', () => reject(new Error('No valid ASK response was found.')));
});
}
}
exports.SparqlJsonParser = SparqlJsonParser;
//# sourceMappingURL=SparqlJsonParser.js.map