Repository: Informasjonsforvaltning/fdk-rdf-parser

Issue:
Legg til støtte for labels fra skos-ap-no v.2.0.3
prefLabel, altLabel og hiddenLabel får alle tre nye predikater og går over til å være direkte angivelse

- `skosxl:prefLabel` -> direkte angivelse på `skos:prefLabel`[ref](https://data.norge.no/specification/skos-ap-no-begrep#Begrep-anbefalt-term)
- `skosxl:altLabel` -> direkte angivelse på `skos:altLabel` [ref](https://data.norge.no/specification/skos-ap-no-begrep#Begrep-tillatt-term)
- `skosxl:hiddenLabel` -> direkte angivelse på `skos:hiddenLabel` [ref](https://data.norge.no/specification/skos-ap-no-begrep#Begrep-frar%C3%A5dd-term)

i.e.
`````
skosxl:prefLabel [ a                   skosxl:Label ;
                              skosxl:literalForm  "språkkode"@nb
                            ] ;
`````
👇 
`````
skos:prefLabel "språkkode"@nb ;
`````

Discussion:
github-actions[bot]: ```
Warning: poetry-plugin-export will not be installed by default in a future version of Poetry.
In order to avoid a breaking change and make your automation forward-compatible, please install poetry-plugin-export explicitly. See https://python-poetry.org/docs/plugins/#using-plugins for details on how to install a plugin.
To disable this warning run 'poetry config warnings.export false'.
The `--dev` option is deprecated, use the `--with dev` notation instead.
+==============================================================================+

                                   /$$$$$$            /$$
                                  /$$__  $$          | $$
               /$$$$$$$  /$$$$$$ | $$  \__//$$$$$$  /$$$$$$   /$$   /$$
              /$$_____/ |____  $$| $$$$   /$$__  $$|_  $$_/  | $$  | $$
             |  $$$$$$   /$$$$$$$| $$_/  | $$$$$$$$  | $$    | $$  | $$
              \____  $$ /$$__  $$| $$    | $$_____/  | $$ /$$| $$  | $$
              /$$$$$$$/|  $$$$$$$| $$    |  $$$$$$$  |  $$$$/|  $$$$$$$
             |_______/  \_______/|__/     \_______/   \___/   \____  $$
                                                              /$$  | $$
                                                             |  $$$$$$/
      by safetycli.com                                        \______/

+==============================================================================+

 REPORT 

  Safety is using PyUp's free open-source vulnerability database. This
data is 30 days old and limited. 
  For real-time enhanced vulnerability data, fix recommendations, severity
reporting, cybersecurity support, team and project policy management and more
sign up at https://pyup.io or email sales@pyup.io

  Safety v3.1.0 is scanning for Vulnerabilities...
  Scanning dependencies in your files:

  -> /tmp/tmpeg_9z2g2

  Using open-source vulnerability database
  Found and scanned 72 packages
  Timestamp 2024-05-08 11:01:27
  0 vulnerabilities reported
  0 vulnerabilities ignored

+==============================================================================+

 No known security vulnerabilities found.

+==============================================================================+

  Safety is using PyUp's free open-source vulnerability database. This
data is 30 days old and limited. 
  For real-time enhanced vulnerability data, fix recommendations, severity
reporting, cybersecurity support, team and project policy management and more
sign up at https://pyup.io or email sales@pyup.io

+==============================================================================+
```
<!-- Sticky Pull Request CommentSafety result -->
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/Informasjonsforvaltning/fdk-rdf-parser/pull/297?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Informasjonsforvaltning) Report
Attention: Patch coverage is `91.66667%` with `1 lines` in your changes are missing coverage. Please review.
> Project coverage is 99.78%. Comparing base [(`969a0bd`)](https://app.codecov.io/gh/Informasjonsforvaltning/fdk-rdf-parser/commit/969a0bdc1110685f4c2bea4ca4ceba4106488e33?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Informasjonsforvaltning) to head [(`d22516d`)](https://app.codecov.io/gh/Informasjonsforvaltning/fdk-rdf-parser/pull/297?dropdown=coverage&src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Informasjonsforvaltning).

| [Files](https://app.codecov.io/gh/Informasjonsforvaltning/fdk-rdf-parser/pull/297?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Informasjonsforvaltning) | Patch % | Lines |
|---|---|---|
| [src/fdk\_rdf\_parser/parse\_functions/concept.py](https://app.codecov.io/gh/Informasjonsforvaltning/fdk-rdf-parser/pull/297?src=pr&el=tree&filepath=src%2Ffdk_rdf_parser%2Fparse_functions%2Fconcept.py&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Informasjonsforvaltning#diff-c3JjL2Zka19yZGZfcGFyc2VyL3BhcnNlX2Z1bmN0aW9ucy9jb25jZXB0LnB5) | 91.66% | [0 Missing and 1 partial :warning: ](https://app.codecov.io/gh/Informasjonsforvaltning/fdk-rdf-parser/pull/297?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Informasjonsforvaltning) |

<details><summary>Additional details and impacted files</summary>


```diff
@@             Coverage Diff             @@
##              main     #297      +/-   ##
===========================================
- Coverage   100.00%   99.78%   -0.22%     
===========================================
  Files           89       89              
  Lines         2366     2377      +11     
  Branches       263      268       +5     
===========================================
+ Hits          2366     2372       +6     
- Misses           0        3       +3     
- Partials         0        2       +2     
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/Informasjonsforvaltning/fdk-rdf-parser/pull/297?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Informasjonsforvaltning).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Informasjonsforvaltning).


Patch:
diff --git a/src/fdk_rdf_parser/parse_functions/concept.py b/src/fdk_rdf_parser/parse_functions/concept.py
index 75c9731..e891d18 100644
--- a/src/fdk_rdf_parser/parse_functions/concept.py
+++ b/src/fdk_rdf_parser/parse_functions/concept.py
@@ -35,6 +35,7 @@ from fdk_rdf_parser.rdf_utils import (
     date_value,
     dcat_uri,
     euvoc_uri,
+    has_literal_value_on_predicate,
     has_value_on_predicate,
     is_type,
     object_value,
@@ -356,15 +357,24 @@ def parse_collection(graph: Graph, concept_record_uri: URIRef) -> Optional[Colle
     return None
 
 
-def parse_label_set(
-    graph: Graph, concept_uri: URIRef, predicate: URIRef
+def extract_labels(
+    graph: Graph, concept_uri: URIRef, predicate: URIRef, predicate_deprecated: URIRef
 ) -> Optional[List[Dict[str, str]]]:
-    values = []
-    for label in graph.objects(concept_uri, predicate):
-        literal_form = value_translations(graph, label, skosxl_uri("literalForm"))
-        if literal_form:
-            values.append(literal_form)
-    return values if len(values) > 0 else None
+    labels = list()
+    if has_literal_value_on_predicate(graph, concept_uri, predicate):
+        main_labels = value_translations(graph, concept_uri, predicate)
+        labels.append(main_labels) if main_labels is not None else None
+
+    else:
+        deprecated_labels = [
+            value_translations(graph, label, skosxl_uri("literalForm"))
+            for label in graph.objects(concept_uri, predicate_deprecated)
+        ]
+
+        for label in deprecated_labels:
+            labels.append(label) if label is not None else None
+
+    return labels if len(labels) > 0 else None
 
 
 def _parse_concept(
@@ -374,7 +384,9 @@ def _parse_concept(
     concept_temporal = concept_temporal_list[0] if concept_temporal_list else Temporal()
     contact_points = extract_contact_points(graph, concept_uri)
 
-    pref_label_list = parse_label_set(graph, concept_uri, skosxl_uri("prefLabel"))
+    pref_label_list = extract_labels(
+        graph, concept_uri, SKOS.prefLabel, skosxl_uri("prefLabel")
+    )
     definition_list = extract_definitions(graph, concept_uri)
 
     return Concept(
@@ -390,8 +402,12 @@ def _parse_concept(
         prefLabel=(
             pref_label_list[0] if pref_label_list and len(pref_label_list) > 0 else None
         ),
-        hiddenLabel=parse_label_set(graph, concept_uri, skosxl_uri("hiddenLabel")),
-        altLabel=parse_label_set(graph, concept_uri, skosxl_uri("altLabel")),
+        hiddenLabel=extract_labels(
+            graph, concept_uri, SKOS.hiddenLabel, skosxl_uri("hiddenLabel")
+        ),
+        altLabel=extract_labels(
+            graph, concept_uri, SKOS.altLabel, skosxl_uri("altLabel")
+        ),
         contactPoint=contact_points[0] if contact_points else None,
         definition=get_first_definition_with_no_target_group(definition_list),
         definitions=definition_list,
@@ -407,6 +423,6 @@ def _parse_concept(
         exactMatch=value_set(graph, concept_uri, SKOS.exactMatch),
         closeMatch=value_set(graph, concept_uri, SKOS.closeMatch),
         memberOf=value_set(graph, concept_uri, uneskos_uri("memberOf")),
-        remark=parse_label_set(graph, concept_uri, SKOS.scopeNote),
+        remark=extract_labels(graph, concept_uri, SKOS.scopeNote, SKOS.scopeNote),
         range=extract_range(graph, concept_uri),
     )
diff --git a/src/fdk_rdf_parser/rdf_utils/__init__.py b/src/fdk_rdf_parser/rdf_utils/__init__.py
index 6d4607f..4148f87 100644
--- a/src/fdk_rdf_parser/rdf_utils/__init__.py
+++ b/src/fdk_rdf_parser/rdf_utils/__init__.py
@@ -32,6 +32,7 @@ from .ns import (
 from .utils import (
     date_value,
     duration_string_value,
+    has_literal_value_on_predicate,
     has_value_on_predicate,
     is_type,
     linguistic_system_keywords,
diff --git a/src/fdk_rdf_parser/rdf_utils/utils.py b/src/fdk_rdf_parser/rdf_utils/utils.py
index b69d91b..ee0fd48 100644
--- a/src/fdk_rdf_parser/rdf_utils/utils.py
+++ b/src/fdk_rdf_parser/rdf_utils/utils.py
@@ -19,6 +19,7 @@ from isodate import (
 from rdflib import (
     BNode,
     Graph,
+    Literal,
     URIRef,
 )
 from rdflib.namespace import (
@@ -39,6 +40,13 @@ def has_value_on_predicate(graph: Graph, subject: URIRef, predicate: URIRef) ->
     return graph.value(subject, predicate) is not None
 
 
+def has_literal_value_on_predicate(
+    graph: Graph, subject: URIRef, predicate: URIRef
+) -> bool:
+    value = graph.value(subject, predicate)
+    return isinstance(value, Literal)
+
+
 def object_value(graph: Graph, subject: URIRef, predicate: URIRef) -> Optional[Any]:
     value = graph.value(subject, predicate)
     return value.toPython() if value and not isinstance(value, BNode) else None


Test patch:
diff --git a/tests/test_concept.py b/tests/test_concept.py
index 2e0aecd..7b4dc47 100644
--- a/tests/test_concept.py
+++ b/tests/test_concept.py
@@ -77,6 +77,7 @@ def test_parse_concepts(mock_reference_data_client: Mock) -> None:
                               skosxl:literalForm  "w"@nb
                             ] ;
         skosxl:hiddenLabel  [ ] ;
+        skos:hiddenLabel    "hidden"@nb ;
         skosxl:prefLabel    [ a                   skosxl:Label ;
                               skosxl:literalForm  "to"@nb
                             ] ;
@@ -289,6 +290,7 @@ def test_parse_concepts(mock_reference_data_client: Mock) -> None:
                 "nn": "gjeldande",
                 "nb": "gjeldende",
             },
+            hiddenLabel=[{"nb": "hidden"}],
             altLabel=[{"nb": "w"}],
             definition=Definition(
                 text={"nb": "def-1"},
@@ -622,9 +624,7 @@ def test_parse_concept(mock_reference_data_client: Mock) -> None:
             skos:exactMatch     <http://begrepskatalogen/begrep/20b2e2ab-9fe1-11e5-a9f8-e4115b280940> ;
             skos:closeMatch     <http://begrepskatalogen/begrep/20b2e2aa-9fe1-11e5-a9f8-e4115b280940> ;
             uneskos:memberOf    <https://registrering-begrep-api.staging.fellesdatakatalog.digdir.no/910258028> ;
-            skosxl:altLabel     [ a                   skosxl:Label ;
-                                skosxl:literalForm  "w"@nb
-                                ] ;
+            skos:altLabel       "altLabel"@nb, "altLabel2"@en ;
             skosxl:hiddenLabel  [ ] ;
             skosxl:prefLabel    [ a                   skosxl:Label ;
                                 skosxl:literalForm  "to"@nb
@@ -695,7 +695,7 @@ def test_parse_concept(mock_reference_data_client: Mock) -> None:
             "nn": "gjeldande",
             "nb": "gjeldende",
         },
-        altLabel=[{"nb": "w"}],
+        altLabel=[{"nb": "altLabel", "en": "altLabel2"}],
         definition=Definition(
             text={"nb": "skos_definition"},
         ),