The KGCL Java library
The Java library is organized in four distinct packages.
- The
org.incenp.obofoundry.kgcl
package is intended to provide a reasonably high-level API to manipulate KGCL. - The
org.incenp.obofoundry.kgcl.owl
provides classes to apply KGCL-described changes to a OWL ontology, using the OWLAPI library. - The
org.incenp.obofoundry.kgcl.model
package provides the classes that make up the object model for KGCL. Those classes are directly derived from the LinkML schema that formally describes KGCL. They may be used by those who want to manipulate KGCL objects directly. When using the high-level API, the only class in this package that client code should need to directly use isChange
. - The
org.incenp.obofoundry.kgcl.parser
package contains a ANTLR-generated parser to deserialise a KGCL changeset from the KGCL language. The classes there may be used by those who want to parse KGCL and manipulate the parse tree themselves (knowledge of the ANTLR runtime is required). The high-level API abstracts those classes away completely.
See the API documentation for details. This page gives a brief overview of the most important, client code-facing classes.
Serialising / deserialising KGCL objects
Currently, the only KGCL serialisation format supported is the “KGCL-DSL” format. Support for JSON/YAML formats may be added in the future.
Deserialising KGCL-DSL
Use the KGCLReader class to deserialise a changeset from a KGCL-DSL file:
import java.util.List; import org.incenp.obofoundry.kgcl.KGCLReader; import org.incenp.obofoundry.kgcl.model.Change; try { KGCLReader reader = new KGCLReader("my-changeset.kgcl"); if ( reader.read() ) { // Parsing successful, get the actual changes List<Change> changeset = reader.getChangeSet(); } else { // Invalid KGCL instructions, get details about the errors List<KGCLSyntaxError> errors = reader.getErrors(); } } catch ( IOException ioe ) { // A non-KGCL-specific I/O error occurred }
To parse KGCL instructions from a String, you can either call the KGCLReader
constructor with a StringReader
object:
import java.io.StringReader; StringReader kgcl = new StringReader("obsolete EX:0001"); KGCLReader reader = new KGCLReader(kgcl);
or you can use the argument-less constructor and pass the string containing the KGCL instructions to the read()
method – this form allows to use the same reader object to parse several strings by repeatedly calling the read()
method, before getting all the accumulated changes at the end with getChangeSet()
:
KGCLReader reader = new KGCLReader(); reader.read("create class EX:0002 'my new class'"); reader.read("obsolete EX:0001 with replacement EX:0002"); if ( ! reader.hasErrors() ) { List<Change> changeset = reader.getChangeSet(); }
Serialising KGCL-DSL
Use the KGCLwriter class to serialise a KGCL change(set) into a KGCL-DSL file:
import org.incenp.obofoundry.kgcl.KGCLWriter; List<Change> changeset = ...; // the changeset to serialise try { KGCLWriter writer = new KGCLWriter("my-changeset.kgcl"); writer.write(changeset); writer.close(); } catch ( IOException ioe ) { // A non-KGCL-specific I/O error occurred }
To get the serialised KGCL as a string, you can either write to a StringWriter
object rather than a file, or use instead the KGCLTextTranslator class (which is used internally by KGCLWriter
to get the text representation of a KGCL change object):
import org.incenp.obofoundry.kgcl.KGCLTextTranslator; Change change = ...; // the change to serialise KGCLTextTranslator translator = new KGCLTextTranslator(); String kgcl = change.accept(translator);
Identifying nodes using shortened identifiers or labels
If the KGCL instructions to parse reference nodes using shortened identifiers (a.k.a “CURIEs”, such as EX:0001
), the KGCLReader
object may be provided with a PrefixManager
from the OWLAPI to automatically resolve any shortened identifier into its corresponding full-length IRI:
import org.semanticweb.owlapi.model.PrefixManager; PrefixManager pm = ...; // Obtain a PrefixManager suitable for the // prefixes used in the changeset KGCLReader reader = new KGCLReader("my-changeset.kgcl"); reader.setPrefixManager(pm); reader.read();
Note that all the classes of the KGCL library that manipulate KGCL objects, and in particular the classes that can be used to apply a changeset to a OWL ontology, assume that the KGCL objects contain full-length identifiers only instead of shortened identifiers, so using a PrefixManager
at the parsing stage to automatically resolve all shortened identifiers is strongly recommended.
Alternatively, rather than a PrefixManager
object, the reader may be provided with a map of prefix names to prefixes, using the setPrefixMap()
method.
When serialising, the KGCLWriter
object may likewise be provided with a PrefixManager
or a prefix map so that identifiers may be written in shortened form.
The KGCL-DSL syntax also allows referencing nodes using their labels rather than their identifiers. For that to be possible, the KGCLReader
object must be provided with an implementation of the LabelResolver object so that the labels can be resolved into proper identifiers. The library provides an implementation that can resolve labels based on a OWL ontology:
import org.semanticweb.owlapi.model.OWLOntology; import org.incenp.obofoundry.kgcl.owl.OntologyBasedLabelResolver; OWLOntology ont = ...; // the ontology to apply the changes to KGCLReader reader = new KGCLReader("my-changeset.kgcl"); reader.setLabelResolver(new OntologyBasedLabelResolver(ont));
Arbitrary manipulations of KGCL change objects
The library allows using a Visitor pattern to implement any kind of arbitrary manipulations of a KGCL change or changeset.
The IChangeVisitor is the interface for all KGCL visitors. It specifies one visit()
method for each type of KGCL change:
public interface IChangeVisitor<T> { T visit(Change v); T visit(NodeRename v); T visit(NewSynonym v); T visit(NodeObsoletion v); ... }
The ChangeVisitorBase is a helper class to facilitate the implementation of a IChangeVisitor
implementation, by providing a default implementation of all methods. The recommended way to create a visitor is to derive ChangeVisitorBase
and implement only the methods you need.
The visitor pattern is used internally by several other classes of the library, such as the KGCLTextTranslator
class already mentioned above or the OntologyPatcher
class (see below).
Applying changes to an ontology
Currently, the KGCL library only supports applying KGCL-described changes to a OWL ontology. Support for other types of knowledge graphs may be added in the future.
The main class to apply changes to an ontology is the OntologyPatcher class.
Create a OntologyPatcher
object by passing its constructor the ontology the changes should be applied to, as well as a OWLReasoner
object (the reasoner is not strictly necessary and may be null
, but in that case the patcher will not be able to verify the validity of some changes; for example, when applying a NodeDeepening
change, a reasoner is needed to ensure that the target node is a descendant of the original node). Then apply the desired changes with the apply()
method.
import org.incenp.obofoundry.kgcl.owl.OntologyPatcher; import org.incenp.obofoundry.kgcl.RejectedChange; OWLOntology ont = ...; // the ontology to modify OWLReasoner reasoner = ...; List<Change> changeset = ...; // the changes to apply OntologyPatcher patcher = new OntologyPatcher(ont, reasoner); if ( patcher.apply(changeset) ) { // All changes successfully applied } else { // Some changes could not be applied List<RejectedChange> rejected = patcher.getRejectedChanges(); }
Some changes may be “rejected” if the contents of the ontology do not match what the changes are expecting. For example, a change that tries to add a synonym to a class will be rejected if the class cannot be found in the ontology.
By default, if some changes in a changeset cannot be applied, the other changes will still be applied normally. To apply a changeset in a “all or nothing” manner, where no changes should be applied at all if even only one change cannot be applied, call the apply(changeset, false)
method.