66from dataclasses import make_dataclass
77from datetime import datetime
88from typing import List , Union , Dict , Optional , Tuple
9+
910import rdflib
1011from ontolutils import namespaces , urirefs , Thing , as_id
1112from ontolutils .namespacelib .m4i import M4I
1213from pydantic import field_validator , Field , HttpUrl , ValidationError , model_validator
1314from rdflib import URIRef
15+
1416from ssnolib import config
1517from ssnolib .dcat import Distribution , Dataset
1618from ssnolib .m4i import TextVariable
2022from ssnolib .skos import Concept
2123from ssnolib .sparql_utils import build_simple_sparql_query , WHERE
2224from ssnolib .utils import parse_and_exclude_none , download_file
23-
2425from . import plugins
2526from .standard_name import StandardName , VectorStandardName , ScalarStandardName
2627from .unit_utils import _parse_unit , reverse_qudt_lookup , _format_unit
@@ -123,6 +124,20 @@ def __str__(self) -> str:
123124 return f'{ self .__class__ .__name__ } ("{ self .name } ")'
124125
125126
127+ @namespaces (ssno = "https://matthiasprobst.github.io/ssno#" ,
128+ schema = "https://schema.org/" ,
129+ dcterms = "http://purl.org/dc/terms/" )
130+ @urirefs (DomainConceptSet = 'ssno:DomainConceptSet' ,
131+ hasValidValues = 'ssno:hasValidValues' ,
132+ name = 'schema:name' ,
133+ description = 'dcterms:description' )
134+ class DomainConceptSet (Concept ):
135+ """Implementation of ssno:Collection"""
136+ name : str # schema:name
137+ description : str # dcterms:description
138+ hasValidValues : Optional [List [Union [str , Dict , TextVariable ]]] = None # ssno:hasValidValues
139+
140+
126141@namespaces (ssno = "https://matthiasprobst.github.io/ssno#" )
127142@urirefs (Qualification = 'ssno:Qualification' ,
128143 before = 'ssno:before' ,
@@ -200,7 +215,7 @@ class Character(Concept):
200215 """Implementation of ssno:Transformation"""
201216
202217 character : str # ssno:character
203- associatedWith : Union [str , HttpUrl , Qualification ] # ssno:associatedWith
218+ associatedWith : Union [str , HttpUrl , Qualification , DomainConceptSet ] # ssno:associatedWith
204219
205220 @field_validator ('associatedWith' , mode = 'before' )
206221 @classmethod
@@ -251,6 +266,7 @@ def _hasCharacter(cls, hasCharacter):
251266 qualifiedAttribution = 'prov:qualifiedAttribution' ,
252267 standardNames = 'ssno:standardNames' ,
253268 hasModifier = 'ssno:hasModifier' ,
269+ hasDomainConceptSet = 'ssno:hasDomainConceptSet' ,
254270 subject = 'dcterms:subject' ,
255271 keywords = 'schema:keywords' ,
256272 relation = 'dcterms:relation' ,
@@ -297,6 +313,7 @@ class StandardNameTable(Concept):
297313 hasModifier : Optional [
298314 List [Union [Qualification , VectorQualification , Transformation ]]
299315 ] = Field (default = None , alias = "has_modifier" ) # ssno:hasModifier
316+ hasDomainConceptSet : Optional [List [DomainConceptSet ]] = Field (default = None , alias = "has_domain_concept_set" )
300317 subject : Optional [Union [str , HttpUrl ]] = Field (default = None )
301318 keywords : Optional [Union [str , List [str ]]] = Field (default = None )
302319 relation : Optional [Union [Thing , List [Thing ]]] = Field (default = None )
@@ -1260,7 +1277,7 @@ def parse_table(source=None, data=None, fmt: Optional[str] = None):
12601277 # jetzt qualifications holen:
12611278 has_modifier = []
12621279 for _type in ("ssno:Qualification" , "ssno:VectorQualification" ):
1263- sparql = build_simple_sparql_query (
1280+ sparql_modifiers = build_simple_sparql_query (
12641281 prefixes = prefixes ,
12651282 wheres = [
12661283 WHERE (snt_id , "ssno:hasModifier" , "?modifierID" ),
@@ -1272,7 +1289,7 @@ def parse_table(source=None, data=None, fmt: Optional[str] = None):
12721289 WHERE ("?modifierID" , "dcterms:description" , "?description" , is_optional = True )
12731290 ]
12741291 )
1275- for res in sparql .query (g ):
1292+ for res in sparql_modifiers .query (g ):
12761293 modifierID = _parse_id (res ['modifierID' ])
12771294 # now look for the valid values:
12781295 sparql_valid_values = build_simple_sparql_query (
@@ -1334,7 +1351,6 @@ def parse_table(source=None, data=None, fmt: Optional[str] = None):
13341351 ]
13351352 )
13361353
1337-
13381354 for res in sparql_transformation .query (g ):
13391355 hasCharacter = []
13401356 modifierID = _parse_id (res ['modifierID' ])
@@ -1350,14 +1366,58 @@ def parse_table(source=None, data=None, fmt: Optional[str] = None):
13501366 )
13511367 for character in sparql_hasCharacter .query (g ):
13521368 hasCharacter .append (
1353- Character (id = character ["hasCharacterID" ], character = character ["character" ].value , associatedWith = character ["associatedWith" ].value ))
1369+ Character (id = character ["hasCharacterID" ], character = character ["character" ].value ,
1370+ associatedWith = character ["associatedWith" ].value ))
13541371 has_modifier .append (
13551372 Transformation (name = res ['name' ].value , description = res ['description' ], altersUnit = res ['altersUnit' ],
13561373 hasCharacter = hasCharacter )
13571374 )
13581375 if has_modifier :
13591376 snt .hasModifier = has_modifier
13601377
1378+ # domain concept sets holen:
1379+ domain_concept_sets = []
1380+ sparql_domain_concept_sets = build_simple_sparql_query (
1381+ prefixes = prefixes ,
1382+ wheres = [
1383+ WHERE (snt_id , "ssno:hasDomainConceptSet" , "?domainConceptSetID" ),
1384+ WHERE ("?domainConceptSetID" , "a" , "ssno:DomainConceptSet" ),
1385+ WHERE ("?domainConceptSetID" , "schema:name" , "?name" ),
1386+ WHERE ("?domainConceptSetID" , "dcterms:description" , "?description" , is_optional = True ),
1387+ ]
1388+ )
1389+
1390+ for res in sparql_domain_concept_sets .query (g ):
1391+ domain_concept_set_id = _parse_id (res ['domainConceptSetID' ])
1392+ # now look for the valid values:
1393+ sparql_valid_values = build_simple_sparql_query (
1394+ prefixes = prefixes ,
1395+ wheres = [
1396+ WHERE (domain_concept_set_id , "ssno:hasValidValues" , "?hasValidValuesID" ),
1397+ WHERE ("?hasValidValuesID" , "a" , "m4i:TextVariable" ),
1398+ WHERE ("?hasValidValuesID" , "m4i:hasStringValue" , "?hasStringValue" ),
1399+ WHERE ("?hasValidValuesID" , "m4i:hasVariableDescription" , "?hasVariableDescription" ,
1400+ is_optional = True ),
1401+ ]
1402+ )
1403+ hasValidValues = []
1404+ for valid_values in sparql_valid_values .query (g ):
1405+ validvalues_dict = dict (hasStringValue = valid_values ['hasStringValue' ],
1406+ hasVariableDescription = valid_values ['hasVariableDescription' ])
1407+ hasValidValues .append (
1408+ TextVariable (** {k : v .value .strip () for k , v in validvalues_dict .items () if v }))
1409+
1410+ has_domain_concept_set_dict = dict (name = res ['name' ].value , description = res ['description' ].value )
1411+ domain_concept_sets .append (
1412+ DomainConceptSet (
1413+ id = domain_concept_set_id ,
1414+ hasValidValues = hasValidValues ,
1415+ ** {k : v for k , v in has_domain_concept_set_dict .items () if v }
1416+ )
1417+ )
1418+
1419+ snt .hasDomainConceptSet = domain_concept_sets
1420+
13611421 standard_names = []
13621422
13631423 sparql_get_vector_standard_names = build_simple_sparql_query (
@@ -1471,8 +1531,16 @@ def get_regex_from_transformation(transformation: Transformation) -> str:
14711531
14721532def check_if_standard_name_can_be_build_with_transformation (standard_name : str , snt : StandardNameTable ) -> Tuple [
14731533 List [StandardName ], Union [Transformation , None ]]:
1474- transformations = [t for t in snt .hasModifier if isinstance (t , Transformation )]
1475- qualifications = {t .id : t for t in snt .hasModifier if isinstance (t , Qualification )}
1534+ if snt .hasModifier is None :
1535+ transformations = {}
1536+ qualifications = {}
1537+ else :
1538+ transformations = [t for t in snt .hasModifier if isinstance (t , Transformation )]
1539+ qualifications = {t .id : t for t in snt .hasModifier if isinstance (t , Qualification )}
1540+ if snt .hasDomainConceptSet is not None :
1541+ domain_concept_sets = {t .id : t for t in snt .hasDomainConceptSet if isinstance (t , DomainConceptSet )}
1542+ else :
1543+ domain_concept_sets = {}
14761544 for transformation in transformations :
14771545 pattern = get_regex_from_transformation (transformation )
14781546 match = re .fullmatch (f"^{ pattern } $" , standard_name )
@@ -1488,13 +1556,18 @@ def check_if_standard_name_can_be_build_with_transformation(standard_name: str,
14881556 found_ns = snt .get_standard_name (term )
14891557 if found_ns :
14901558 matching_standard_names .append (found_ns )
1491- else : # must be qualificaiton
1492- # search in qualifications
1493- found_q = qualifications .get (char .associatedWith )
1494- if found_q :
1495- if term in [v .hasStringValue for v in found_q .hasValidValues ]:
1496- found_valid_value = [v for v in found_q .hasValidValues if v .hasStringValue == term ][0 ]
1497- matching_standard_names .append (found_valid_value )
1559+ elif str (char .associatedWith ) in domain_concept_sets :
1560+ found_dcs = domain_concept_sets .get (char .associatedWith )
1561+ if term in [v .hasStringValue for v in found_dcs .hasValidValues ]:
1562+ found_valid_value = [v for v in found_dcs .hasValidValues if v .hasStringValue == term ][0 ]
1563+ matching_standard_names .append (found_valid_value )
1564+ elif str (char .associatedWith ) in qualifications :
1565+ found_q = domain_concept_sets .get (char .associatedWith )
1566+ if term in [v .hasStringValue for v in found_q .hasValidValues ]:
1567+ found_valid_value = [v for v in found_q .hasValidValues if v .hasStringValue == term ][0 ]
1568+ matching_standard_names .append (found_valid_value )
1569+ else : # must be qualification or domain concept set
1570+ raise ValueError (f"Unknown associatedWith value { char .associatedWith } " )
14981571 if len (matching_standard_names ) == len (terms ):
14991572 return matching_standard_names , transformation
15001573 # matching_standard_names = [snt.get_standard_name(t) for t in terms]
0 commit comments