ramp-shapes
TypeScript icon, indicating that this package has built-in type declarations

0.11.0 • Public • Published

RAMP shapes: declarative RDF algebraic data type mapping npm version

Home page | Introductory paper | Specification draft | Playground

RAMP is a type construction language, specification and an implementation of mapping operations between RDF graphs and structured data types.

Features

RAMP introduces a language based on RDF which allows to describe a runtime object interface with so-called "shapes". The shapes are basically types augumented with metadata to map them into RDF graph. Usage of such shapes allows to:

  • Map RDF graph data into JS objects.
  • Generate RDF quad/triple data from JS objects.
  • Construct SPARQL queries to fetch necessary data for given shapes.
  • (In the future) Validate that runtime object structure matches specified shape.

Feature comparison with other RDF modelling languages

Feature OWL/RDFS SHACL ShEx JSON-LD RAMP Shapes
Describes closed RDF graph structure
Describes data mapping / serialization requires frame definition
Has ability to generate query and deserialize results based on shapes
Has RDF representation
Supports RDF lists with workaround
Supports shape unions through shape targets
Supports cardinality constraints (min/max)
Supports recursive shapes depends on implementation
Supports property paths
Supports ignoring optional non-matching shapes by declaring shape severity

Installation

Install with npm install --save ramp-shapes

Usage

Try out on the interactive playground.

import * as Ramp from 'ramp-shapes';
import * as N3 from 'n3';
import * as SparqlJs from 'sparqljs';

// get graph triples (source data)
const dataset = Ramp.Rdf.dataset(new N3.Parser().parse(`
    @prefix ex: <http://example.com/schema/>.
    @prefix : <http://example.com/data/>.

    :anno1 a ex:Annotation;
        ex:start :point1;
        ex:end ("1" "2").

    :point1 a ex:Point;
        ex:position 42.
`));

// define custom shapes using Turtle syntax
const shapes = Ramp.frameShapes(Ramp.Rdf.dataset(new N3.Parser().parse(`
    @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>.
    @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.
    @prefix xsd: <http://www.w3.org/2001/XMLSchema#>.
    @prefix ramp: <http://ramp-shapes.github.io/schema#>.
    @prefix ex: <http://example.com/schema/>.

    ex:Annotation a ramp:Record;
        ramp:typeProperty [
            ramp:name "type";
            ramp:path rdf:type;
            ramp:shape [ a ramp:Resource; ramp:termValue ex:Annotation ]
        ];
        ramp:property [
            ramp:name "id";
            ramp:path ();
            ramp:shape [ a ramp:Resource ]
        ];
        ramp:property [
            ramp:name "start";
            ramp:path ex:start;
            ramp:shape ex:Selector
        ];
        ramp:property [
            ramp:name "end";
            ramp:path ex:end;
            ramp:shape [ a ramp:Optional; ramp:item ex:Selector ]
        ].

    ex:Selector a ramp:AnyOf;
        ramp:variant ex:Point, ex:Path.

    ex:Point a ramp:Record;
        ramp:typeProperty [
            ramp:name "type";
            ramp:path rdf:type;
            ramp:shape [ a ramp:Resource; ramp:termValue ex:Point ]
        ];
        ramp:property [
            ramp:name "position";
            ramp:path ex:position;
            ramp:shape [ a ramp:Literal; ramp:termDatatype xsd:integer ]
        ].

    ex:Path a ramp:List;
        ramp:item [ a ramp:Literal; ramp:termDatatype xsd:string ].
`)));

// choose entry point shape
const shape = shapes.find(s =>
  s.id.value === 'http://example.com/schema#Annotation'
);

// use defined shapes to lower RDF graph into JS objects...
const matches = Ramp.frame({shape, dataset});
for (const match of matches) {
  /* match.value object has ex:Annotation shape, e.g.:
    {
      "type": "http://example.com/schema/Annotation",
      "id": "http://example.com/data/anno1",
      "start": {
        "type": "http://example.com/schema/Point",
        "position": 42
      },
      "end": ["1", "2"]
    }
  */

  // ... and lift JS object back into an RDF graph
  const quads = Ramp.flatten({shape, value: match.value});
  /* quads is Iterable<Rdf.Quad>, e.g.:

    :anno1 a ex:Annotation;
        ex:start _:record_044916_1.
    _:record_044916_1 a ex:Point;
        ex:position "42"^^xsd:integer.
    :anno1 ex:end _:list_044916_2.
    _:list_044916_2 rdf:first "1";
        rdf:rest _:list_044916_3.
    _:list_044916_3 rdf:first "2";
        rdf:rest rdf:nil.
  */
}

// another application of defined shapes is to generate a CONSTRUCT query
// to get necessary graph data for framing
const query = Ramp.generateQuery({
  shape,
  // (optionally) specify prefixes for SPARQL
  prefixes: {
    rdf: "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
    rdfs: "http://www.w3.org/2000/01/rdf-schema#",
    xsd: "http://www.w3.org/2001/XMLSchema#",
    ex: "http://example.com/schema/",
    "": "http://example.com/data/",
  }
});
const queryString = new SparqlJs.Generator().stringify(query);
/* query is a CONSTRUCT query in SPARQL.js runtime format:

  PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
  PREFIX ex: <http://example.com/schema/>
  CONSTRUCT {
    ?record_1 rdf:type ex:Annotation.
    ?record_1 ex:start ?record_4.
    ?record_4 rdf:type ex:Point.
    ?record_4 ex:position ?literal_5.
    ?record_1 ex:start ?list_6.
    ?listNode_7 rdf:rest ?nextNode_8.
    ?listNode_7 rdf:first ?literal_9.
    ?record_1 ex:end ?record_11.
    ?record_11 rdf:type ex:Point.
    ?record_11 ex:position ?literal_12.
    ?record_1 ex:end ?list_13.
    ?listNode_14 rdf:rest ?nextNode_15.
    ?listNode_14 rdf:first ?literal_16.
  }
  WHERE {
    ?record_1 rdf:type ex:Annotation.
    {
      ?record_1 ex:start ?record_4.
      ?record_4 rdf:type ex:Point.
      ?record_4 ex:position ?literal_5.
    }
    UNION
    {
      ?record_1 ex:start ?list_6.
      ?list_6 (rdf:rest*) ?listNode_7.
      ?listNode_7 rdf:rest ?nextNode_8.
      ?listNode_7 rdf:first ?literal_9.
    }
    OPTIONAL {
      {
        ?record_1 ex:end ?record_11.
        ?record_11 rdf:type ex:Point.
        ?record_11 ex:position ?literal_12.
      }
      UNION
      {
        ?record_1 ex:end ?list_13.
        ?list_13 (rdf:rest*) ?listNode_14.
        ?listNode_14 rdf:rest ?nextNode_15.
        ?listNode_14 rdf:first ?literal_16.
      }
    }
  }
 */

References

Morozov A., Wohlgenannt G., Mouromtsev D., Pavlov D., Emelyanov Y. (2019) RAMP Shapes: Declarative RDF ADT Mapping. In: Garoufallou E., Fallucchi F., William De Luca E. (eds) Metadata and Semantic Research. MTSR 2019. Communications in Computer and Information Science, vol 1057. Springer, Cham

https://link.springer.com/chapter/10.1007/978-3-030-36599-8_4

Readme

Keywords

Package Sidebar

Install

npm i ramp-shapes

Weekly Downloads

7

Version

0.11.0

License

MIT

Unpacked Size

1.09 MB

Total Files

149

Last publish

Collaborators

  • alexeymz