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.

Basic ontology parsing

 1/*
 2 * This introductory example shows how to read an ontology
 3 * and log its axioms and annotations.
 4 * Note that error and import handling are omitted 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
16int main(void) {
17    // You must always initialize the library before use.
18    cowl_init();
19
20    // Instantiate a manager and deserialize an ontology from file.
21    CowlManager *manager = cowl_manager();
22    CowlOntology *ontology = cowl_manager_read_path(manager, ustring_literal(ONTO));
23
24    if (ontology) {
25        // Do stuff with the ontology. In this case we are just logging it
26        // to the standard output using the default writer.
27        cowl_manager_write_file(manager, ontology, stdout);
28
29        // Release the ontology.
30        cowl_ontology_release(ontology);
31    }
32
33    // Release the manager.
34    cowl_manager_release(manager);
35
36    return EXIT_SUCCESS;
37}

Handling of errors and imports

 1/*
 2 * This example is the same as the previous one,
 3 * except error and import handling are included.
 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
17static CowlOntology *load_import(void *ctx, CowlIRI *iri);
18static void handle_error(void *ctx, CowlError const *error);
19
20int main(void) {
21
22    // API initialization can fail due to low memory.
23    if (cowl_init()) {
24        return EXIT_FAILURE;
25    }
26
27    // Setup a global error handler and import loader.
28    CowlImportLoader loader = { NULL, load_import };
29    cowl_set_import_loader(loader);
30
31    UOStream stream;
32    if (uostream_to_path(&stream, LOG)) {
33        return EXIT_FAILURE;
34    }
35
36    CowlErrorHandler handler = { &stream, handle_error };
37    cowl_set_error_handler(handler);
38
39    // Read the ontology from file.
40    CowlManager *manager = cowl_manager();
41
42    if (manager) {
43        CowlOntology *onto = cowl_manager_read_path(manager, ustring_literal(ONTO));
44
45        // Do stuff with the ontology.
46        if (onto) {
47            cowl_manager_write_file(manager, onto, stdout);
48            cowl_ontology_release(onto);
49        }
50
51        cowl_manager_release(manager);
52    }
53
54    uostream_deinit(&stream);
55
56    return EXIT_SUCCESS;
57}
58
59/*
60 * You should return the appropriate ontology given the specified IRI.
61 * This may involve making network requests or simply retrieving
62 * the imported ontology from the local filesystem. In this example
63 * we just return a generic local "import.owl" ontology, disregarding its IRI.
64 */
65static CowlOntology *load_import(cowl_unused void *ctx, cowl_unused CowlIRI *iri) {
66    CowlOntology *import = NULL;
67    CowlManager *manager = cowl_manager();
68
69    if (manager) {
70        import = cowl_manager_read_path(manager, ustring_literal(IMPORT));
71        cowl_manager_release(manager);
72    }
73
74    return import;
75}
76
77/*
78 * In general, it is very reasonable to just check that the ontology returned
79 * by the manager is not NULL. The error handler mechanism is only needed if you wish
80 * to implement more fine-grained error handling. In this example, errors are logged.
81 */
82static void handle_error(void *ctx, CowlError const *error) {
83    cowl_write_error(ctx, error);
84}

Ontology querying

 1/*
 2 * In this example we will be logging the direct atomic subclasses
 3 * of a certain class. Note that error and import handling are omitted
 4 * 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(cowl_unused void *ctx, 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    UOStream *std_out = uostream_std();
26    cowl_write_string(std_out, cowl_iri_get_rem(cowl_class_get_iri(cls)));
27    cowl_write_static(std_out, "\n");
28
29    return true;
30}
31
32int main(void) {
33    cowl_init();
34
35    CowlManager *manager = cowl_manager();
36    CowlOntology *ontology = cowl_manager_read_path(manager, ustring_literal(ONTO));
37    cowl_manager_release(manager);
38
39    // Query the ontology
40    if (ontology) {
41        // Get the class whose atomic subclasses we are interested in.
42        puts("Atomic subclasses of " CLASS_NAME ":");
43        CowlClass *cls = cowl_class_from_static(NS CLASS_NAME);
44
45        // Run the query.
46        CowlIterator iter = { NULL, for_each_cls };
47        cowl_ontology_iterate_sub_classes(ontology, cls, &iter, false);
48
49        // Cleanup.
50        cowl_class_release(cls);
51        cowl_ontology_release(ontology);
52    }
53
54    return EXIT_SUCCESS;
55}

Recursive ontology querying

 1/*
 2 * In this example we will be logging the atomic subclasses
 3 * of a certain class recursively. Error and import handling are omitted.
 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 NS "http://www.co-ode.org/ontologies/pizza/pizza.owl#"
15#define CLASS_NAME "Food"
16
17// Iterator body, invoked for each class expression matching the query.
18static bool for_each_cls(void *ctx, CowlAny *cls) {
19    if (cowl_cls_exp_get_type(cls) != COWL_CET_CLASS) return true;
20
21    // Log the IRI remainder.
22    UOStream *std_out = uostream_std();
23    cowl_write_string(std_out, cowl_iri_get_rem(cowl_class_get_iri(cls)));
24    cowl_write_static(std_out, "\n");
25
26    // Recurse.
27    CowlIterator iter = { ctx, for_each_cls };
28    return cowl_ontology_iterate_sub_classes(ctx, cls, &iter, false);
29}
30
31int main(void) {
32    cowl_init();
33
34    CowlManager *manager = cowl_manager();
35    CowlOntology *ontology = cowl_manager_read_path(manager, ustring_literal(ONTO));
36    cowl_manager_release(manager);
37
38    if (ontology) {
39        puts("Recursive atomic subclasses of " CLASS_NAME ":");
40        CowlClass *cls = cowl_class_from_static(NS CLASS_NAME);
41
42        // Since we are going to perform a recursive query,
43        // we need the ontology to be part of the context.
44        CowlIterator iter = { ontology, for_each_cls };
45        cowl_ontology_iterate_sub_classes(ontology, cls, &iter, false);
46
47        cowl_class_release(cls);
48        cowl_ontology_release(ontology);
49    }
50
51    return EXIT_SUCCESS;
52}

Ontology editing and serialization

 1/*
 2 * This example demonstrates ontology editing and serialization to file.
 3 * Error and import handling are deliberately omitted.
 4 *
 5 * @author Ivano Bilenchi
 6 *
 7 * @copyright Copyright (c) 2022 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 IN_PATH "example_pizza.owl"
14#define OUT_PATH "example_pizza_new.owl"
15#define NS "http://www.co-ode.org/ontologies/pizza/pizza.owl#"
16
17int main(void) {
18    cowl_init();
19
20    // We will be editing the pizza ontology by adding a new type of pizza.
21    printf("Reading ontology " IN_PATH "...");
22    CowlManager *manager = cowl_manager();
23    CowlOntology *ontology = cowl_manager_read_path(manager, ustring_literal(IN_PATH));
24
25    if (ontology) {
26        printf(" done!\n");
27    } else {
28        printf(" failed\n");
29        return EXIT_FAILURE;
30    }
31
32    // Note that most of the following function calls can fail due to
33    // memory exhaustion, so you should always check their return values.
34    CowlClass *my_pizza = cowl_class_from_static(NS "MyPizza");
35    CowlClass *pizza = cowl_class_from_static(NS "Pizza");
36
37    // We first declare the new class.
38    CowlAnyAxiom *axiom = cowl_decl_axiom(my_pizza, NULL);
39    cowl_ontology_add_axiom(ontology, axiom);
40    cowl_decl_axiom_release(axiom);
41
42    // Then we state that it is a subclass of 'Pizza'.
43    axiom = cowl_sub_cls_axiom(my_pizza, pizza, NULL);
44    cowl_ontology_add_axiom(ontology, axiom);
45    cowl_sub_cls_axiom_release(axiom);
46
47    // Finally we serialize the edited ontology to a new file.
48    printf("Writing ontology " OUT_PATH "...");
49
50    if (cowl_manager_write_path(manager, ontology, ustring_literal(OUT_PATH))) {
51        printf(" failed\n");
52    } else {
53        printf(" done!\n");
54    }
55
56    cowl_release(my_pizza);
57    cowl_release(pizza);
58    cowl_release(ontology);
59    cowl_release(manager);
60
61    return EXIT_SUCCESS;
62}