diff --git a/bin/rdf-ext-cli.js b/bin/rdf-ext-cli.js index 57f5ceb..bacdc28 100755 --- a/bin/rdf-ext-cli.js +++ b/bin/rdf-ext-cli.js @@ -9,6 +9,7 @@ import createInputStream from '../lib/createInputStream.js' import createOutputStream from '../lib/createOutputStream.js' import createShaclStream from '../lib/createShaclStream.js' import transformMapNamespaceFunc from '../lib/transformMapNamespace.js' +import transformSkolemIrisFunc from '../lib/transformSkolemIris.js' import transformToTripleFunc from '../lib/transformToTriple.js' const program = new Command() @@ -42,6 +43,7 @@ program .option('--shacl-details', 'generate nested result details') .option('--shacl-trace', 'generate results for path traversing') .option('--transform-map-namespace ', 'map the given namespaces', collectMappings, rdf.termMap()) + .option('--transform-skolem-iris ', 'map blank nodes to Skolem IRIs') .option('--transform-to-triples', 'set graph to default graph') .option('--output-prefix ', 'output prefix', collectPrefixes, new Map()) .option('--output-type ', 'output content type', 'text/turtle') @@ -58,6 +60,7 @@ program shaclDetails, shaclTrace, transformMapNamespace, + transformSkolemIris, transformToTriple, outputPrefix, outputType, @@ -104,6 +107,13 @@ program stream = toTripleStream } + if (transformSkolemIris) { + const toTripleStream = transformSkolemIrisFunc(transformSkolemIris) + + stream.pipe(toTripleStream) + stream = toTripleStream + } + if (transformToTriple) { const toTripleStream = transformToTripleFunc() diff --git a/examples/url-to-skolem-iri-turtle.sh b/examples/url-to-skolem-iri-turtle.sh new file mode 100755 index 0000000..ea1006a --- /dev/null +++ b/examples/url-to-skolem-iri-turtle.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +./bin/rdf-ext-cli.js \ + --pretty \ + --transform-skolem-iris http://example.com/.well-known/genid/ \ + --output-prefix houseplace=https://housemd.rdf-ext.org/place/ \ + --output-prefix schema=http://schema.org/ \ + https://housemd.rdf-ext.org/place/221b-baker-street diff --git a/lib/transformSkolemIris.js b/lib/transformSkolemIris.js new file mode 100644 index 0000000..1d5806f --- /dev/null +++ b/lib/transformSkolemIris.js @@ -0,0 +1,37 @@ +import { randomUUID } from 'node:crypto' +import rdf from 'rdf-ext' +import { Transform } from 'readable-stream' + +function transformSkolemIris (baseIri) { + const nodeMap = rdf.termMap() + + const mapTerm = term => { + if (term.termType === 'BlankNode') { + if (!nodeMap.has(term)) { + nodeMap.set(term, rdf.namedNode(`${baseIri}${randomUUID().split('-').join('')}`)) + } + + return nodeMap.get(term) + } + + return term + } + + const mapQuad = quad => { + return rdf.quad( + mapTerm(quad.subject), + mapTerm(quad.predicate), + mapTerm(quad.object), + mapTerm(quad.graph) + ) + } + + return new Transform({ + objectMode: true, + transform: (quad, encoding, callback) => { + callback(null, mapQuad(quad)) + } + }) +} + +export default transformSkolemIris