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 queries
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 ":");
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 ":");
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}