# Lightning fast, asynchronous, streaming RDF for JavaScript
[![Build Status](https://travis-ci.org/rdfjs/N3.js.svg?branch=master)](https://travis-ci.org/rdfjs/N3.js)
[![Coverage Status](https://coveralls.io/repos/github/rdfjs/N3.js/badge.svg)](https://coveralls.io/github/rdfjs/N3.js)
[![npm version](https://badge.fury.io/js/n3.svg)](https://www.npmjs.com/package/n3)
[![DOI](https://zenodo.org/badge/3058202.svg)](https://zenodo.org/badge/latestdoi/3058202)

The N3.js library is an implementation of the [RDF.js low-level specification](http://rdf.js.org/) that lets you handle [RDF](https://www.w3.org/TR/rdf-primer/) in JavaScript easily.
It offers:

- [**Parsing**](#parsing) triples/quads from
  [Turtle](https://www.w3.org/TR/turtle/),
  [TriG](https://www.w3.org/TR/trig/),
  [N-Triples](https://www.w3.org/TR/n-triples/),
  [N-Quads](https://www.w3.org/TR/n-quads/),
  and [Notation3 (N3)](https://www.w3.org/TeamSubmission/n3/)
- [**Writing**](#writing) triples/quads to
  [Turtle](https://www.w3.org/TR/turtle/),
  [TriG](https://www.w3.org/TR/trig/),
  [N-Triples](https://www.w3.org/TR/n-triples/),
  and [N-Quads](https://www.w3.org/TR/n-quads/)
- [**Storage**](#storing) of triples/quads in memory

Parsing and writing is:
- **asynchronous** – triples arrive as soon as possible
- **streaming** – streams are parsed as data comes in, so you can parse files larger than memory
- **fast** – by far the [fastest spec-compatible parser in JavaScript](https://github.com/rdfjs/N3.js/tree/master/perf)

## Installation
For Node.js, N3.js comes as an [npm package](https://npmjs.org/package/n3).

```Bash
$ npm install n3
```

```JavaScript
const N3 = require('n3');
```

N3.js seamlessly works in browsers via [webpack](https://webpack.js.org/)
or [browserify](http://browserify.org/).
If you're unfamiliar with these tools,
you can read
[_webpack: Creating a Bundle – getting started_](https://webpack.js.org/guides/getting-started/#creating-a-bundle)
or
[_Introduction to browserify_](https://writingjavascript.org/posts/introduction-to-browserify).

## Creating triples/quads
N3.js follows the [RDF.js low-level specification](http://rdf.js.org/).

`N3.DataFactory` will give you the [factory](http://rdf.js.org/#datafactory-interface) functions to create triples and quads:

```JavaScript
const { DataFactory } = N3;
const { namedNode, literal, defaultGraph, quad } = DataFactory;
const myQuad = quad(
  namedNode('https://ruben.verborgh.org/profile/#me'),
  namedNode('http://xmlns.com/foaf/0.1/givenName'),
  literal('Ruben', 'en'),
  defaultGraph(),
);
console.log(myQuad.subject.value);         // https://ruben.verborgh.org/profile/#me
console.log(myQuad.object.value);          // Ruben
console.log(myQuad.object.datatype.value); // http://www.w3.org/1999/02/22-rdf-syntax-ns#langString
console.log(myQuad.object.language);       // en
```

In the rest of this document, we will treat “triples” and “quads” equally:
we assume that a quad is simply a triple in a named or default graph.

## Parsing

### From an RDF document to quads

`N3.Parser` transforms Turtle, TriG, N-Triples, or N-Quads document into quads through a callback:
```JavaScript
const parser = new N3.Parser();
parser.parse(
  `PREFIX c: <http://example.org/cartoons#>
   c:Tom a c:Cat.
   c:Jerry a c:Mouse;
           c:smarterThan c:Tom.`,
  (error, quad, prefixes) => {
    if (quad)
      console.log(quad);
    else
      console.log("# That's all, folks!", prefixes);
  });
```
The callback's first argument is an optional error value, the second is a quad.
If there are no more quads,
the callback is invoked one last time with `null` for `quad`
and a hash of prefixes as third argument.
<br>
Pass a second callback to `parse` to retrieve prefixes as they are read.
<br>
If no callbacks are provided, parsing happens synchronously.

By default, `N3.Parser` parses a permissive superset of Turtle, TriG, N-Triples, and N-Quads.
<br>
For strict compatibility with any of those languages, pass a `format` argument upon creation:

```JavaScript
const parser1 = N3.Parser({ format: 'N-Triples' });
const parser2 = N3.Parser({ format: 'application/trig' });
```

Notation3 (N3) is supported _only_ through the `format` argument:

```JavaScript
const parser3 = N3.Parser({ format: 'N3' });
const parser4 = N3.Parser({ format: 'Notation3' });
const parser5 = N3.Parser({ format: 'text/n3' });
```

It is possible to provide the base IRI of the document that you want to parse.
This is done by passing a `baseIRI` argument upon creation:
```JavaScript
const parser = new N3.Parser({ baseIRI: 'http://example.org/' });
``` 

### From an RDF stream to quads

`N3.Parser` can parse [Node.js streams](http://nodejs.org/api/stream.html) as they grow,
returning quads as soon as they're ready.

```JavaScript
const parser = N3.Parser(),
      rdfStream = fs.createReadStream('cartoons.ttl');
parser.parse(rdfStream, console.log);
```

`N3.StreamParser` is a [Node.js stream](http://nodejs.org/api/stream.html) and [RDF.js Sink](http://rdf.js.org/#sink-interface) implementation.
This solution is ideal if your consumer is slower,
since source data is only read when the consumer is ready.

```JavaScript
const streamParser = N3.StreamParser(),
      rdfStream = fs.createReadStream('cartoons.ttl');
rdfStream.pipe(streamParser);
streamParser.pipe(new SlowConsumer());

function SlowConsumer() {
  const writer = new require('stream').Writable({ objectMode: true });
  writer._write = (quad, encoding, done) => {
    console.log(quad);
    setTimeout(done, 1000);
  };
  return writer;
}
```

A dedicated `prefix` event signals every prefix with `prefix` and `term` arguments.

## Writing

### From quads to a string

`N3.Writer` serializes quads as an RDF document.
Write quads through `addQuad`.

```JavaScript
const writer = N3.Writer({ prefixes: { c: 'http://example.org/cartoons#' } });
writer.addQuad(
  namedNode('http://example.org/cartoons#Tom'),
  namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'),
  namedNode('http://example.org/cartoons#Cat')
);
writer.addQuad(quad(
  namedNode('http://example.org/cartoons#Tom'),
  namedNode('http://example.org/cartoons#name'),
  literal('Tom')
));
writer.end((error, result) => console.log(result));
```

By default, `N3.Writer` writes Turtle (or TriG if some quads are in a named graph).
<br>
To write N-Triples (or N-Quads) instead, pass a `format` argument upon creation:

```JavaScript
const writer1 = N3.Writer({ format: 'N-Triples' });
const writer2 = N3.Writer({ format: 'application/trig' });
```

### From quads to an RDF stream

`N3.Writer` can also write quads to a Node.js stream.

```JavaScript
const writer = N3.Writer(process.stdout, { end: false, prefixes: { c: 'http://example.org/cartoons#' } });
writer.addQuad(
  namedNode('http://example.org/cartoons#Tom'),
  namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'),
  namedNode('http://example.org/cartoons#Cat')
);
writer.addQuad(quad(
  namedNode('http://example.org/cartoons#Tom'),
  namedNode('http://example.org/cartoons#name'),
  literal('Tom')
));
writer.end();
```

### From a quad stream to an RDF stream

`N3.StreamWriter` is a [Node.js stream](http://nodejs.org/api/stream.html) and [RDF.js Sink](http://rdf.js.org/#sink-interface) implementation.

```JavaScript
const streamParser = new N3.StreamParser(),
      inputStream = fs.createReadStream('cartoons.ttl'),
      streamWriter = new N3.StreamWriter({ prefixes: { c: 'http://example.org/cartoons#' } });
inputStream.pipe(streamParser);
streamParser.pipe(streamWriter);
streamWriter.pipe(process.stdout);
```

### Blank nodes and lists
You might want to use the `[…]` and list `(…)` notations of Turtle and TriG.
However, a streaming writer cannot create these automatically:
the shorthand notations are only possible if blank nodes or list heads are not used later on,
which can only be determined conclusively at the end of the stream.

The `blank` and `list` functions allow you to create them manually instead:
```JavaScript
const writer = N3.Writer({ prefixes: { c: 'http://example.org/cartoons#',
                                       foaf: 'http://xmlns.com/foaf/0.1/' } });
writer.addQuad(
  writer.blank(
    namedNode('http://xmlns.com/foaf/0.1/givenName'),
    literal('Tom', 'en')),
  namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'),
  namedNode('http://example.org/cartoons#Cat')
);
writer.addQuad(quad(
  namedNode('http://example.org/cartoons#Jerry'),
  namedNode('http://xmlns.com/foaf/0.1/knows'),
  writer.blank([{
    predicate: namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'),
    object:    namedNode('http://example.org/cartoons#Cat'),
  },{
    predicate: namedNode('http://xmlns.com/foaf/0.1/givenName'),
    object:    literal('Tom', 'en'),
  }])
));
writer.addQuad(
  namedNode('http://example.org/cartoons#Mammy'),
  namedNode('http://example.org/cartoons#hasPets'),
  writer.list([
    namedNode('http://example.org/cartoons#Tom'),
    namedNode('http://example.org/cartoons#Jerry'),
  ])
);
writer.end((error, result) => console.log(result));
```

## Storing

`N3.Store` allows you to store triples in memory and find them fast.

In this example, we create a new store and add the triples `:Pluto a :Dog.` and `:Mickey a :Mouse`.
<br>
Then, we find triples with `:Mickey` as subject.

```JavaScript
const store = N3.Store();
store.addQuad(
  namedNode('http://ex.org/Pluto'), 
  namedNode('http://ex.org/type'),
  namedNode('http://ex.org/Dog')
);
store.addQuad(
  namedNode('http://ex.org/Mickey'),
  namedNode('http://ex.org/type'),
  namedNode('http://ex.org/Mouse')
);

const mickey = store.getQuads(namedNode('http://ex.org/Mickey'), null, null)[0];
console.log(mickey);
```

### Addition and deletion of quads
The store provides the following manipulation methods
([documentation](http://rdfjs.github.io/N3.js/docs/N3Store.html)):
- `addQuad` to insert one quad
- `addQuads` to insert an array of quads
- `removeQuad` to remove one quad
- `removeQuads` to remove an array of quads
- `createBlankNode` returns an unused blank node identifier

### Searching quads or entities
The store provides the following search methods
([documentation](http://rdfjs.github.io/N3.js/docs/N3Store.html)):
- `getQuads` returns an array of quads matching the given pattern
- `countQuads` counts the number of quads matching the given pattern
- `forEach` executes a callback on all matching quads
- `every` returns whether a callback on matching quads always returns true
- `some`  returns whether a callback on matching quads returns true at least once
- `getSubjects` returns an array of unique subjects occurring in matching quads
- `forSubjects` executes a callback on unique subjects occurring in matching quads
- `getPredicates` returns an array of unique predicates occurring in matching quad
- `forPredicates` executes a callback on unique predicates occurring in matching quads
- `getObjects` returns an array of unique objects occurring in matching quad
- `forObjects` executes a callback on unique objects occurring in matching quads
- `getGraphs` returns an array of unique graphs occurring in matching quad
- `forGraphs` executes a callback on unique graphs occurring in matching quads

## Compatibility
### Format specifications
The N3.js parser and writer is fully compatible with the following W3C specifications:
- [RDF 1.1 Turtle](https://www.w3.org/TR/turtle/)
  – [EARL report](https://raw.githubusercontent.com/rdfjs/N3.js/earl/n3js-earl-report-turtle.ttl)
- [RDF 1.1 TriG](https://www.w3.org/TR/trig/)
  – [EARL report](https://raw.githubusercontent.com/rdfjs/N3.js/earl/n3js-earl-report-trig.ttl)
- [RDF 1.1 N-Triples](https://www.w3.org/TR/n-triples/)
  – [EARL report](https://raw.githubusercontent.com/rdfjs/N3.js/earl/n3js-earl-report-ntriples.ttl)
- [RDF 1.1 N-Quads](https://www.w3.org/TR/n-quads/)
  – [EARL report](https://raw.githubusercontent.com/rdfjs/N3.js/earl/n3js-earl-report-nquads.ttl)

In addition, the N3.js parser also supports [Notation3 (N3)](https://www.w3.org/TeamSubmission/n3/) (no official specification yet).

Pass a `format` option to the constructor with the name or MIME type of a format
for strict, fault-intolerant behavior.

### Interface specifications
The N3.js submodules are compatible with the following [RDF.js](http://rdf.js.org) interfaces:

- `N3.DataFactory` implements
  [`DataFactory`](http://rdf.js.org/#datafactory-interface)
  - the terms it creates implement [`Term`](http://rdf.js.org/#term-interface)
    and one of
    [`NamedNode`](http://rdf.js.org/#namednode-interface),
    [`BlankNode`](http://rdf.js.org/#blanknode-interface),
    [`Literal`](http://rdf.js.org/#litereal-interface),
    [`Variable`](http://rdf.js.org/#variable-interface),
    [`DefaultGraph`](http://rdf.js.org/#defaultgraph-interface)
  - the triples/quads it creates implement
    [`Triple`](http://rdf.js.org/#triple-interface)
    and
    [`Quad`](http://rdf.js.org/#quad-interface)
- `N3.StreamParser` implements
  [`Stream`](http://rdf.js.org/#stream-interface)
  and
  [`Sink`](http://rdf.js.org/#sink-interface)
- `N3.StreamWriter` implements
  [`Stream`](http://rdf.js.org/#stream-interface)
  and
  [`Sink`](http://rdf.js.org/#sink-interface)
- `N3.Store` implements
  [`Sink`](http://rdf.js.org/#sink-interface)

## License and contributions
The N3.js library is copyrighted by [Ruben Verborgh](https://ruben.verborgh.org/)
and released under the [MIT License](https://github.com/rdfjs/N3.js/blob/master/LICENSE.md).

Contributions are welcome, and bug reports or pull requests are always helpful.
If you plan to implement a larger feature, it's best to contact me first.
