0.11.0 • Published 2 years ago

ramp-shapes v0.11.0

Weekly downloads
4
License
MIT
Repository
github
Last release
2 years ago

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

FeatureOWL/RDFSSHACLShExJSON-LDRAMP Shapes
Describes closed RDF graph structure
Describes data mapping / serializationrequires frame definition
Has ability to generate query and deserialize results based on shapes
Has RDF representation
Supports RDF listswith workaround
Supports shape unionsthrough shape targets
Supports cardinality constraints (min/max)
Supports recursive shapesdepends on implementation
Supports property paths
Supports ignoring optional non-matching shapesby 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

0.11.0

2 years ago

0.10.0

3 years ago

0.9.0

3 years ago

0.8.0

4 years ago

0.7.0

4 years ago

0.6.0

4 years ago

0.5.0

5 years ago