Examples

The following examples are designed to get you started using Cowl. They are ordered by complexity, so it is recommended that you read them sequentially.

Reading ontologies

Related documentation: ontology reading

 1/*
 2 * This introductory example shows how to read an ontology
 3 * and log its axioms and annotations.
 4 *
 5 * @note Memory allocation failures are not handled for the sake of simplicity.
 6 *
 7 * @author Ivano Bilenchi
 8 *
 9 * @copyright Copyright (c) 2019 SisInf Lab, Polytechnic University of Bari
10 * @copyright <http://swot.sisinflab.poliba.it>
11 * @copyright SPDX-License-Identifier: EPL-2.0
12 */
13#include "cowl.h"
14
15#define ONTO "example_pizza.owl"
16
17int main(void) {
18    // You must always initialize the library before use.
19    cowl_init();
20
21    // Instantiate a manager and deserialize an ontology from file.
22    CowlManager *manager = cowl_manager();
23    CowlOntology *onto = cowl_manager_read_path(manager, ustring_literal(ONTO));
24
25    if (!onto) {
26        // The ontology could not be read.
27        fprintf(stderr, "Failed to load ontology " ONTO "\n");
28        return EXIT_FAILURE;
29    }
30
31    // Do stuff with the ontology. In this case we are just logging it
32    // to the standard output using the default writer.
33    cowl_manager_write_file(manager, onto, stdout);
34
35    // Release the manager and the ontology.
36    cowl_release(manager);
37    cowl_release(onto);
38
39    return EXIT_SUCCESS;
40}

Handling of errors and imports

Related documentation: error handling, import handling

 1/*
 2 * This example is the same as the previous one, except all errors are handled
 3 * and logged, and ontology imports are resolved.
 4 *
 5 * @author Ivano Bilenchi
 6 *
 7 * @copyright Copyright (c) 2019 SisInf Lab, Polytechnic University of Bari
 8 * @copyright <http://swot.sisinflab.poliba.it>
 9 * @copyright SPDX-License-Identifier: EPL-2.0
10 */
11#include "cowl.h"
12
13#define ONTO "example_pizza.owl"
14#define IMPORT "import.owl"
15#define LOG "errors.log"
16
17/*
18 * You should return the appropriate ontology given the specified IRI.
19 * This may involve making network requests or simply retrieving
20 * the imported ontology from the local filesystem. In this example
21 * we just return a generic local "import.owl" ontology, disregarding its IRI.
22 */
23static CowlOntology *load_import(cowl_unused void *ctx, cowl_unused CowlIRI *iri) {
24    CowlOntology *import = NULL;
25    CowlManager *manager = cowl_manager();
26
27    if (manager) {
28        import = cowl_manager_read_path(manager, ustring_literal(IMPORT));
29        cowl_release(manager);
30    }
31
32    return import;
33}
34
35/*
36 * In general, it is very reasonable to just check that the ontology returned
37 * by the manager is not NULL. The error handler mechanism is only needed if you wish
38 * to implement more fine-grained error handling. In this example, errors are logged.
39 */
40static void handle_error(void *ctx, CowlError const *error) {
41    cowl_write_error(ctx, error);
42    cowl_write_static(ctx, "\n");
43}
44
45int main(void) {
46    // API initialization can fail due to low memory.
47    if (cowl_init()) {
48        return EXIT_FAILURE;
49    }
50
51    // Setup a global error handler and import loader.
52    CowlImportLoader loader = { NULL, load_import };
53    cowl_set_import_loader(loader);
54
55    UOStream stream;
56    if (uostream_to_path(&stream, LOG)) {
57        fprintf(stderr, "Failed to open " LOG "\n");
58        return EXIT_FAILURE;
59    }
60
61    CowlErrorHandler handler = { &stream, handle_error };
62    cowl_set_error_handler(handler);
63
64    // Read the ontology from file.
65    CowlManager *manager = cowl_manager();
66
67    if (!manager) {
68        return EXIT_FAILURE;
69    }
70
71    CowlOntology *onto = cowl_manager_read_path(manager, ustring_literal(ONTO));
72
73    if (!onto) {
74        fprintf(stderr, "Failed to load ontology " ONTO "\n");
75        return EXIT_FAILURE;
76    }
77
78    // Do stuff with the ontology.
79    cowl_manager_write_file(manager, onto, stdout);
80
81    cowl_release_all(manager, onto);
82    uostream_deinit(&stream);
83
84    return EXIT_SUCCESS;
85}

Querying ontologies

Related documentation: ontology querying

Basic queries

 1/*
 2 * In this example we will be logging the direct atomic subclasses of a class.
 3 *
 4 * @note Memory allocation failures are not handled for the sake of simplicity.
 5 *
 6 * @author Ivano Bilenchi
 7 *
 8 * @copyright Copyright (c) 2019 SisInf Lab, Polytechnic University of Bari
 9 * @copyright <http://swot.sisinflab.poliba.it>
10 * @copyright SPDX-License-Identifier: EPL-2.0
11 */
12#include "cowl.h"
13
14#define ONTO "example_pizza.owl"
15#define NS "http://www.co-ode.org/ontologies/pizza/pizza.owl#"
16#define CLASS_NAME "Food"
17
18// Iterator body, invoked for each class expression matching the query.
19static bool for_each_cls(void *std_out, CowlAny *cls) {
20    // We are only interested in atomic classes. Note that due to pseudo-inheritance
21    // this check ensures that the concrete type of 'exp' is CowlClass.
22    if (cowl_cls_exp_get_type(cls) != COWL_CET_CLASS) return true;
23
24    // Log the IRI remainder.
25    cowl_write_string(std_out, cowl_iri_get_rem(cowl_class_get_iri(cls)));
26    cowl_write_static(std_out, "\n");
27
28    return true;
29}
30
31int main(void) {
32    cowl_init();
33
34    CowlManager *manager = cowl_manager();
35    CowlOntology *onto = cowl_manager_read_path(manager, ustring_literal(ONTO));
36    cowl_release(manager);
37
38    if (!onto) {
39        fprintf(stderr, "Failed to load ontology " ONTO "\n");
40        return EXIT_FAILURE;
41    }
42
43    // Query the ontology.
44    UOStream *std_out = uostream_std();
45    cowl_write_static(std_out, "Atomic subclasses of " CLASS_NAME ":\n");
46
47    // Get the class whose atomic subclasses we are interested in.
48    CowlClass *cls = cowl_class_from_static(NS CLASS_NAME);
49
50    // Run the query.
51    CowlIterator iter = { std_out, for_each_cls };
52    cowl_ontology_iterate_sub_classes(onto, cls, &iter, false);
53
54    // Cleanup.
55    cowl_release_all(cls, onto);
56
57    return EXIT_SUCCESS;
58}

Recursive queries

 1/*
 2 * In this example we will be logging the atomic subclasses of a class recursively.
 3 *
 4 * @note Memory allocation failures are not handled for the sake of simplicity.
 5 *
 6 * @author Ivano Bilenchi
 7 *
 8 * @copyright Copyright (c) 2019 SisInf Lab, Polytechnic University of Bari
 9 * @copyright <http://swot.sisinflab.poliba.it>
10 * @copyright SPDX-License-Identifier: EPL-2.0
11 */
12#include "cowl.h"
13
14#define ONTO "example_pizza.owl"
15#define NS "http://www.co-ode.org/ontologies/pizza/pizza.owl#"
16#define CLASS_NAME "Food"
17
18// Custom context struct for the query.
19typedef struct CustomContext {
20    CowlOntology *onto;
21    UOStream *stream;
22} CustomContext;
23
24// Iterator body, invoked for each class expression matching the query.
25static bool for_each_cls(void *ptr, CowlAny *cls) {
26    if (cowl_cls_exp_get_type(cls) != COWL_CET_CLASS) return true;
27
28    // Log the IRI remainder.
29    CustomContext *ctx = ptr;
30    cowl_write_string(ctx->stream, cowl_iri_get_rem(cowl_class_get_iri(cls)));
31    cowl_write_static(ctx->stream, "\n");
32
33    // Recurse.
34    CowlIterator iter = { ctx, for_each_cls };
35    return cowl_ontology_iterate_sub_classes(ctx->onto, cls, &iter, false);
36}
37
38int main(void) {
39    cowl_init();
40
41    CowlManager *manager = cowl_manager();
42    CowlOntology *onto = cowl_manager_read_path(manager, ustring_literal(ONTO));
43    cowl_release(manager);
44
45    if (!onto) {
46        fprintf(stderr, "Failed to load ontology " ONTO "\n");
47        return EXIT_FAILURE;
48    }
49
50    UOStream *std_out = uostream_std();
51    cowl_write_static(std_out, "Recursive atomic subclasses of " CLASS_NAME ":\n");
52    CowlClass *cls = cowl_class_from_static(NS CLASS_NAME);
53
54    // Since we are going to perform a recursive query,
55    // we need the ontology to be part of the context.
56    CustomContext ctx = { onto, std_out };
57    CowlIterator iter = { &ctx, for_each_cls };
58    cowl_ontology_iterate_sub_classes(onto, cls, &iter, false);
59
60    cowl_release_all(cls, onto);
61    return EXIT_SUCCESS;
62}

Editing and writing ontologies

Related documentation: ontology editing, ontology writing

 1/*
 2 * This example demonstrates ontology editing and serialization to file.
 3 *
 4 * @note Memory allocation failures are not handled for the sake of simplicity.
 5 *
 6 * @author Ivano Bilenchi
 7 *
 8 * @copyright Copyright (c) 2022 SisInf Lab, Polytechnic University of Bari
 9 * @copyright <http://swot.sisinflab.poliba.it>
10 * @copyright SPDX-License-Identifier: EPL-2.0
11 */
12#include "cowl.h"
13
14#define IN_PATH "example_pizza.owl"
15#define OUT_PATH "example_pizza_new.owl"
16#define NS "http://www.co-ode.org/ontologies/pizza/pizza.owl#"
17
18int main(void) {
19    cowl_init();
20
21    // We will be editing the pizza ontology by adding the Porcini pizza.
22    printf("Reading ontology " IN_PATH "... ");
23    CowlManager *manager = cowl_manager();
24    CowlOntology *onto = cowl_manager_read_path(manager, ustring_literal(IN_PATH));
25
26    if (onto) {
27        puts("done!");
28    } else {
29        puts("failed");
30        return EXIT_FAILURE;
31    }
32
33    // Declaration(Class(pizza:PorciniTopping))
34    CowlClass *porcini_topping = cowl_class_from_static(NS "PorciniTopping");
35    CowlAnyAxiom *axiom = cowl_decl_axiom(porcini_topping, NULL);
36    cowl_ontology_add_axiom(onto, axiom);
37    cowl_release(axiom);
38
39    // Declaration(Class(pizza:Porcini))
40    CowlClass *porcini = cowl_class_from_static(NS "Porcini");
41    axiom = cowl_decl_axiom(porcini, NULL);
42    cowl_ontology_add_axiom(onto, axiom);
43    cowl_release(axiom);
44
45    // SubClassOf(pizza:PorciniTopping pizza:MushroomTopping)
46    CowlClass *mushroom_topping = cowl_class_from_static(NS "MushroomTopping");
47    axiom = cowl_sub_cls_axiom(porcini_topping, mushroom_topping, NULL);
48    cowl_ontology_add_axiom(onto, axiom);
49    cowl_release_all(axiom, mushroom_topping);
50
51    // SubClassOf(pizza:Porcini pizza:NamedPizza)
52    CowlClass *named_pizza = cowl_class_from_static(NS "NamedPizza");
53    axiom = cowl_sub_cls_axiom(porcini, named_pizza, NULL);
54    cowl_ontology_add_axiom(onto, axiom);
55    cowl_release_all(axiom, named_pizza);
56
57    // SubClassOf(pizza:Porcini
58    // ObjectSomeValuesFrom(pizza:hasTopping pizza:MozzarellaTopping))
59    CowlObjProp *has_topping = cowl_obj_prop_from_static(NS "hasTopping");
60    CowlClass *mozzarella_topping = cowl_class_from_static(NS "MozzarellaTopping");
61    CowlObjQuant *obj_quant = cowl_obj_quant(COWL_QT_SOME, has_topping,
62                                             mozzarella_topping);
63    axiom = cowl_sub_cls_axiom(porcini, obj_quant, NULL);
64    cowl_ontology_add_axiom(onto, axiom);
65    cowl_release_all(axiom, obj_quant, mozzarella_topping);
66
67    // SubClassOf(pizza:Porcini
68    // ObjectSomeValuesFrom(pizza:hasTopping pizza:PorciniTopping))
69    obj_quant = cowl_obj_quant(COWL_QT_SOME, has_topping, porcini_topping);
70    axiom = cowl_sub_cls_axiom(porcini, obj_quant, NULL);
71    cowl_ontology_add_axiom(onto, axiom);
72    cowl_release_all(axiom, obj_quant);
73
74    // SubClassOf(pizza:Porcini ObjectAllValuesFrom(pizza:hasTopping
75    // ObjectUnionOf(pizza:MozzarellaTopping pizza:PorciniTopping)))
76    UVec(CowlObjectPtr) vec = uvec(CowlObjectPtr);
77    uvec_push(CowlObjectPtr, &vec, mozzarella_topping);
78    uvec_push(CowlObjectPtr, &vec, porcini_topping);
79    CowlVector *operands = cowl_vector(&vec);
80    CowlNAryBool *closure = cowl_nary_bool(COWL_NT_UNION, operands);
81    obj_quant = cowl_obj_quant(COWL_QT_ALL, has_topping, closure);
82    axiom = cowl_sub_cls_axiom(porcini, obj_quant, NULL);
83    cowl_ontology_add_axiom(onto, axiom);
84    cowl_release_all(axiom, obj_quant, closure, operands, porcini_topping, porcini,
85                     has_topping);
86
87    // Serialize the edited ontology to a new file.
88    printf("Writing ontology " OUT_PATH "... ");
89
90    if (cowl_manager_write_path(manager, onto, ustring_literal(OUT_PATH))) {
91        puts("failed");
92    } else {
93        puts("done!");
94    }
95
96    cowl_release_all(onto, manager);
97    return EXIT_SUCCESS;
98}

Ontology streams

Related documentation: input streams, output streams

Input streams

 1/*
 2 * In this example we will be logging the direct atomic subclasses
 3 * of a certain class, but we will do so without instantiating a
 4 * CowlOntology object.
 5 *
 6 * @note Memory allocation failures are not handled for the sake of simplicity.
 7 *
 8 * @author Ivano Bilenchi
 9 *
10 * @copyright Copyright (c) 2023 SisInf Lab, Polytechnic University of Bari
11 * @copyright <http://swot.sisinflab.poliba.it>
12 * @copyright SPDX-License-Identifier: EPL-2.0
13 */
14#include "cowl.h"
15
16#define ONTO "example_pizza.owl"
17#define NS "http://www.co-ode.org/ontologies/pizza/pizza.owl#"
18#define CLASS_NAME "Food"
19
20// Axiom handler, invoked for each axiom in the ontology document.
21static cowl_ret handle_axiom(void *target_class, CowlAnyAxiom *axiom) {
22    // We are only interested in subclass axioms.
23    if (cowl_axiom_get_type(axiom) != COWL_AT_SUB_CLASS) return COWL_OK;
24
25    // We are only interested in axioms where the superclass is the target class.
26    CowlAnyClsExp *cls = cowl_sub_cls_axiom_get_super(axiom);
27    if (!cowl_equals(target_class, cls)) return COWL_OK;
28
29    // We are only interested in axioms where the subclass is atomic.
30    cls = cowl_sub_cls_axiom_get_sub(axiom);
31    if (cowl_cls_exp_get_type(cls) != COWL_CET_CLASS) return COWL_OK;
32
33    // Log the IRI remainder.
34    puts(cowl_string_get_cstring(cowl_iri_get_rem(cowl_class_get_iri(cls))));
35    return COWL_OK;
36}
37
38int main(void) {
39    cowl_init();
40
41    CowlManager *manager = cowl_manager();
42    CowlClass *target_class = cowl_class_from_static(NS CLASS_NAME);
43
44    // Configure the ontology input stream.
45    CowlIStreamHandlers handlers = { .ctx = target_class, .axiom = handle_axiom };
46    CowlIStream *stream = cowl_manager_get_istream(manager, handlers);
47
48    // Process the ontology as a stream.
49    puts("Atomic subclasses of " CLASS_NAME ":");
50    if (cowl_istream_process_path(stream, ustring_literal(ONTO))) {
51        return EXIT_FAILURE;
52    }
53
54    cowl_release_all(manager, target_class, stream);
55    return EXIT_SUCCESS;
56}

Output streams

  1/*
  2 * In this example we will be creating a new ontology document by using an
  3 * ontology output stream.
  4 *
  5 * @note Memory allocation failures are not handled for the sake of simplicity.
  6 *
  7 * @author Ivano Bilenchi
  8 *
  9 * @copyright Copyright (c) 2023 SisInf Lab, Polytechnic University of Bari
 10 * @copyright <http://swot.sisinflab.poliba.it>
 11 * @copyright SPDX-License-Identifier: EPL-2.0
 12 *
 13 * @file
 14 */
 15
 16#include "cowl.h"
 17
 18#define PATH "porcini_pizza.owl"
 19
 20#define IMPORT_IRI "http://www.co-ode.org/ontologies/pizza"
 21#define IMPORT_NS IMPORT_IRI "/pizza.owl#"
 22
 23#define IRI "http://foo.com/ontologies/porcini_pizza"
 24#define NS IRI "/porcini_pizza.owl#"
 25
 26int main(void) {
 27    cowl_init();
 28
 29    printf("Generating ontology " PATH "... ");
 30
 31    UOStream ostream;
 32    if (uostream_to_path(&ostream, PATH)) {
 33        // Initializing and writing to the stream may fail.
 34        // You should handle IO errors as fit for your application.
 35        goto err_io;
 36    }
 37
 38    CowlManager *manager = cowl_manager();
 39    CowlOStream *stream = cowl_manager_get_ostream(manager, &ostream);
 40    cowl_release(manager);
 41
 42    // Optional: setup prefixes so that IRIs can be rendered in their prefixed form.
 43    CowlSymTable *st = cowl_ostream_get_sym_table(stream);
 44    cowl_sym_table_register_prefix_raw(st, ustring_literal(""), ustring_literal(NS),
 45                                       false);
 46    cowl_sym_table_register_prefix_raw(st, ustring_literal("pizza"),
 47                                       ustring_literal(IMPORT_NS), false);
 48
 49    // Write the ontology header.
 50    CowlIRI *iri = cowl_iri_from_static(IRI);
 51    CowlIRI *import_iri = cowl_iri_from_static(IMPORT_IRI);
 52    UVec(CowlObjectPtr) imports = uvec(CowlObjectPtr);
 53    uvec_push(CowlObjectPtr, &imports, import_iri);
 54
 55    CowlOntologyHeader header = {
 56        .id = { iri },
 57        .imports = &imports,
 58    };
 59
 60    if (cowl_ostream_write_header(stream, header)) goto err_io;
 61
 62    cowl_release_all(iri, import_iri);
 63    uvec_deinit(CowlObjectPtr, &imports);
 64
 65    // Write the axioms.
 66    // Declaration(Class(:PorciniTopping))
 67    CowlClass *porcini = cowl_class_from_static(NS "PorciniTopping");
 68    CowlAnyAxiom *axiom = cowl_decl_axiom(porcini, NULL);
 69    if (cowl_ostream_write_axiom(stream, axiom)) goto err_io;
 70    cowl_release(axiom);
 71
 72    // Declaration(Class(:Porcini))
 73    CowlClass *porcini_pizza = cowl_class_from_static(NS "Porcini");
 74    axiom = cowl_decl_axiom(porcini_pizza, NULL);
 75    if (cowl_ostream_write_axiom(stream, axiom)) goto err_io;
 76    cowl_release(axiom);
 77
 78    // SubClassOf(:PorciniTopping pizza:MushroomTopping)
 79    CowlClass *mushroom = cowl_class_from_static(IMPORT_NS "MushroomTopping");
 80    axiom = cowl_sub_cls_axiom(porcini, mushroom, NULL);
 81    if (cowl_ostream_write_axiom(stream, axiom)) goto err_io;
 82    cowl_release_all(axiom, mushroom);
 83
 84    // SubClassOf(:Porcini pizza:NamedPizza)
 85    CowlClass *named_pizza = cowl_class_from_static(IMPORT_NS "NamedPizza");
 86    axiom = cowl_sub_cls_axiom(porcini_pizza, named_pizza, NULL);
 87    if (cowl_ostream_write_axiom(stream, axiom)) goto err_io;
 88    cowl_release_all(axiom, named_pizza);
 89
 90    // SubClassOf(:Porcini
 91    // ObjectSomeValuesFrom(pizza:hasTopping pizza:MozzarellaTopping))
 92    CowlObjProp *has_topping = cowl_obj_prop_from_static(IMPORT_NS "hasTopping");
 93    CowlClass *mozzarella = cowl_class_from_static(IMPORT_NS "MozzarellaTopping");
 94    CowlObjQuant *obj_quant = cowl_obj_quant(COWL_QT_SOME, has_topping, mozzarella);
 95    axiom = cowl_sub_cls_axiom(porcini_pizza, obj_quant, NULL);
 96    if (cowl_ostream_write_axiom(stream, axiom)) goto err_io;
 97    cowl_release_all(axiom, obj_quant, mozzarella);
 98
 99    // SubClassOf(:Porcini
100    // ObjectSomeValuesFrom(pizza:hasTopping :PorciniTopping))
101    obj_quant = cowl_obj_quant(COWL_QT_SOME, has_topping, porcini);
102    axiom = cowl_sub_cls_axiom(porcini_pizza, obj_quant, NULL);
103    if (cowl_ostream_write_axiom(stream, axiom)) goto err_io;
104    cowl_release_all(axiom, obj_quant);
105
106    // SubClassOf(:Porcini ObjectAllValuesFrom(pizza:hasTopping
107    // ObjectUnionOf(pizza:MozzarellaTopping :PorciniTopping)))
108    UVec(CowlObjectPtr) vec = uvec(CowlObjectPtr);
109    uvec_push(CowlObjectPtr, &vec, mozzarella);
110    uvec_push(CowlObjectPtr, &vec, porcini);
111    CowlVector *operands = cowl_vector(&vec);
112    CowlNAryBool *closure = cowl_nary_bool(COWL_NT_UNION, operands);
113    obj_quant = cowl_obj_quant(COWL_QT_ALL, has_topping, closure);
114    axiom = cowl_sub_cls_axiom(porcini_pizza, obj_quant, NULL);
115    if (cowl_ostream_write_axiom(stream, axiom)) goto err_io;
116    cowl_release_all(axiom, obj_quant, closure, operands, porcini, porcini_pizza,
117                     has_topping);
118
119    // Finally, write the footer.
120    if (cowl_ostream_write_footer(stream)) goto err_io;
121
122    puts("done!");
123    cowl_release(stream);
124    return EXIT_SUCCESS;
125
126err_io:
127    puts("failed");
128    return EXIT_FAILURE;
129}