RDF::N3 reader/writer and reasoner

Notation-3 reader/writer for RDF.rb .

Gem Version Build Status Coverage Status


RDF::N3 is an Notation-3 parser and reasoner for Ruby using the RDF.rb library suite.

Reader inspired from TimBL predictiveParser and Python librdf implementation.

Uses CG Specification

This version tracks the W3C N3 Community Group Specification which has incompatibilities with the Team Submission version. Notably:

This brings N3 closer to compatibility with Turtle.


RDF::N3 parses Notation-3, Turtle and N-Triples into statements or quads. It also performs reasoning and serializes to N3.

Install with gem install rdf-n3



Instantiate a reader from a local file:

RDF::N3::Reader.open("etc/foaf.n3") do |reader|
   reader.each_statement do |statement|
     puts statement.inspect

Define @base and @prefix definitions, and use for serialization using :base_uri an :prefixes options

Write a graph to a file:

RDF::N3::Writer.open("etc/test.n3") do |writer|
   writer << graph


Experimental N3 reasoning is supported. Instantiate a reasoner from a dataset:

RDF::N3::Reasoner.new do |reasoner|
  RDF::N3::Reader.open("etc/foaf.n3") {|reader| reasoner << reader}

   reader.each_statement do |statement|
     puts statement.inspect

Reasoning is performed by turning a repository containing formula and predicate operators into an executable set of operators (similar to the executable SPARQL Algebra). Reasoning adds statements to the base dataset, marked with :inferred (e.g. statement.inferred?). Predicate operators are defined from the following vocabularies.

When dispatching built-in operators, precedence is given to operators whos operands are fully evaluated, followed by those having only variable output operands, followed by those having the fewest operands. Operators are evaluated until either no solutions are derived, or all operators have been completed.

Reasoning is discussed in the Design Issues document.

RDF List vocabulary http://www.w3.org/2000/10/swap/list#

RDF Log vocabulary http://www.w3.org/2000/10/swap/log#

RDF Math vocabulary http://www.w3.org/2000/10/swap/math#

RDF String vocabulary http://www.w3.org/2000/10/swap/str#

RDF Time vocabulary <>


N3 Formulae are introduced with the { statement-list } syntax. A given formula is assigned an RDF::Node instance, which is also used as the graph_name for RDF::Statement instances provided to RDF::N3::Reader#each_statement. For example, the following N3 generates the associated statements:

@prefix x: <http://example.org/x-ns/#> .
@prefix log: <http://www.w3.org/2000/10/swap/log#> .
@prefix dc: <http://purl.org/dc/elements/1.1/#> .

{ [ x:firstname  "Ora" ] dc:wrote [ dc:title  "Moby Dick" ] } a log:falsehood .

when turned into an RDF Repository results in the following quads

_:form <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2000/10/swap/log#falsehood> .
_:moby <http://purl.org/dc/elements/1.1/#title> "Moby Dick" _:form .
_:ora <http://purl.org/dc/elements/1.1/#wrote> _:moby _:form .
_:ora <http://example.org/x-ns/#firstname> "Ora" _:form .

Reasoning uses a Notation3 Algebra, similar to SPARQL S-Expressions. This implementation considers formulae to be patterns, which may be asserted on statements made in the default graph, possibly loaded from a separate file. The logical relationships are reduced to algebraic operators.


N3 Variables are introduced with @forAll, @forSome, or ?x. Variables reference URIs described in formulae, typically defined in the default vocabulary (e.g., ":x"). Existential variables are replaced with an allocated RDF::Node instance. Universal variables are replaced with a RDF::Query::Variable instance. For example, the following N3 generates the associated statements:

@forAll <#h>. @forSome <#g>. <#g> <#loves> <#h> .

results in:

h = RDF::Query::Variable.new(<#h>)
g = RDF::Node.new()
RDF::Statement(f, <#loves>, h)

Note that the behavior of both existential and universal variables is not entirely in keeping with the Team Submission, and neither work quite like SPARQL variables. When used in the antecedent part of an implication, universal variables should behave much like SPARQL variables. This area is subject to a fair amount of change.


Formulae are typically used to query the knowledge-base, which is set from the base-formula/default graph. A formula is composed of both constant statements, and variable statements. When running as a query, such as for the antecedent formula in log:implies, statements including either explicit variables or blank nodes are treated as query patterns and are used to query the knowledge base to create a solution set, which is used either prove the formula correct, or create bindings passed to the consequent formula.

Blank nodes associated with rdf:List statements used as part of a built-in are made non-distinguished existential variables, and patters containing these variables become optional. If they are not bound as part of the query, the implicitly are bound as the original blank nodes defined within the formula, which allows for both constant list arguments, list arguments that contain variables, or arguments which are variables expanding to lists.



Full documentation available on RubyDoc.info

Principle Classes

Additional vocabularies




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.


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