graphy.js

A collection of RDF libraries for JavaScript

View the Project on GitHub

« API / Concise Terms, Triples and Quads

This document describes a language for concisely expressing RDF data from within a JavaScript programming environment, allowing for a convenient technique of mixing in data from live variables and objects to create RDF quads and RDF terms such as named nodes, blank nodes, and literals.

Introduction

Concise hashes allow for representing RDF quads and triples in a convenient tree structure. In addition to providing a simple, human-readable interface to constructing RDF data, they also greatly improve the bandwidth of passing around chunks of RDF data between readers, datasets and serializers. Furthermore, special value types can be used within concise hashes (in full-mode) to nest anonymous blank node structures or linked-list structures such as RDF collections, serialize comments or newlines, and configure serializer output options. All of these features make concise hashes an ideal data structure for generating RDF programatically.

Example:

// snippets/concise-triples.js
const factory = require('@graphy/core.data.factory');
const ttl_write = require('@graphy/content.ttl.write');

// create a Turtle content writer
let ds_writer = ttl_write({
   prefixes: {
      rdf: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
      rdfs: 'http://www.w3.org/2000/01/rdf-schema#',
      owl: 'http://www.w3.org/2002/07/owl#',
      dbr: 'http://dbpedia.org/resource/',
      dbo: 'http://dbpedia.org/ontology/',
      demo: 'http://ex.org/demo#',
      eg: 'http://ex.org/owl#',
   },
});

// pipe to stdout
ds_writer.pipe(process.stdout);

// write some triples using a concise triples hash
ds_writer.write({
   type: 'c3',
   value: {
      // triples about dbr:Banana
      [factory.comment()]: 'hey look, a comment!',
      'dbr:Banana': {
         // `a` is shortcut for rdf:type
         a: 'dbo:Plant',

         // primitive ES types map to XSD datatypes
         'eg:boolean': true,
         'eg:integer': 42,
         'eg:decimal': 0.1,
         'eg:infinity': Infinity,

         // list of objects
         'rdfs:label': ['@en"Banana', '@fr"Banane', '@es"Plátano'],

         // nested array becomes an RDF collection
         'demo:steps': [
            ['demo:Peel', 'demo:Slice', 'demo:distribute'],
         ],
      },

      // example from OWL 2 primer: https://www.w3.org/TR/owl2-primer/#Property_Restrictions
      [factory.comment()]: 'hey look, another comment!',
      'eg:HappyPerson': {
         a: 'owl:Class',

         // nesting an anonymous blank node
         'owl:equivalentClass': {
            a: 'owl:Class',

            // a list of objects
            'owl:intersectionOf': [
               [
                  // nested anonymous blank node
                  {
                     a: 'owl:Restriction',
                     'owl:onProperty': 'eg:hasChild',
                     'owl:allValuesFrom': 'eg:Happy',
                  },
                  // another nested anonymous blank node
                  {
                     a: 'owl:Restriction',
                     'owl:onProperty': 'eg:hasChild',
                     'owl:someValuesFrom': 'eg:Happy',
                  },
               ],
            ],
         },
      },
   },
});

// end the writable side of the transform
ds_writer.end();

Outputs:

@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix dbr: <http://dbpedia.org/resource/> .
@prefix dbo: <http://dbpedia.org/ontology/> .
@prefix demo: <http://ex.org/demo#> .
@prefix eg: <http://ex.org/owl#> .

# hey look, a comment!
dbr:Banana a dbo:Plant ;
   eg:boolean true ;
   eg:integer 42 ;
   eg:decimal 0.1 ;
   eg:infinity "INF"^^<http://www.w3.org/2001/XMLSchema#double> ;
   rdfs:label "Banana"@en, "Banane"@fr, "Plátano"@es ;
   demo:steps (
      demo:Peel
      demo:Slice
      demo:distribute
   ) .

# hey look, another comment!
eg:HappyPerson a owl:Class ;
   owl:equivalentClass [
      rdf:type owl:Class ;
      owl:intersectionOf (
         [
            rdf:type owl:Restriction ;
            owl:onProperty eg:hasChild ;
            owl:allValuesFrom eg:Happy ;
         ]
         [
            rdf:type owl:Restriction ;
            owl:onProperty eg:hasChild ;
            owl:someValuesFrom eg:Happy ;
         ]
      ) ;
   ] .


#string/c1 – Concise Term String

The concise term string defines a syntax that allows developers to quickly create RDF terms such as named nodes, blank nodes, and literals from a simple string. The syntax should be familiar to those who use Turtle.

The first character of the string dictates what type of Term it is:

Named Nodes: No Closing Brackets

Notice that the first character to indicate an absolute IRI is the right-angle bracket >. This was selected intentionally to remind you that the format does not have a closing bracket for absolute IRIs.

let p_iri = 'http://dbpedia.org/resource/9/11_Memorial_(Arizona)';
let yt_node = factory.c1('>'+p_iri);

Labeled Blank Nodes: When to Use Them

There’s not much need to create labeled blank nodes using concise-term strings since you can implicitly create them using concise triple and concise quad hashes. However, if you need to create new triples where the subject is a blank node, or need to use labeled blank nodes, this syntax will allow you to create them explicitly.

let a_triples = [...factory.c3({
    '_:b1': {
        // usual blank node label
        '>http://ex.org/dislikes': '_:b2',

        // some custom blank node label
        '>http://ex.org/pointsTo': '_:someLabeledBlankNode',

        // automatically creates a unique labeled blank node (using uuidv4)
        '>http://ex.org/unique': '_:',

        // creates anonymous blank node
        '>http://ex.org/anonymous': {},

        // creates anonymous blank node with its own triple(s)
        '>http://ex.org/likes': {
            a: '>http://ex.org/AnonymousBlankNode',
        },
    },
})];

Literals: No Escaping Needed

Since only one term can be expressed in a string, the syntax does not need to have delimiters for the start or end of certain sequences and so the contents of a Literal do not need to be escaped. For example, a plain RDF literal can be expressed like so:

let s_expression = 'Hello World!';
let yt_greeting = factory.c1('"'+s_expression);

Here, the double quote at position 0 indicates that this is a plain literal, and that the contents follow (until the end of the string). If you wanted to add quote characters to the contents of the RDF literal, it would simply look like this:

let s_expression = '"Hello World!"';
let yt_greeting = factory.c1('"'+s_expression);

Prefixed Names: All Characters Allowed

The ‘suffix’ of prefixed names may contain any character, such as /, ., ,, and so on, without having to worry about the way it is serialized to the output destination. Invalid IRI characters ([#x00-#x20<>"{}|^]`) will be automatically converted to unicode escape sequences.

let h_prefixes = {dbr:'http://dbpedia.org/resource/'};
let yt_node = factory.c1('dbr:9/11_Memorial_(Arizona)', h_prefixes);
yt_node.value;  // 'http://dbpedia.org/resource/9/11_Memorial_(Arizona)'

Concise Term String Grammar

State Production
Term NamedNode | BlankNode | Literal | DefaultGraph | Variable | Directive
NamedNode AbsoluteIRI | PrefixedName | TypeAlias
AbsoluteIRI '>' .*
PrefixedName ([^_:@"^`][^:]*)? ':' .*
TypeAlias 'a'
BlankNode '_' ':' .*
Literal PlainLiteral | DatatypedLiteral | LanguagedLiteral
PlainLiteral '"' .*
DatatypedLiteral '^' Datatype PlainLiteral
Datatype '>' [^"]* | ([^:@"^\`][^:"]*)? ':' [^"]*
LanguagedLiteral '@' [a-zA-Z0-9-]+ PlainLiteral
DefaultGraph '*'
Variable '?' .*
Directive '`' '[' uuid_v4 ']' JSON

Hash Interfaces:

A ‘hash’ refers to a dictionary (a plain ES object) value with enumerable properties (which themselves may or may not be defined in value’s prototype chain). The following section documents the implications of the key and value types.

Directives

Directives allow for special events to be passed to the output serializer at a given location within the document, such as for the insertion of comments and newlines, as well as to configure scoped options such as list structure. The following functions create directive strings which can be used as the keys in concise triples and concise quads hashes:


#hash/c4r – Concise Quads Hash (strict-mode)

A concise quads hash in strict-mode describes a plain object whose keys represent the graph of a set of quads, and whose values are concise triple hashes in strict-mode, which represent the subjects, predicates and objects related to the graph/subject/predicate combinations in a tree-like structure.

Example:

// snippets/concise-quads-strict-mode.js
const trig_write = require('@graphy/content.trig.write');

// create a TriG content writer
let ds_writer = trig_write({
   prefixes: {
      rdf: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
      rdfs: 'http://www.w3.org/2000/01/rdf-schema#',
      owl: 'http://www.w3.org/2002/07/owl#',
      dbr: 'http://dbpedia.org/resource/',
      dbo: 'http://dbpedia.org/ontology/',
      dc: 'http://purl.org/dc/terms/',
      foaf: 'http://xmlns.com/foaf/0.1/',
      demo: 'http://ex.org/demo#',
   },
});

// pipe to stdout
ds_writer.pipe(process.stdout);

// write some quads using a concise quads hash
ds_writer.write({
   type: 'c4r',
   value: {  // example 2 from TriG: https://www.w3.org/TR/trig/
      '*': {
         'demo:bob': {
            'dc:publisher': ['"Bob'],
         },
         'demo:alice': {
            'dc:publisher': ['"Alice'],
         },
      },

      'demo:bob': {
         '_:a': {
            'foaf:name': ['"Bob'],
            'foaf:mbox': ['>mailto:bob@oldcorp.example.org'],
            'foaf:knows': ['_:b'],
         },
      },

      'demo:alice': {
         '_:b': {
            'foaf:name': ['"Alice'],
            'foaf:mbox': ['>mailto:alice@work.example.org'],
         },
      },
   },
});

// end the writable side of the transform
ds_writer.end();

Outputs:

@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix dbr: <http://dbpedia.org/resource/> .
@prefix dbo: <http://dbpedia.org/ontology/> .
@prefix dc: <http://purl.org/dc/terms/> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix demo: <http://ex.org/demo#> .

{
   demo:bob dc:publisher "Bob" .

   demo:alice dc:publisher "Alice" .
}

demo:bob {
   _:a foaf:name "Bob" ;
      foaf:mbox <mailto:bob@oldcorp.example.org> ;
      foaf:knows _:b .
}

demo:alice {
   _:b foaf:name "Alice" ;
      foaf:mbox <mailto:alice@work.example.org> .
}



#hash/c4 – Concise Quads Hash (full-mode)

Extends the strict-mode version by allowing the use of directives in keys (such as embedded comments, newlines, etc.), as well as more flexible ways to write RDF objects including nested blank nodes, list structures, collections, extensible coercible type (e.g., instances of Date and Number), and strings.

A concise quads hash describes a plain object whose keys represent the graph of a set of quads, and whose values are concise triple hashes, which represent the subjects, predicates and objects, list structures, collections, or nested blank nodes related to the graph/subject/predicate combinations in a tree-like structure.

Example:

// snippets/concise-quads.js
const factory = require('@graphy/core.data.factory');
const trig_write = require('@graphy/content.trig.write');

// create a TriG content writer
let ds_writer = trig_write({
   prefixes: {
      rdf: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
      rdfs: 'http://www.w3.org/2000/01/rdf-schema#',
      owl: 'http://www.w3.org/2002/07/owl#',
      dbr: 'http://dbpedia.org/resource/',
      dbo: 'http://dbpedia.org/ontology/',
      dc: 'http://purl.org/dc/terms/',
      foaf: 'http://xmlns.com/foaf/0.1/',
      demo: 'http://ex.org/demo#',
   },
});

// pipe to stdout
ds_writer.pipe(process.stdout);

// write some quads using a concise quads hash
ds_writer.write({
   type: 'c4',
   value: {  // example 2 from TriG: https://www.w3.org/TR/trig/
      [factory.comment()]: 'default graph',
      '*': {
         'demo:bob': {
            'dc:publisher': '"Bob',
         },
         'demo:alice': {
            'dc:publisher': '"Alice',
         },
      },

      'demo:bob': {
         '_:a': {
            'foaf:name': '"Bob',
            'foaf:mbox': '>mailto:bob@oldcorp.example.org',
            'foaf:knows': '_:b',
         },
      },

      'demo:alice': {
         '_:b': {
            'foaf:name': '"Alice',
            'foaf:mbox': '>mailto:alice@work.example.org',
         },
      },
   },
});

// end the writable side of the transform
ds_writer.end();

Outputs:

@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix dbr: <http://dbpedia.org/resource/> .
@prefix dbo: <http://dbpedia.org/ontology/> .
@prefix dc: <http://purl.org/dc/terms/> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix demo: <http://ex.org/demo#> .

# default graph
{
   demo:bob dc:publisher "Bob" .

   demo:alice dc:publisher "Alice" .
}

demo:bob {
   _:a foaf:name "Bob" ;
      foaf:mbox <mailto:bob@oldcorp.example.org> ;
      foaf:knows _:b .
}

demo:alice {
   _:b foaf:name "Alice" ;
      foaf:mbox <mailto:alice@work.example.org> .
}



#hash/c3r – Concise Triples Hash (strict-mode)

A concise triples in strict-mode hash describes a plain object whose keys represent the subject of a set of triples, and whose values are concise pair hashes, which represent the objects, list structures, collections, or nested blank nodes related to the subject/predicate combination in a tree-like structure.

Example:

// snippets/concise-triples-strict-mode.js
const ttl_write = require('@graphy/content.ttl.write');

// create a Turtle content writer
let ds_writer = ttl_write({
   prefixes: {
      rdf: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
      rdfs: 'http://www.w3.org/2000/01/rdf-schema#',
      owl: 'http://www.w3.org/2002/07/owl#',
      dbr: 'http://dbpedia.org/resource/',
      dbo: 'http://dbpedia.org/ontology/',
      demo: 'http://ex.org/demo#',
      eg: 'http://ex.org/owl#',
   },
});

// pipe to stdout
ds_writer.pipe(process.stdout);

// write some triples using a concise triples hash
ds_writer.write({
   type: 'c3r',
   value: {
      // triples about dbr:Banana
      'dbr:Banana': {
         // `a` is shortcut for rdf:type
         a: ['dbo:Plant'],

         // list of objects
         'rdfs:label': ['@en"Banana', '@fr"Banane', '@es"Plátano'],

         // nested objects are not allowed in strict-mode
         // they must be encoded as blank nodes
         'demo:steps': ['_:b0'],
      },

      '_:b0': {
         'rdf:first': ['demo:Peel'],
         'rdf:rest': ['_:b1'],
      },

      '_:b1': {
         'rdf:first': ['demo:Slice'],
         'rdf:rest': ['_:b2'],
      },

      '_:b2': {
         'rdf:first': ['demo:distribute'],
         'rdf:rest': ['rdf:nil'],
      },
   },
});

// end the writable side of the transform
ds_writer.end();

Outputs:

@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix dbr: <http://dbpedia.org/resource/> .
@prefix dbo: <http://dbpedia.org/ontology/> .
@prefix demo: <http://ex.org/demo#> .
@prefix eg: <http://ex.org/owl#> .

dbr:Banana a dbo:Plant ;
   rdfs:label "Banana"@en, "Banane"@fr, "Plátano"@es ;
   demo:steps _:b0 .

_:b0 rdf:first demo:Peel ;
   rdf:rest _:b1 .

_:b1 rdf:first demo:Slice ;
   rdf:rest _:b2 .

_:b2 rdf:first demo:distribute ;
   rdf:rest rdf:nil .



#hash/c3 – Concise Triples Hash (full-mode)

Extends the strict-mode version by allowing the use of directives in keys (such as embedded comments, newlines, etc.), as well as more flexible ways to write RDF objects including nested blank nodes, list structures, collections, extensible coercible type (e.g., instances of Date and Number), and strings.

A concise triples hash describes a plain object whose keys represent the subject of a set of triples, and whose values are concise pair hashes, which represent the objects, list structures, collections, or nested blank nodes related to the subject/predicate combination in a tree-like structure.

Example:

// snippets/concise-triples.js
const factory = require('@graphy/core.data.factory');
const ttl_write = require('@graphy/content.ttl.write');

// create a Turtle content writer
let ds_writer = ttl_write({
   prefixes: {
      rdf: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
      rdfs: 'http://www.w3.org/2000/01/rdf-schema#',
      owl: 'http://www.w3.org/2002/07/owl#',
      dbr: 'http://dbpedia.org/resource/',
      dbo: 'http://dbpedia.org/ontology/',
      demo: 'http://ex.org/demo#',
      eg: 'http://ex.org/owl#',
   },
});

// pipe to stdout
ds_writer.pipe(process.stdout);

// write some triples using a concise triples hash
ds_writer.write({
   type: 'c3',
   value: {
      // triples about dbr:Banana
      [factory.comment()]: 'hey look, a comment!',
      'dbr:Banana': {
         // `a` is shortcut for rdf:type
         a: 'dbo:Plant',

         // primitive ES types map to XSD datatypes
         'eg:boolean': true,
         'eg:integer': 42,
         'eg:decimal': 0.1,
         'eg:infinity': Infinity,

         // list of objects
         'rdfs:label': ['@en"Banana', '@fr"Banane', '@es"Plátano'],

         // nested array becomes an RDF collection
         'demo:steps': [
            ['demo:Peel', 'demo:Slice', 'demo:distribute'],
         ],
      },

      // example from OWL 2 primer: https://www.w3.org/TR/owl2-primer/#Property_Restrictions
      [factory.comment()]: 'hey look, another comment!',
      'eg:HappyPerson': {
         a: 'owl:Class',

         // nesting an anonymous blank node
         'owl:equivalentClass': {
            a: 'owl:Class',

            // a list of objects
            'owl:intersectionOf': [
               [
                  // nested anonymous blank node
                  {
                     a: 'owl:Restriction',
                     'owl:onProperty': 'eg:hasChild',
                     'owl:allValuesFrom': 'eg:Happy',
                  },
                  // another nested anonymous blank node
                  {
                     a: 'owl:Restriction',
                     'owl:onProperty': 'eg:hasChild',
                     'owl:someValuesFrom': 'eg:Happy',
                  },
               ],
            ],
         },
      },
   },
});

// end the writable side of the transform
ds_writer.end();

Outputs:

@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix dbr: <http://dbpedia.org/resource/> .
@prefix dbo: <http://dbpedia.org/ontology/> .
@prefix demo: <http://ex.org/demo#> .
@prefix eg: <http://ex.org/owl#> .

# hey look, a comment!
dbr:Banana a dbo:Plant ;
   eg:boolean true ;
   eg:integer 42 ;
   eg:decimal 0.1 ;
   eg:infinity "INF"^^<http://www.w3.org/2001/XMLSchema#double> ;
   rdfs:label "Banana"@en, "Banane"@fr, "Plátano"@es ;
   demo:steps (
      demo:Peel
      demo:Slice
      demo:distribute
   ) .

# hey look, another comment!
eg:HappyPerson a owl:Class ;
   owl:equivalentClass [
      rdf:type owl:Class ;
      owl:intersectionOf (
         [
            rdf:type owl:Restriction ;
            owl:onProperty eg:hasChild ;
            owl:allValuesFrom eg:Happy ;
         ]
         [
            rdf:type owl:Restriction ;
            owl:onProperty eg:hasChild ;
            owl:someValuesFrom eg:Happy ;
         ]
      ) ;
   ] .



#hash/c2r – Concise Pairs Hash (strict-mode)

A concise pairs hash in strict-mode describes a plain object whose keys represent the predicate of a set of predicate/object pairs, and whose values are an Array of ConciseObjectItems.


#hash/c2 – Concise Pairs Hash (full-mode)

A concise pairs hash describes a plain object whose keys represent the predicate of a set of predicate/object pairs, and whose values are ConciseObjects, which represent the objects, list structures, collections, or nested blank nodes related to the predicate in a tree-like structure.


Values

Definitions for the expected types on the values supplied within concise pairs hashes in full-mode.

value ConciseObject

A value that must be one of the following types:

value ConciseObjectItem extends ConciseObject

A value that expects the same types as ConciseObject with one overriding feature: