Repository: Informasjonsforvaltning/fdk-rdf-parser

Issue:
ny startDate & endDate fra skos-ap-no v.2.0.3
ref https://data.norge.no/specification/skos-ap-no-begrep#Begrep-dato-gyldig-fra-og-med og https://data.norge.no/specification/skos-ap-no-begrep#Begrep-dato-gyldig-til-og-med

gyldig fra og til vil ikke lenger bli angitt via en liste med PeriodOfTime, kun direkte angitt på selve begrepet, og skal bruke euvoc:startDate og euvoc:endDate i stedet for hhv schema:startDate og schema:endDate

Disse linjene bør flyttes ut til en egen metode og legge til støtte for v2.0.3 av skos-ap-no:
https://github.com/Informasjonsforvaltning/fdk-rdf-parser/blob/main/src/fdk_rdf_parser/parse_functions/concept.py#L383-L384

Dvs dette i ny skos-ap-no:
````
euvoc:startDate "2020-05-29"^^xsd:date;
euvoc:endDate "2021-05-29"^^xsd:date;
````
er ekvivalent med dette i gammel skos-ap-no:
````
dct:temporal [ a dct:PeriodOfTime ;
    schema:startDate "2020-05-29"^^xsd:date;
    schema:endDate "2021-05-29"^^xsd:date;
] ;
````

Discussion:
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/Informasjonsforvaltning/fdk-rdf-parser/pull/307?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Informasjonsforvaltning) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 100.00%. Comparing base [(`e2ff215`)](https://app.codecov.io/gh/Informasjonsforvaltning/fdk-rdf-parser/commit/e2ff215db4d333aa5a7b2f6068aebc94261c9a16?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Informasjonsforvaltning) to head [(`936eb81`)](https://app.codecov.io/gh/Informasjonsforvaltning/fdk-rdf-parser/pull/307?dropdown=coverage&src=pr&el=desc&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      #307   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           89        89           
  Lines         2372      2376    +4     
  Branches       265       266    +1     
=========================================
+ Hits          2372      2376    +4     
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/Informasjonsforvaltning/fdk-rdf-parser/pull/307?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).

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/tmpillnwrxr

  Using open-source vulnerability database
  Found and scanned 72 packages
  Timestamp 2024-05-24 13:55:53
  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 -->

Patch:
diff --git a/src/fdk_rdf_parser/parse_functions/concept.py b/src/fdk_rdf_parser/parse_functions/concept.py
index cb07846..b8bb792 100644
--- a/src/fdk_rdf_parser/parse_functions/concept.py
+++ b/src/fdk_rdf_parser/parse_functions/concept.py
@@ -18,10 +18,7 @@ from rdflib.namespace import (
     SKOS,
 )
 
-from fdk_rdf_parser.classes import (
-    Concept,
-    Temporal,
-)
+from fdk_rdf_parser.classes import Concept
 from fdk_rdf_parser.classes.concept import (
     AssociativeRelation,
     Collection,
@@ -50,7 +47,7 @@ from fdk_rdf_parser.rdf_utils import (
 from .contactpoint import extract_contact_points
 from .harvest_meta_data import extract_meta_data
 from .publisher import extract_publisher
-from .temporal import extract_temporal
+from .temporal import extract_temporal_skos
 
 
 def parse_text_and_uri(graph: Graph, subject: URIRef) -> TextAndURI:
@@ -340,6 +337,15 @@ def extract_generic_relations(
     return generic_relations if len(generic_relations) > 0 else None
 
 
+def extract_collection_label(
+    graph: Graph, collection_uri: URIRef
+) -> Optional[Dict[str, str]]:
+    if has_literal_value_on_predicate(graph, collection_uri, DCTERMS.title):
+        return value_translations(graph, collection_uri, DCTERMS.title)
+    else:
+        return value_translations(graph, collection_uri, RDFS.label)
+
+
 def parse_collection(graph: Graph, concept_record_uri: URIRef) -> Optional[Collection]:
     collection_record_uri = graph.value(concept_record_uri, DCTERMS.isPartOf)
 
@@ -352,7 +358,7 @@ def parse_collection(graph: Graph, concept_record_uri: URIRef) -> Optional[Colle
             return Collection(
                 id=object_value(graph, collection_record_uri, DCTERMS.identifier),
                 publisher=extract_publisher(graph, collection_uri),
-                label=value_translations(graph, collection_uri, RDFS.label),
+                label=extract_collection_label(graph, collection_uri),
                 uri=collection_uri.toPython(),
                 description=value_translations(
                     graph, collection_uri, DCTERMS.description
@@ -384,8 +390,8 @@ def extract_labels(
 def _parse_concept(
     graph: Graph, fdk_record_uri: URIRef, concept_uri: URIRef
 ) -> Concept:
-    concept_temporal_list = extract_temporal(graph, concept_uri)
-    concept_temporal = concept_temporal_list[0] if concept_temporal_list else Temporal()
+
+    concept_temporal = extract_temporal_skos(graph, concept_uri)
     contact_points = extract_contact_points(graph, concept_uri)
 
     pref_label_list = extract_labels(
diff --git a/src/fdk_rdf_parser/parse_functions/temporal.py b/src/fdk_rdf_parser/parse_functions/temporal.py
index 42e9280..c5c3dca 100644
--- a/src/fdk_rdf_parser/parse_functions/temporal.py
+++ b/src/fdk_rdf_parser/parse_functions/temporal.py
@@ -14,6 +14,7 @@ from fdk_rdf_parser.classes import Temporal
 from fdk_rdf_parser.rdf_utils import (
     date_value,
     dcat_uri,
+    euvoc_uri,
     owl_time_uri,
     resource_list,
     schema_uri,
@@ -59,6 +60,24 @@ def extract_temporal(graph: Graph, subject: URIRef) -> Optional[List[Temporal]]:
     return values if len(values) > 0 else None
 
 
+def extract_temporal_skos(graph: Graph, subject: URIRef) -> Temporal:
+    temporal = Temporal()
+
+    start_value = date_value(graph, subject, euvoc_uri("startDate"))
+    end_value = date_value(graph, subject, euvoc_uri("endDate"))
+
+    deprecated_resource = graph.value(subject, DCTERMS.temporal)
+    if start_value or end_value:
+        temporal = Temporal(startDate=start_value, endDate=end_value)
+    elif deprecated_resource is not None:
+        start_value = date_value(graph, deprecated_resource, schema_uri("startDate"))
+        end_value = date_value(graph, deprecated_resource, schema_uri("endDate"))
+
+        temporal = Temporal(startDate=start_value, endDate=end_value)
+
+    return temporal
+
+
 def extract_owl_time_instant(graph: Graph, subject: Any) -> Optional[str]:
     owl_date = date_value(graph, subject, owl_time_uri("inXSDDateTime"))
     owl_date = (


Test patch:
diff --git a/tests/test_concept.py b/tests/test_concept.py
index 0d0466a..c1bac4d 100644
--- a/tests/test_concept.py
+++ b/tests/test_concept.py
@@ -47,10 +47,11 @@ def test_parse_concepts(mock_reference_data_client: Mock) -> None:
 @prefix xkos:  <http://rdf-vocabulary.ddialliance.org/xkos#> .
 @prefix euvoc:  <http://publications.europa.eu/ontology/euvoc#> .
 @prefix uneskos: <http://purl.org/umu/uneskos#> .
+@prefix schema:  <http://schema.org/> .
 
 <https://registrering-begrep-api.staging.fellesdatakatalog.digdir.no/910258028>
         a               skos:Collection ;
-        rdfs:label      "Concept collection belonging to 910258028" ;
+        dct:title      "Concept collection belonging to 910258028" ;
         dct:identifier  "https://registrering-begrep-api.staging.fellesdatakatalog.digdir.no/910258028" ;
         dct:publisher   <https://data.brreg.no/enhetsregisteret/api/enheter/910258028> ;
         skos:member     <https://registrering-begrep-api.staging.fellesdatakatalog.digdir.no/910258028/c4ae179e-6a3a-42bc-85a2-1e32d75fc013> , <https://registrering-begrep-api.staging.fellesdatakatalog.digdir.no/910258028/3609b02d-72c5-47e0-a6b8-df0a503cf190> , <https://registrering-begrep-api.staging.fellesdatakatalog.digdir.no/910258028/1843b048-f9af-4665-8e53-3c001d0166c0> , <https://registrering-begrep-api.staging.fellesdatakatalog.digdir.no/910258028/9f25b5ad-8aa7-4233-853b-7434e20aeaef> , <https://registrering-begrep-api.staging.fellesdatakatalog.digdir.no/910258028/523ff894-638b-44a2-a4fd-3e96a5a8a5a3> .
@@ -65,6 +66,10 @@ def test_parse_concepts(mock_reference_data_client: Mock) -> None:
 
 <https://registrering-begrep-api.staging.fellesdatakatalog.digdir.no/910258028/1843b048-f9af-4665-8e53-3c001d0166c0>
         a                   skos:Concept ;
+        dct:temporal        [ a           dct:PeriodOfTime ;
+                                schema:startDate "2020-05-29"^^xsd:date;
+                                schema:endDate "2021-05-29"^^xsd:date;
+                                ] ;
         dct:created        "2023-02-17"^^xsd:date ;
         dct:identifier      "1843b048-f9af-4665-8e53-3c001d0166c0" ;
         dct:modified        "2019-12-16"^^xsd:date ;
@@ -301,11 +306,6 @@ def test_parse_concepts(mock_reference_data_client: Mock) -> None:
                 ],
             ),
             definitions=[
-                Definition(
-                    text={"nb": "def-2"},
-                    targetGroup="https://data.norge.no/vocabulary/audience-type#public",
-                    sourceRelationship="https://data.norge.no/vocabulary/relationship-with-source-type#self-composed",
-                ),
                 Definition(
                     text={"nb": "def-1"},
                     sourceRelationship="https://data.norge.no/vocabulary/relationship-with-source-type#self-composed",
@@ -315,6 +315,11 @@ def test_parse_concepts(mock_reference_data_client: Mock) -> None:
                         )
                     ],
                 ),
+                Definition(
+                    text={"nb": "def-2"},
+                    targetGroup="https://data.norge.no/vocabulary/audience-type#public",
+                    sourceRelationship="https://data.norge.no/vocabulary/relationship-with-source-type#self-composed",
+                ),
             ],
             associativeRelation=[
                 AssociativeRelation(
@@ -343,6 +348,8 @@ def test_parse_concepts(mock_reference_data_client: Mock) -> None:
                 ),
             ],
             type="concept",
+            validFromIncluding="2020-05-29",
+            validToIncluding="2021-05-29",
         ),
         "https://registrering-begrep-api.staging.fellesdatakatalog.digdir.no/910258028/3609b02d-72c5-47e0-a6b8-df0a503cf190": Concept(
             id="fc8baf8d-6146-3b69-93c5-52bd41592c4e",
@@ -634,7 +641,9 @@ def test_parse_concept(mock_reference_data_client: Mock) -> None:
             skosno:valueRange
                                   "test-nn"@nn,
                                   "test",
-                                  <https://range.com> .
+                                  <https://range.com> ;
+            euvoc:startDate       "2020-05-29"^^xsd:date;
+            euvoc:endDate         "2021-05-29"^^xsd:date .
 
 
     <http://publications.europa.eu/resource/authority/concept-status/CURRENT>
@@ -706,6 +715,8 @@ def test_parse_concept(mock_reference_data_client: Mock) -> None:
             )
         ],
         type="concept",
+        validFromIncluding="2020-05-29",
+        validToIncluding="2021-05-29",
     )
 
     result = parse_concept(src)