ruby-rdf / shex

The Unlicense
12 stars 2 forks source link

ShEx: Shape Expression language for Ruby

This is a pure-Ruby library for working with the Shape Expressions Language to validate the shape of RDF graphs.

Gem Version Build Status Coverage Status Gitter chat DOI

Features

Description

The ShEx gem implements a ShEx Shape Expression engine version 2.0.

Examples

Validating a node using ShExC

require 'rdf/turtle'
require 'shex'

shexc = %(
  PREFIX doap:  <http://usefulinc.com/ns/doap#>
  PREFIX dc:    <http://purl.org/dc/terms/>
  PREFIX ex:    <http://example.com/>

  ex:TestShape EXTRA a {
    a [doap:Project];
    ( doap:name Literal;
      doap:description Literal
    | dc:title Literal;
      dc:description Literal)+;
    doap:category    IRI*;
    doap:developer   IRI+;
    doap:implements [<http://shex.io/shex-semantics/>]
  }
)
graph = RDF::Graph.load("etc/doap.ttl")
schema = ShEx.parse(shexc)
map = {
  RDF::URI("https://rubygems.org/gems/shex") => RDF::URI("http://example.com/TestShape")
}
schema.satisfies?(graph, map)
# => true

Validating a node using ShExJ

require 'rubygems'
require 'rdf/turtle'
require 'shex'

shexj = %({
  "@context": "http://www.w3.org/ns/shex.jsonld",
  "type": "Schema",
  "shapes": [{
    "id": "http://example.com/TestShape",
    "type": "Shape",
    "extra": ["http://www.w3.org/1999/02/22-rdf-syntax-ns#type"],
    "expression": {
      "type": "EachOf",
      "expressions": [{
        "type": "TripleConstraint",
        "predicate": "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
        "valueExpr": {
          "type": "NodeConstraint",
          "values": ["http://usefulinc.com/ns/doap#Project"]
        }
      }, {
        "type": "OneOf",
        "expressions": [{
            "type": "EachOf",
            "expressions": [{
              "type": "TripleConstraint",
              "predicate": "http://usefulinc.com/ns/doap#name",
              "valueExpr": {
                "type": "NodeConstraint",
                "nodeKind": "literal"
              }
            }, {
              "type": "TripleConstraint",
              "predicate": "http://usefulinc.com/ns/doap#description",
              "valueExpr": {
                "type": "NodeConstraint",
                "nodeKind": "literal"
              }
            }]
          }, {
            "type": "EachOf",
            "expressions": [{
              "type": "TripleConstraint",
              "predicate": "http://purl.org/dc/terms/title",
              "valueExpr": {
                "type": "NodeConstraint",
                "nodeKind": "literal"
              }
            }, {
              "type": "TripleConstraint",
              "predicate": "http://purl.org/dc/terms/description",
              "valueExpr": {
                "type": "NodeConstraint",
                "nodeKind": "literal"
              }
            }]
          }],
          "min": 1,
          "max": -1
        }, {
          "type": "TripleConstraint",
          "predicate": "http://usefulinc.com/ns/doap#category",
          "valueExpr": {
            "type": "NodeConstraint",
            "nodeKind": "iri"
          },
          "min": 0,
          "max": -1
        }, {
          "type": "TripleConstraint",
          "predicate": "http://usefulinc.com/ns/doap#developer",
          "valueExpr": {
            "type": "NodeConstraint",
            "nodeKind": "iri"
          },
          "min": 1,
          "max": -1
        }, {
          "type": "TripleConstraint",
          "predicate": "http://usefulinc.com/ns/doap#implements",
          "valueExpr": {
            "type": "NodeConstraint",
            "values": [
              "http://shex.io/shex-semantics/"
            ]
          }
        }
      ]
    }
  }
]})
graph = RDF::Graph.load("etc/doap.ttl")
schema = ShEx.parse(shexj, format: :shexj)
map = {
  RDF::URI("https://rubygems.org/gems/shex") => RDF::URI("http://example.com/TestShape")
}
schema.satisfies?(graph, map)
# => true

Extensions

ShEx has an extension mechanism using Semantic Actions. Extensions may be implemented in Ruby ShEx by sub-classing {ShEx::Extension} and implementing {ShEx::Extension#visit} and possibly {ShEx::Extension#initialize}, {ShEx::Extension#enter}, {ShEx::Extension#exit}, and {ShEx::Extension#close}. The #visit method will be called as part of the #satisfies? operation.

require 'shex'
class ShEx::Test < ShEx::Extension("http://shex.io/extensions/Test/")
  # (see ShEx::Extension#initialize)
  def initialize(schema: nil, logger: nil, depth: 0, **options)
    ...
  end

  # (see ShEx::Extension#visit)
  def visit(code: nil, matched: nil, expression: nil, depth: 0, **options)
    ...
  end
end

The #enter method will be called on any {ShEx::Algebra::TripleExpression} that includes a {ShEx::Algebra::SemAct} referencing the extension, while the #exit method will be called on exit, even if not satisfied.

The #initialize method is called when {ShEx::Algebra::Schema#execute} starts and #close called on exit, even if not satisfied.

To make sure your extension is found, make sure to require it before the shape is executed.

Command Line

When the linkeddata gem is installed, RDF.rb includes a rdf executable which acts as a wrapper to perform a number of different operations on RDF files, including ShEx. The commands specific to ShEx is

Using this command requires either a shex-input where the ShEx schema is URI encoded, or shex, which references a URI or file path to the schema. Other required options are shape and focus.

Example usage:

rdf shex https://raw.githubusercontent.com/ruby-rdf/shex/develop/etc/doap.ttl \
  --schema https://raw.githubusercontent.com/ruby-rdf/shex/develop/etc/doap.shex \
  --focus https://rubygems.org/gems/shex

Documentation

https://ruby-rdf.github.io/shex

Implementation Notes

The ShExC parser uses the EBNF gem to generate a PEG parser.

The parser uses the executable [S-Expressions][] generated from the EBNF ShExC grammar to create a set of executable {ShEx::Algebra} Operators which are directly executed to perform shape validation.

Change Log

See Release Notes on GitHub

Dependencies

Installation

The recommended installation method is via RubyGems. To install the latest official release of RDF.rb, do:

% [sudo] gem install shex

Download

To get a local working copy of the development repository, do:

% git clone git://github.com/ruby-rdf/shex.git

Alternatively, download the latest development version as a tarball as follows:

% wget https://github.com/ruby-rdf/shex/tarball/master

Resources

Mailing List

Author

Contributing

This repository uses Git Flow to mange development and release activity. All submissions must be on a feature branch based on the develop branch to ease staging and integration.

License

This is free and unencumbered public domain software. For more information, see https://unlicense.org/ or the accompanying {file:LICENSE} file.