1919)
2020
2121import pandas as pd
22+ import rdflib
2223import yaml
2324from curies import Converter
2425from deprecation import deprecated
3132
3233from sssom .validators import check_all_prefixes_in_curie_map
3334
34- from .constants import CURIE_MAP , SCHEMA_YAML , SSSOM_URI_PREFIX , PathOrIO
35+ from .constants import CURIE_MAP , PREDICATE_MODIFIER_NOT , SCHEMA_YAML , SSSOM_URI_PREFIX , PathOrIO
3536from .context import _load_sssom_context
3637from .parsers import to_mapping_set_document
3738from .util import (
5556OWL_EQUIV_OBJECTPROPERTY = "http://www.w3.org/2002/07/owl#equivalentProperty"
5657SSSOM_NS = SSSOM_URI_PREFIX
5758
59+ NO_TERM_REF = rdflib .URIRef ("https://w3id.org/sssom/NoTermFound" )
60+ PREDICATE_MODIFIER = rdflib .URIRef ("https://w3id.org/sssom/predicate_modifier" )
61+ OBJECT_NOT = rdflib .URIRef ("https://w3id.org/sssom/NegatedPredicate" )
62+ LITERAL_NOT = rdflib .Literal (PREDICATE_MODIFIER_NOT )
63+ NEGATED_NODES : set [rdflib .Node ] = {OBJECT_NOT , LITERAL_NOT }
64+
5865# Writers
5966
6067MSDFWriter = Callable [[MappingSetDataFrame , TextIO ], None ]
@@ -116,8 +123,18 @@ def write_rdf(
116123 msdf : MappingSetDataFrame ,
117124 file : PathOrIO ,
118125 serialisation : Optional [str ] = None ,
126+ * ,
127+ hydrate : bool = False ,
119128) -> None :
120- """Write a mapping set dataframe to the file as RDF."""
129+ """Write a mapping set dataframe to the file as RDF.
130+
131+ :param msdf: A mapping set dataframe
132+ :param file: The path or file object to write to
133+ :param serialisation: The RDF format to serialize to, see :data:`RDF_FORMATS`.
134+ Defaults to turtle.
135+ :param hydrate: If true, will add subject-predicate-objects directly representing
136+ mappings. This is opt-in behavior.
137+ """
121138 if serialisation is None :
122139 serialisation = SSSOM_DEFAULT_RDF_SERIALISATION
123140 elif serialisation not in RDF_FORMATS :
@@ -128,7 +145,7 @@ def write_rdf(
128145 serialisation = SSSOM_DEFAULT_RDF_SERIALISATION
129146
130147 check_all_prefixes_in_curie_map (msdf )
131- graph = to_rdf_graph (msdf = msdf )
148+ graph = to_rdf_graph (msdf = msdf , hydrate = hydrate )
132149 t = graph .serialize (format = serialisation , encoding = "utf-8" )
133150 with _open_text_writer (file ) as fh :
134151 print (t .decode (), file = fh )
@@ -204,6 +221,33 @@ def write_owl(
204221# Converters convert a mappingsetdataframe to an object of the supportes types (json, pandas dataframe)
205222
206223
224+ def _hydrate_axioms (
225+ graph : rdflib .Graph ,
226+ * ,
227+ add_negative : bool = True ,
228+ add_no_term_found : bool = True ,
229+ ) -> None :
230+ for axiom in graph .subjects (RDF .type , OWL .Axiom ):
231+ for p in graph .objects (subject = axiom , predicate = OWL .annotatedProperty ):
232+ for s in graph .objects (subject = axiom , predicate = OWL .annotatedSource ):
233+ for o in graph .objects (subject = axiom , predicate = OWL .annotatedTarget ):
234+ if not add_negative and _is_negated (graph , axiom ):
235+ continue
236+ if not add_no_term_found and _is_no_term_found (s , o ):
237+ continue
238+ graph .add ((s , p , o ))
239+
240+
241+ def _is_no_term_found (s : rdflib .Node , o : rdflib .Node ) -> bool :
242+ return s == NO_TERM_REF or o == NO_TERM_REF
243+
244+
245+ def _is_negated (graph : rdflib .Graph , axiom : rdflib .Node ) -> bool :
246+ return any (
247+ obj in NEGATED_NODES for obj in graph .objects (subject = axiom , predicate = PREDICATE_MODIFIER )
248+ )
249+
250+
207251def to_owl_graph (msdf : MappingSetDataFrame ) -> Graph :
208252 """Convert a mapping set dataframe to OWL in an RDF graph."""
209253 msdf .df = invert_mappings (
@@ -217,11 +261,8 @@ def to_owl_graph(msdf: MappingSetDataFrame) -> Graph:
217261 for _s , _p , o in graph .triples ((None , URIRef (URI_SSSOM_MAPPINGS ), None )):
218262 graph .add ((o , URIRef (RDF_TYPE ), OWL .Axiom ))
219263
220- for axiom in graph .subjects (RDF .type , OWL .Axiom ):
221- for p in graph .objects (subject = axiom , predicate = OWL .annotatedProperty ):
222- for s in graph .objects (subject = axiom , predicate = OWL .annotatedSource ):
223- for o in graph .objects (subject = axiom , predicate = OWL .annotatedTarget ):
224- graph .add ((s , p , o ))
264+ # TODO consider making this not add negative or term not found
265+ _hydrate_axioms (graph , add_negative = True , add_no_term_found = True )
225266
226267 sparql_prefixes = """
227268PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
@@ -307,7 +348,7 @@ def to_owl_graph(msdf: MappingSetDataFrame) -> Graph:
307348 return graph
308349
309350
310- def to_rdf_graph (msdf : MappingSetDataFrame ) -> Graph :
351+ def to_rdf_graph (msdf : MappingSetDataFrame , * , hydrate : bool = False ) -> Graph :
311352 """Convert a mapping set dataframe to an RDF graph."""
312353 doc = to_mapping_set_document (msdf )
313354 graph = rdflib_dumper .as_rdf_graph (
@@ -316,6 +357,8 @@ def to_rdf_graph(msdf: MappingSetDataFrame) -> Graph:
316357 # TODO Use msdf.converter directly via https://github.com/linkml/linkml-runtime/pull/278
317358 prefix_map = msdf .converter .bimap ,
318359 )
360+ if hydrate :
361+ _hydrate_axioms (graph , add_no_term_found = False , add_negative = False )
319362 return cast (Graph , graph )
320363
321364
0 commit comments