HOWL makes it easy for humans to read and write RDF and OWL. Here you'll find a description of HOWL, examples, and tools for working with HOWL data.
This is work-in-progress. Your feedback is appreciated!
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.w4.org/2001/XMLSchema#
PREFIX owl:> http://www.w3.org/2002/07/owl#
PREFIX obo:> http://purl.obolibrary.org/obo/
PREFIX ex:> http://example.com/
LABEL rdf:type: type
LABEL rdfs:label: label
LABEL rdfs:comment: comment
LABEL obo:BFO_0000051: has part
TYPE comment:> xsd:string
ex:ontology
label: Example Ontology
type:> owl:Ontology
ex:foo
label: Foo
type:> owl:Class
comment: A comment on 'Foo'.@en
> comment: An annotation on the comment.^^xsd:string
>> comment: An annotation on the annotation.
comment: Values can span multiple lines,
and include blank lines...
as long as each line after the first
is indented with two spaces.
ex:bar
label: Bar
type:> owl:Class
subClassOf:>> 'has part' some Bar
# Lines starting with '#' are just comments.
For more examples, see the demo site, the ontology directory, and the Makefile.
The 0.2 series supports:
- draft HOWL syntax (some changes from 0.1)
- basic OWL class expressions from Protégé:
not
,and
,or
,some
,only
- converting HOWL to N-Triples, N-Quads, or JSON
You can use another tool such as rapper or Jena riot to convert from N-Triples/N-Quads to any other concrete RDF or OWL syntax.
Not yet supported: Converting to HOWL from other RDF and OWL syntaxes.
You can install HOWL as:
- a command-line tool (
howl
) - a Clojure library
- a JavaScript library
The howl
command-line tool requires Java (1.6+). On Unix (Linux, Mac OS X):
- Download a released version of the
howl-X.Y.Z.jar
file, or build it yourself by following the instructions below - Rename the file to
howl
, put it on your PATH, and make it executable:chmod +x howl
- Run
howl
on one or more HOWL files to convert them to N-Triples:
howl input.howl input2.howl > output.nt
Run howl --help
for more options. The howl
file is a JAR, so you can also run java -jar howl
, with standard Java options.
On Windows, download the JAR file and run it from the Command Prompt using Java (not tested!):
java -jar howl.jar input.howl input2.howl > output.nt
HOWL is also available as a Clojure/ClojureScript library. See the Clojars page for details:
- Download a released version of the
howl-X.Y.Z.js
file, or build it yourself by following the instructions below - Add a
<script>
tag to your HTML page:<script src="howl.js" type="text/javascript" charset="utf-8"></script>
- Call one of the API functions:
var your_quad_string = howl.api.convert_to_quads(your_howl_string);
It might also work under Node.js -- let us know!
Features in this example:
PREFIX ex:> http://example.com/
- set prefixes, similar to Turtle and SPARQL
LABEL obo:BFO_0000051: has part
- like PREFIXes for single terms
TYPE comment:> xsd:string
- set default language tag or datatype for a predicate
- prefixes, labels, and types
- can occur at any point in the document
- can be included from an external document, keeping the main document very simple
- can be automatically generated using tools (not yet supported)
ex:ontology
- specify the current subject by its prefixed name, IRI, or label
label: Example Ontology
- use
:
for literal statements - specify a predicate by its prefixed name, IRI, or label
- literals quotation marks
- multi-line literals are indented
- optionally append a language tag or datatype
- use
type:> owl:Ontology
- use
:>
for link statements (when the object is a node) - specify the object by its prefixed name, IRI, or label
- use
subClassOf:>> 'has part' some Bar
- use
:>>
for expression statements - supports Manchester syntax, as used in Protégé
- use
> comment: An annotation on the comment.^^xsd:string
- use
>
for an OWL annotation - use
>>
for nested annotations (and so on)
- use
Other features, not in this example:
- RDF dataset support: default graph and zero or more named graphs using
GRAPH
- set or change the
BASE
IRI at any point in the document
Behind the scenes:
- line-based format for stream processing
- JSON format for parse information, for language agnostic tooling
HOWL is designed to be simple and predictable. The most common mistakes will probably be using a label that has not been defined, or using the wrong separator.
:
for text, numbers, dates, and other literal values:>
for links:>>
for complex expressions, i.e. things that link to things
There are plans for tools that will:
- check for missing labels
- checking for dangerous or misleading labels
- find missing labels among a list of ontologies, and write them to a file
- update labels, using the IRI to replacing an old label with a new label
- "linting" statements to infer whether the user meant to use a literal, link, or expression
RDF is built up from IRIs. IRIs provide a flexible system for using, creating, and reusing a practically unlimited number of globally unique names. But IRIs are often difficult for humans to read and write.
The prefixed names used in Turtle and SPARQL syntax are shorter than full IRIs and are often easier to read and write. We have tools for translating between prefixed names and their full IRIs.
HOWL goes one step further, supporting human-readable labels in almost every place that an IRI can be used. The HOWL tools take care of the translation between labels and the IRIs that they denote. A HOWL label is a string that:
- must not begin or end with whitespace
- must not contain newlines or tabs
- must not begin with a reserved word (case sensitive) followed by a space: BASE, PREFIX, LABEL, TYPE, GRAPH
- must not begin with
#
- must not begin with
>
- must not contain
:
(colon space) - must not contain
:>
(colon arrow space) - must not contain
:>>
(colon arrow arrow space)
HOWL labels are defined either by LABEL
blocks, or when an rdfs:label
is asserted for a subject and that label meets these criteria.
HOWL is build from a sequence of "blocks". Each block is a string consisting of one line of text, followed by zero or more blank or indented lines of text. HOWL is designed for streaming, so a sequence of files is transformed into a sequence of parsed blocks. Each parsed block can be represented as a JSON object.
These are all the block types:
- Blank
- Comment
- BASE
- PREFIX
- LABEL
- TYPE
- GRAPH
- Subject
- Literal (a statement in which the object is an RDF literal)
- Link (a statement in which the object is an RDF node)
- Expression (a statement in which the object is an OWL expression)
If a HOWL stream starts with blank lines, these will be parsed as blank blocks. We keep track of this whitespace so that we can process a file and render it back with the exact formatting the user provided. Note that blank lines that don't being a stream are merged into the previous block.
This blank block:
is parsed into this JSON object:
{"file-name": "example.howl",
"line-number": 1,
"block": " \n",
"block-type": "BLANK_BLOCK",
"parse": ["BLANK_BLOCK"
["EOL" " \n"]],
"eol": " \n"}
Comment blocks do not specify any information for HOWL, but the parser does keep track of them. A comment line must start with '#' -- the '#' has no special meaning unless it is the first character on a line.
This comment block:
# Just a comment.
is parsed into this JSON object:
{"file-name": "example.howl",
"line-number": 1,
"block": "# Just a comment.\n",
"block-type": "COMMENT_BLOCK",
"parse": ["COMMENT_BLOCK"
"# ",
"Just a comment."
["EOL" "\n"]],
"hash": "# ",
"comment": "Just a comment.",
"eol": "\n"}
Base blocks set the current base IRI for resolving relative IRIs. Multiple base blocks can occur, each changing the current base from that point until the next base block.
This prefix block:
BASE http://example.com/
is parsed into this JSON object:
{"file-name": "example.howl",
"line-number": 1,
"block": "BASE http://example.com/\n",
"block-type": "BASE_BLOCK",
"parse": ["BASE_BLOCK"
"BASE"
["SPACES" " "]
["BASE" ["ABSOLUTE_IRI" "http://example.com/"]]
["EOL" "\n"]],
"base": ["ABSOLUTE_IRI" "http://example.com/"],
"eol": "\n"}
Prefix blocks are identical to SPARQL prefix lines.
This prefix block:
PREFIX rdf:> http://www.w3.org/1999/02/22-rdf-syntax-ns#
is parsed into this JSON object:
{"file-name": "example.howl",
"line-number": 1,
"block": "PREFIX rdf:> http://www.w3.org/1999/02/22-rdf-syntax-ns#\n",
"block-type": "PREFIX_BLOCK",
"parse": ["PREFIX_BLOCK"
"PREFIX"
["SPACES" " "]
["PREFIX" "rdf"]
["COLON_ARROW" "" ":>" " "]
["PREFIXED"
["ABSOLUTE_IRI" "http://www.w3.org/1999/02/22-rdf-syntax-ns#"]]
["EOL" "\n"]],
"prefix": "rdf",
"prefixed": ["ABSOLUTE_IRI" "http://www.w3.org/1999/02/22-rdf-syntax-ns#"],
"eol": "\n"}
HOWL makes RDF more readable by using labels rather than IRIs and prefixed names whenever possible. Label blocks allow you to associate a label to an identifier, without making any other assertions about it -- no triple will be generated. If you want to assert that a subject has a label, use the special label:
predicate shown below.
This label block:
LABEL rdfs:comment: comment
is parsed into this JSON object:
{"file-name": "example.howl",
"line-number": 1,
"block": "LABEL rdfs:comment: comment\n",
"block-type": "LABEL_BLOCK",
"parse": ["LABEL_BLOCK"
"LABEL"
["SPACES" " "]
["IDENTIFIER" ["PREFIXED_NAME" "rdfs" ":" "comment"]]
["COLON" "" ":" " "]
["LABEL" "comment"]
["EOL" "\n"]],
"identifier": ["PREFIXED_NAME" "rdfs" ":" "comment"],
"label": "comment",
"eol": "\n"}
Like JSON-LD, HOWL allows you to associate a default datatype (or language tag) with a predicate. Unless they specify a datatype (or language tag), any literal object for that predicate will use that datatype (or language tag). No triple is generated for a type block.
This type block:
TYPE comment:> xsd:string
is parsed into this JSON object:
{"file-name": "example.howl",
"line-number": 1,
"block": "TYPE comment:> xsd:string\n",
"block-type": "TYPE_BLOCK",
"parse": ["TYPE_BLOCK"
"TYPE"
["SPACES" " "]
["PREDICATE" ["LABEL" "comment"]]
["COLON_ARROW" "" ":>" " "]
["DATATYPE" ["PREFIXED_NAME" "xsd" ":" "string"]]
["EOL" "\n"]],
"predicate": ["LABEL" "comment"],
"datatype": ["PREFIXED_NAME" "xsd" ":" "string"],
"eol": "\n"}
A HOWL file specifies an RDF dataset, with a default RDF graph and zero or more named RDF graphs. For each block there is a current graph, starting with the default graph, and changed whenever a graph block occurs. Every subject and statement block is assigned to the current graph.
Graph blocks have two forms:
GRAPH IDENTIFIER
specifies a named graph; the IDENTIFIER will also be the subject, so it can be followed by statements about the named graphGRAPH
specifies the default graph; the default graph cannot be a subject
This graph block:
GRAPH ex:graph
is parsed into this JSON object:
{"file-name": "example.howl",
"line-number": 1,
"block": "GRAPH ex:graph\n",
"block-type": "GRAPH_BLOCK",
"parse": ["GRAPH_BLOCK"
"GRAPH"
["SPACES" " "]
["GRAPH" ["PREFIXED_NAME" "ex" ":" "graph"]]
["EOL" "\n"]],
"graph": ["PREFIXED_NAME" "ex" ":" "graph"],
"eol": "\n"}
This graph block:
GRAPH
is parsed into this JSON object:
{"file-name": "example.howl",
"line-number": 1,
"block": "GRAPH\n",
"block-type": "GRAPH_BLOCK",
"parse": ["GRAPH_BLOCK"
"GRAPH"
["EOL" "\n"]],
"eol": "\n"}
A subject block is just the identifier or label for a subject. It specifies the current
This subject block:
ex:subject
is parsed into this JSON object:
{"file-name": "example.howl",
"line-number": 1,
"block": "ex:subject\n",
"block-type": "SUBJECT_BLOCK",
"parse": ["SUBJECT_BLOCK"
["SUBJECT" ["PREFIXED_NAME" "ex" ":" "subject"]]
["EOL" "\n"]],
"subject": ["PREFIXED_NAME" "ex" ":" "subject"],
"eol": "\n"}
The key difference between the HOWL syntax for literals and the Turtle or NTriples syntax is that HOWL does not require quotation marks. A literal block consists of a predicate, a :
(colon and one or more spaces), followed by the literal content, and optionally ending with a language tag or datatype.
This literal block:
comment: This comment has a datatype.^^xsd:string
is parsed into this JSON object:
{"file-name": "example.howl",
"line-number": 1,
"block": "comment: This comment has a datatype.^^xsd:string\n",
"block-type": "LITERAL_BLOCK",
"parse": ["LITERAL_BLOCK"
["ARROWS" "" ""]
["PREDICATE" ["LABEL" "comment"]]
["COLON" "" ":" " "]
["LITERAL"
"This comment has a datatype."
"^^"
["DATATYPE" ["PREFIXED_NAME" "xsd" ":" "string"]]]
["EOL" "\n"]],
"arrows": "",
"predicate": ["LABEL" "comment"],
"content": "This comment has a datatype.",
"datatype": ["PREFIXED_NAME" "xsd" ":" "string"],
"eol": "\n"}
So these HOWL blocks:
PREFIX rdfs:> http://www.w3.org/2000/01/rdf-schema#
PREFIX xsd:> http://www.w4.org/2001/XMLSchema#
PREFIX ex:> http://example.com
LABEL rdfs:comment: comment
GRAPH ex:graph
ex:subject
comment: This comment has a datatype.^^xsd:string
specify this NQuad (with newlines added for readability):
<http://example.com/graph>
<http://example.com/subject>
<http://www.w3.org/1999/02/22-rdf-syntax-ns#comment>
"This comment has a datatype."^^<http://www.w4.org/2001/XMLSchema#string> .
To express a triple where the object is an IRI, we use a link block. The subject for the link block will be whatever the current subject is, as specified in a previous subject block or graph block. The link block consists of a predicate, a :>
(colon, arrow, and one or more spaces) separator, and an object. The predicate can be a prefixed name, IRI, or label. The object can be any of these, or a blank node.
This link block:
rdf:type:> owl:Class
is parsed into this JSON object:
{"file-name": "example.howl",
"line-number": 1,
"block": "rdf:type:> owl:Class\n",
"block-type": "LINK_BLOCK",
"parse": ["LINK_BLOCK"
["ARROWS" "" ""]
["PREDICATE" ["PREFIXED_NAME" "rdf" ":" "type"]]
["COLON_ARROW" "" ":>" " "]
["OBJECT" ["PREFIXED_NAME" "owl" ":" "Class"]]
["EOL" "\n"]],
"arrows": "",
"predicate": ["PREFIXED_NAME" "rdf" ":" "type"],
"object": ["PREFIXED_NAME" "owl" ":" "Class"],
"eol": "\n"}
So these HOWL blocks:
PREFIX rdf:> http://www.w3.org/1999/02/22-rdf-syntax-ns#
PREFIX owl:> http://www.w3.org/2002/07/owl#
PREFIX ex:> http://example.com
GRAPH ex:graph
ex:subject
rdf:type:> owl:Class
specify this NQuad (with newlines added for readability):
<http://example.com/graph>
<http://example.com/subject>
<http://www.w3.org/1999/02/22-rdf-syntax-ns#type>
<http://www.w3.org/2002/07/owl#Class> .
HOWL files can also contain OWL class expressions in the version of Manchester syntax familiar from the Protégé editor. The subject for the expression block will be whatever the current subject is, as specified in a previous subject block or graph block. The expression block consists of a predicate, a :>>
(colon, two arrows, and one or more spaces) separator, and an expression string. The predicate can be a prefixed name, IRI, or label.
This expression block:
rdfs:subClassOf:>> 'has part' some foo
is parsed into this JSON object:
{"file-name": "example.howl",
"line-number": 1,
"block": "rdfs:subClassOf:>> 'has part' some foo\n",
"block-type": "EXPRESSION_BLOCK",
"parse": ["EXPRESSION_BLOCK"
["PREDICATE" ["PREFIXED_NAME" "rdfs" ":" "subClassOf"]]
["COLON_ARROWS" "" ":>>" " "]
["MN_CLASS_EXPRESSION"
["MN_SOME"
["MN_OBJECT_PROPERTY_EXPRESSION"
["MN_NAME" ["MN_QUOTED_LABEL" "'" "has part" "'"]]]
["MN_SPACE" " "]
"some"
["MN_SPACE" " "]
["MN_CLASS_EXPRESSION"
["MN_NAME" ["MN_LABEL" "foo"]]]]]
["EOL" "\n"]],
"predicate": ["PREFIXED_NAME" "rdfs" ":" "subClassOf"],
"expression": ["MN_CLASS_EXPRESSION"
["MN_SOME"
["MN_OBJECT_PROPERTY_EXPRESSION"
["MN_NAME" ["MN_QUOTED_LABEL" "'" "has part" "'"]]]
["MN_SPACE" " "]
"some"
["MN_SPACE" " "]
["MN_CLASS_EXPRESSION"
["MN_NAME" ["MN_LABEL" "foo"]]]]],
"eol": "\n"}
So these HOWL blocks:
PREFIX rdf:> http://www.w3.org/1999/02/22-rdf-syntax-ns#
PREFIX owl:> http://www.w3.org/2002/07/owl#
PREFIX ex:> http://example.com
GRAPH ex:graph
ex:subject
owl:subClassOf:>> 'has part' some foo
specify these NTriples (with newlines added for readability):
_:b1
<http://www.w3.org/1999/02/22-rdf-syntax-ns#type>
<http://www.w3.org/2002/07/owl#Restriction> .
_:b1
<http://www.w3.org/2002/07/owl#onProperty>
<http://purl.obolibrary.org/obo/BFO_0000051> .
_:b1
<http://www.w3.org/2002/07/owl#someValuesFrom>
<http://example.com/foo> .
<http://example.com/subject>
<http://www.w3.org/2000/01/rdf-schema#subClassOf>
_:b1 .
HOWL includes a convenient syntax for OWL annotations: one or more >
"arrows" preceding a link block or literal block changes the subject to a previous statement.
This literal block:
> comment: A comment on a comment.
is parsed into this JSON object:
{"file-name": "example.howl",
"line-number": 1,
"block": "> comment: A comment on a comment.\n"
"block-type": "LITERAL_BLOCK",
"parse": ["LITERAL_BLOCK"
["ARROWS" ">" " "]
["PREDICATE" ["LABEL" "comment"]]
["COLON" "" ":" " "]
["LITERAL"
"A comment on a comment."]
["EOL" "\n"]],
"arrows": ">",
"predicate": ["LABEL" "comment"],
"content": "A comment on a comment.",
"eol": "\n"}
So these HOWL blocks:
PREFIX rdf:> http://www.w3.org/1999/02/22-rdf-syntax-ns#
PREFIX owl:> http://www.w3.org/2002/07/owl#
PREFIX ex:> http://example.com
LABEL rdfs:comment: comment
GRAPH ex:graph
ex:subject
comment: This comment has a datatype.^^xsd:string
> comment: A comment on a comment.
specify these six NTriples (with newlines added for readability):
- the target statement
- the type of annotation:
owl:Axiom
- the subject of the target:
owl:annotatedSource
- the predicate of the target:
owl:annotatedProperty
- the object of the target:
owl:annotatedTarget
- the annotation statement
<http://example.com/subject>
<http://www.w3.org/1999/02/22-rdf-syntax-ns#comment>
"This comment has a datatype."^^<http://www.w4.org/2001/XMLSchema#string> .
_:b1
<http://www.w3.org/1999/02/22-rdf-syntax-ns#type>
<http://www.w3.org/2002/07/owl#Axiom> .
_:b1
<http://www.w3.org/2002/07/owl#annotatedSource>
<http://example.com/subject> .
_:b1
<http://www.w3.org/2002/07/owl#annotatedProperty>
<http://www.w3.org/1999/02/22-rdf-syntax-ns#comment> .
_:b1
<http://www.w3.org/2002/07/owl#annotatedTarget>
"This comment has a datatype."^^<http://www.w4.org/2001/XMLSchema#string> .
_:b1
<http://www.w3.org/1999/02/22-rdf-syntax-ns#comment>
"A comment on a comment." .
Nesting is allowed. The number of arrows specifies the depth of the nesting:
comment: A -- original comment
> comment: B -- comment on A
>> comment: C -- comment on B
> comment: D -- another comment on A
The howl
tool is written in Clojure. Leiningen 2.5.2+ is required to build it.
lein uberjar
builds a standalone JAR file intarget/
lein cljsbuild once
builds a JavaScript file intarget/
lein test
runs the unit and integration testslein run
can be used to compile and run the command-line interface during development
The Makefile also contains some convenient build tasks.
- 0.2.1-SNAPSHOT
- add
--context
command-line option - changed default output format to N-Quads
- rework TYPE and literal representation to match EDN-LD
- add
- 0.2.0 improve grammar
- allow comments
- PREFIX now uses
:>
, for consistency - TYPE now uses
:>
, for consistency - absolute IRIs don't have to be wrapped in angle brackets
- allow initial blank lines
- 0.1.1
- add cross-platform support: Clojure and ClojureScript
- add cross-platform API in
api.cljc
- add
--version
command-line option - fix named graph support
- fix relative IRI resolution
- fix: TYPE can be language tag
- refactor render-quads
- more tests
- 0.1.0 initial release
- draft HOWL syntax
- basic OWL class expressions from Protégé:
not
,and
,or
,some
,only
- converting HOWL to N-Triples, N-Quads, or JSON
Copyright © 2016, James A. Overton
Distributed under the Simplified BSD License: http://opensource.org/licenses/BSD-2-Clause