|
7 | 7 |
|
8 | 8 | from owlapy import namespaces |
9 | 9 | from .iri import IRI |
10 | | -from .owl_individual import OWLNamedIndividual |
| 10 | +from .owl_individual import OWLNamedIndividual, OWLIndividual |
11 | 11 | from .owl_literal import OWLLiteral |
12 | 12 | from .owl_object import OWLObjectRenderer, OWLEntity, OWLObject |
13 | | -from .owl_property import OWLObjectInverseOf, OWLPropertyExpression |
| 13 | +from .owl_property import OWLObjectInverseOf, OWLPropertyExpression, OWLDataProperty, OWLObjectProperty |
14 | 14 | from .class_expression import OWLClassExpression, OWLBooleanClassExpression, OWLClass, OWLObjectSomeValuesFrom, \ |
15 | 15 | OWLObjectAllValuesFrom, OWLObjectUnionOf, OWLObjectIntersectionOf, OWLObjectComplementOf, OWLObjectMinCardinality, \ |
16 | 16 | OWLObjectExactCardinality, OWLObjectMaxCardinality, OWLObjectHasSelf, OWLDataSomeValuesFrom, OWLDataAllValuesFrom, \ |
|
20 | 20 | from .owl_data_ranges import OWLNaryDataRange, OWLDataComplementOf, OWLDataUnionOf, OWLDataIntersectionOf |
21 | 21 | from .class_expression import OWLObjectHasValue, OWLFacetRestriction, OWLDatatypeRestriction, OWLObjectOneOf |
22 | 22 | from .owl_datatype import OWLDatatype |
23 | | - |
24 | | - |
| 23 | +from .owl_reasoner import OWLReasoner |
| 24 | +from typing import Union, Tuple |
| 25 | +import requests |
| 26 | +import warnings |
| 27 | +import abc |
25 | 28 | _DL_SYNTAX = types.SimpleNamespace( |
26 | 29 | SUBCLASS="⊑", |
27 | 30 | EQUIVALENT_TO="≡", |
@@ -57,6 +60,104 @@ def _simple_short_form_provider(e: OWLEntity) -> str: |
57 | 60 | return sf |
58 | 61 |
|
59 | 62 |
|
| 63 | +mapper = { |
| 64 | + 'OWLNamedIndividual': "http://www.w3.org/2002/07/owl#NamedIndividual", |
| 65 | + 'OWLObjectProperty': "http://www.w3.org/2002/07/owl#ObjectProperty", |
| 66 | + 'OWLDataProperty': "http://www.w3.org/2002/07/owl#DatatypeProperty", |
| 67 | + 'OWLClass': "http://www.w3.org/2002/07/owl#Class" |
| 68 | +} |
| 69 | + |
| 70 | + |
| 71 | +def translating_short_form_provider(e: OWLEntity, reasoner, rules: dict[str:str] = None) -> str: |
| 72 | + """ |
| 73 | + e: entity. |
| 74 | + reasoner: OWLReasoner or Triplestore(from Ontolearn) |
| 75 | + rules: A mapping from OWLEntity to predicates, |
| 76 | + Keys in rules can be general or specific iris, e.g., |
| 77 | + IRI to IRI s.t. the second IRI must be a predicate leading to literal |
| 78 | + """ |
| 79 | + label_iri = "http://www.w3.org/2000/01/rdf-schema#label" |
| 80 | + |
| 81 | + def get_label(entity, r, predicate=label_iri): |
| 82 | + if isinstance(r, OWLReasoner): |
| 83 | + values = list(r.data_property_values(entity, OWLDataProperty(predicate))) |
| 84 | + if values: |
| 85 | + return str(values[0].get_literal()) |
| 86 | + else: |
| 87 | + return _simple_short_form_provider(entity) |
| 88 | + else: |
| 89 | + # else we have a TripleStore |
| 90 | + sparql = f"""select ?o where {{ <{entity.str}> <{predicate}> ?o}}""" |
| 91 | + if results := list(r.query(sparql)): |
| 92 | + return str(results[0]) |
| 93 | + else: |
| 94 | + return _simple_short_form_provider(entity) |
| 95 | + |
| 96 | + if rules is None: |
| 97 | + return get_label(e, reasoner) |
| 98 | + else: |
| 99 | + # Check if a rule exist for a specific IRI: |
| 100 | + # (e.g "http://www.example.org/SomeSpecificClass":"http://www.example.org/SomePredicate") |
| 101 | + # WARNING: If the entity is an OWLClass, the rule specified for that class will only be used to replace the |
| 102 | + # class itself not individuals belonging to that class. The reason for that is that the entity can also be a |
| 103 | + # property and properties does not classify individuals. So to avoid confusion, the specified predicate in the |
| 104 | + # rules will only be used to 'label' the specified entity. |
| 105 | + if specific_predicate := rules.get(e.str, None): |
| 106 | + return get_label(e, reasoner, specific_predicate) |
| 107 | + # Check if a rule exist for a general IRI: |
| 108 | + # (e.g "http://www.w3.org/2002/07/owl#NamedIndividual":"http://www.example.org/SomePredicate") |
| 109 | + # then it will label any entity of that type using the value retrieved from the given predicate. |
| 110 | + elif general_predicate := rules.get(mapper[e.__class__.__name__], None): |
| 111 | + return get_label(e, reasoner, general_predicate) |
| 112 | + # No specific rule set, use http://www.w3.org/2000/01/rdf-schema#label (by default) |
| 113 | + else: |
| 114 | + return get_label(e, reasoner) |
| 115 | + |
| 116 | + |
| 117 | +def translating_short_form_endpoint(e: OWLEntity, endpoint: str, |
| 118 | + rules: dict[abc.ABCMeta:str] = None) -> str: |
| 119 | + """ |
| 120 | + Translates an OWLEntity to a short form string using provided rules and an endpoint. |
| 121 | +
|
| 122 | + Parameters: |
| 123 | + e (OWLEntity): The OWL entity to be translated. |
| 124 | + endpoint (str): The endpoint of a triple store to query against. |
| 125 | + rules (dict[abc.ABCMeta:str], optional): A dictionary mapping OWL classes to string IRIs leading to a literal. |
| 126 | +
|
| 127 | + Returns: |
| 128 | + str: The translated short form of the OWL entity. If no matching rules are found, a simple short form is returned. |
| 129 | +
|
| 130 | + This function iterates over the provided rules to check if the given OWL entity is an instance of any specified class. |
| 131 | + If a match is found, it constructs a SPARQL query to retrieve the literal value associated with the entity and predicate. |
| 132 | + If a literal is found, it is returned as the short form. If no literals are found, the SPARQL query and entity information |
| 133 | + are printed for debugging purposes. If no matching rules are found, a warning is issued and a simple short form is returned. |
| 134 | +
|
| 135 | +
|
| 136 | + Example: |
| 137 | + >>> e = OWLEntity("http://example.org/entity") |
| 138 | + >>> endpoint = "http://example.org/sparql" |
| 139 | + >>> rules = {SomeOWLClass: "http://example.org/predicate"} |
| 140 | + >>> translating_short_form_endpoint(e, endpoint, rules) |
| 141 | + """ |
| 142 | + # () Iterate over rules |
| 143 | + for owlapy_class, str_predicate in rules.items(): |
| 144 | + # () Check whether an OWL entity is an instance of specified class |
| 145 | + if isinstance(e, owlapy_class): |
| 146 | + sparql = f"""select ?o where {{ <{e.str}> <{str_predicate}> ?o}}""" |
| 147 | + response = requests.post(url=endpoint, data={"query": sparql}) |
| 148 | + results = response.json()["results"]["bindings"] |
| 149 | + if len(results) > 0: |
| 150 | + return results[0]["o"]["value"] |
| 151 | + else: |
| 152 | + print(sparql) |
| 153 | + print(f"No literal found\n{sparql}\n{e}") |
| 154 | + continue |
| 155 | + |
| 156 | + warnings.warn(f"No matching rules for OWL Entity:{e}!") |
| 157 | + # No mathing rule found |
| 158 | + return _simple_short_form_provider(e) |
| 159 | + |
| 160 | + |
60 | 161 | class DLSyntaxObjectRenderer(OWLObjectRenderer): |
61 | 162 | """DL Syntax renderer for OWL Objects.""" |
62 | 163 | __slots__ = '_sfp' |
@@ -226,7 +327,7 @@ def _render_operands(self, c: OWLNaryBooleanClassExpression) -> List[str]: |
226 | 327 |
|
227 | 328 | def _render_nested(self, c: OWLClassExpression) -> str: |
228 | 329 | if isinstance(c, OWLBooleanClassExpression) or isinstance(c, OWLRestriction) \ |
229 | | - or isinstance(c, OWLNaryDataRange): |
| 330 | + or isinstance(c, OWLNaryDataRange): |
230 | 331 | return "(%s)" % self.render(c) |
231 | 332 | else: |
232 | 333 | return self.render(c) |
@@ -420,7 +521,7 @@ def _render_operands(self, c: OWLNaryBooleanClassExpression) -> List[str]: |
420 | 521 |
|
421 | 522 | def _render_nested(self, c: OWLClassExpression) -> str: |
422 | 523 | if isinstance(c, OWLBooleanClassExpression) or isinstance(c, OWLRestriction) \ |
423 | | - or isinstance(c, OWLNaryDataRange): |
| 524 | + or isinstance(c, OWLNaryDataRange): |
424 | 525 | return "(%s)" % self.render(c) |
425 | 526 | else: |
426 | 527 | return self.render(c) |
|
0 commit comments