Coverage for oc_ocdm / graph / entities / identifier.py: 94%
67 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-05-08 20:23 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-05-08 20:23 +0000
1#!/usr/bin/python
3# SPDX-FileCopyrightText: 2020-2022 Simone Persiani <iosonopersia@gmail.com>
4# SPDX-FileCopyrightText: 2022-2023 Arcangelo Massari <arcangelo.massari@unibo.it>
5#
6# SPDX-License-Identifier: ISC
8# -*- coding: utf-8 -*-
9from __future__ import annotations
11import re
12from typing import TYPE_CHECKING
14if TYPE_CHECKING:
15 from typing import Optional
17from triplelite import RDFTerm
19from oc_ocdm.graph.graph_entity import GraphEntity
20from oc_ocdm.support.support import encode_url, is_string_empty
23class Identifier(GraphEntity):
24 """Identifier (short: id): an external identifier (e.g. DOI, ORCID, PubMedID, Open
25 Citation Identifier) associated with the bibliographic entity. Members of this class of
26 metadata are themselves given unique corpus identifiers e.g. 'id/0420129'."""
28 def _merge_properties(self, other: GraphEntity, prefer_self: bool) -> None:
29 """
30 The merge operation allows combining two ``Identifier`` entities into a single one,
31 by marking the second entity as to be deleted while also copying its data into the current
32 ``Identifier``. Moreover, every triple from the containing ``GraphSet`` referring to the second
33 entity gets "redirected" to the current entity: **every other reference contained inside a
34 different source (e.g. a triplestore) must be manually handled by the user!**
36 In case of functional properties, values from the current entity get overwritten
37 by those coming from the second entity while, in all other cases, values from the
38 second entity are simply appended to those of the current entity. In this context,
39 ``rdfs:label`` is considered as a functional property, while ``rdf:type`` is not.
41 :param other: The entity which will be marked as to be deleted and whose properties will
42 be merged into the current entity.
43 :type other: Identifier
44 :raises TypeError: if the parameter is of the wrong type
45 :return: None
46 """
47 super()._merge_properties(other, prefer_self)
48 assert isinstance(other, Identifier)
50 literal_value: Optional[str] = other.get_literal_value()
51 scheme: Optional[str] = other.get_scheme()
52 if literal_value is not None and scheme is not None:
53 self._associate_identifier_with_scheme(literal_value, scheme)
55 # HAS LITERAL VALUE and HAS SCHEME
56 def get_literal_value(self) -> Optional[str]:
57 """
58 Getter method corresponding to the ``literal:hasLiteralValue`` RDF predicate.
60 :return: The requested value if found, None otherwise
61 """
62 return self._get_literal(GraphEntity.iri_has_literal_value)
64 def get_scheme(self) -> Optional[str]:
65 """
66 Getter method corresponding to the ``datacite:usesIdentifierScheme`` RDF predicate.
68 :return: The requested value if found, None otherwise
69 """
70 uri: Optional[str] = self._get_uri_reference(GraphEntity.iri_uses_identifier_scheme)
71 return uri
73 def create_oci(self, string: str) -> None:
74 """
75 Setter method corresponding to both the ``literal:hasLiteralValue`` and the
76 ``datacite:usesIdentifierScheme`` RDF predicate.
77 It implicitly sets the object value ``datacite:oci`` for the
78 ``datacite:usesIdentifierScheme`` RDF predicate.
80 **WARNING: this is a functional property, hence any existing value will be overwritten!**
82 :param string: The value that will be set as the object of the property related to this method
83 :type string: str
84 :raises TypeError: if the parameter is of the wrong type
85 :return: None
86 """
87 self._associate_identifier_with_scheme(string, GraphEntity.iri_oci)
89 def create_orcid(self, string: str) -> None:
90 """
91 Setter method corresponding to both the ``literal:hasLiteralValue`` and the
92 ``datacite:usesIdentifierScheme`` RDF predicate.
93 It implicitly sets the object value ``datacite:orcid`` for the
94 ``datacite:usesIdentifierScheme`` RDF predicate.
96 **WARNING: this is a functional property, hence any existing value will be overwritten!**
98 :param string: The value that will be set as the object of the property related to this method
99 :type string: str
100 :raises TypeError: if the parameter is of the wrong type
101 :return: None
102 """
103 self._associate_identifier_with_scheme(string, GraphEntity.iri_orcid)
105 def create_openalex(self, string: str) -> None:
106 """
107 Setter method corresponding to both the ``literal:hasLiteralValue`` and the
108 ``datacite:usesIdentifierScheme`` RDF predicate.
109 It implicitly sets the object value ``datacite:openalex`` for the
110 ``datacite:usesIdentifierScheme`` RDF predicate.
112 **WARNING: this is a functional property, hence any existing value will be overwritten!**
114 :param string: The value that will be set as the object of the property related to this method
115 :type string: str
116 :raises TypeError: if the parameter is of the wrong type
117 :return: None
118 """
119 self._associate_identifier_with_scheme(string, GraphEntity.iri_openalex)
121 def create_doi(self, string: str) -> None:
122 """
123 Setter method corresponding to both the ``literal:hasLiteralValue`` and the
124 ``datacite:usesIdentifierScheme`` RDF predicate.
125 It implicitly sets the object value ``datacite:doi`` for the
126 ``datacite:usesIdentifierScheme`` RDF predicate.
128 The string gets internally preprocessed by converting it to lowercase
129 (e.g. 'DOI:10.1111/HEX.12487' becomes 'doi:10.1111/hex.12487').
131 **WARNING: this is a functional property, hence any existing value will be overwritten!**
133 :param string: The value that will be set as the object of the property related to this method
134 :type string: str
135 :raises TypeError: if the parameter is of the wrong type
136 :return: None
137 """
138 self._associate_identifier_with_scheme(string.lower(), GraphEntity.iri_doi)
140 def create_jid(self, string: str) -> None:
141 """
142 Setter method corresponding to both the ``literal:hasLiteralValue`` and the
143 ``datacite:usesIdentifierScheme`` RDF predicate.
144 It implicitly sets the object value ``datacite:jid`` for the
145 ``datacite:usesIdentifierScheme`` RDF predicate.
147 **WARNING: this is a functional property, hence any existing value will be overwritten!**
149 :param string: The value that will be set as the object of the property related to this method
150 :type string: str
151 :raises TypeError: if the parameter is of the wrong type
152 :return: None
153 """
154 self._associate_identifier_with_scheme(string, GraphEntity.iri_jid)
156 def create_pmid(self, string: str) -> None:
157 """
158 Setter method corresponding to both the ``literal:hasLiteralValue`` and the
159 ``datacite:usesIdentifierScheme`` RDF predicate.
160 It implicitly sets the object value ``datacite:pmid`` for the
161 ``datacite:usesIdentifierScheme`` RDF predicate.
163 **WARNING: this is a functional property, hence any existing value will be overwritten!**
165 :param string: The value that will be set as the object of the property related to this method
166 :type string: str
167 :raises TypeError: if the parameter is of the wrong type
168 :return: None
169 """
170 self._associate_identifier_with_scheme(string, GraphEntity.iri_pmid)
172 def create_pmcid(self, string: str) -> None:
173 """
174 Setter method corresponding to both the ``literal:hasLiteralValue`` and the
175 ``datacite:usesIdentifierScheme`` RDF predicate.
176 It implicitly sets the object value ``datacite:pmcid`` for the
177 ``datacite:usesIdentifierScheme`` RDF predicate.
179 **WARNING: this is a functional property, hence any existing value will be overwritten!**
181 :param string: The value that will be set as the object of the property related to this method
182 :type string: str
183 :raises TypeError: if the parameter is of the wrong type
184 :return: None
185 """
186 self._associate_identifier_with_scheme(string, GraphEntity.iri_pmcid)
188 def create_issn(self, string: str) -> None:
189 """
190 Setter method corresponding to both the ``literal:hasLiteralValue`` and the
191 ``datacite:usesIdentifierScheme`` RDF predicate.
192 It implicitly sets the object value ``datacite:issn`` for the
193 ``datacite:usesIdentifierScheme`` RDF predicate.
195 The string gets internally preprocessed by eventually replacing long dashes with short ones
196 (e.g. '1522–4501' becomes '1522-4501').
198 **WARNING: this is a functional property, hence any existing value will be overwritten!**
200 :param string: The value that will be set as the object of the property related to this method. **It
201 must be a string different from '0000-0000'.**
202 :type string: str
203 :raises TypeError: if the parameter is of the wrong type
204 :return: None
205 """
206 cur_string = re.sub("–", "-", string)
207 if cur_string != "0000-0000":
208 self._associate_identifier_with_scheme(cur_string, GraphEntity.iri_issn)
210 def create_isbn(self, string: str) -> None:
211 """
212 Setter method corresponding to both the ``literal:hasLiteralValue`` and the
213 ``datacite:usesIdentifierScheme`` RDF predicate.
214 It implicitly sets the object value ``datacite:isbn`` for the
215 ``datacite:usesIdentifierScheme`` RDF predicate.
217 The string gets internally preprocessed by eventually replacing long dashes with short ones
218 (e.g. '817525766–0' becomes '817525766-0').
220 **WARNING: this is a functional property, hence any existing value will be overwritten!**
222 :param string: The value that will be set as the object of the property related to this method
223 :type string: str
224 :raises TypeError: if the parameter is of the wrong type
225 :return: None
226 """
227 self._associate_identifier_with_scheme(re.sub("–", "-", string), GraphEntity.iri_isbn)
229 def create_url(self, string: str) -> None:
230 """
231 Setter method corresponding to both the ``literal:hasLiteralValue`` and the
232 ``datacite:usesIdentifierScheme`` RDF predicate.
233 It implicitly sets the object value ``datacite:url`` for the
234 ``datacite:usesIdentifierScheme`` RDF predicate.
236 The string gets internally preprocessed both by converting it to lowercase
237 (e.g. 'https://OPENCITATIONS.NET/' becomes 'https://opencitations.net/') and by
238 applying `URL encoding` on it (e.g. 'https://opencitations.net/file name.txt'
239 becomes 'https://opencitations.net/file%20name.txt').
241 **WARNING: this is a functional property, hence any existing value will be overwritten!**
243 :param string: The value that will be set as the object of the property related to this method
244 :type string: str
245 :raises TypeError: if the parameter is of the wrong type
246 :return: None
247 """
248 self._associate_identifier_with_scheme(encode_url(string.lower()), GraphEntity.iri_url)
250 def create_xpath(self, string: str) -> None:
251 """
252 Setter method corresponding to both the ``literal:hasLiteralValue`` and the
253 ``datacite:usesIdentifierScheme`` RDF predicate.
254 It implicitly sets the object value `datacite:local-resource-identifier-scheme` for the
255 ``datacite:usesIdentifierScheme`` RDF predicate.
257 **WARNING: this is a functional property, hence any existing value will be overwritten!**
259 :param string: The value that will be set as the object of the property related to this method
260 :type string: str
261 :raises TypeError: if the parameter is of the wrong type
262 :return: None
263 """
264 self._associate_identifier_with_scheme(string, GraphEntity.iri_xpath)
266 def create_intrepid(self, string: str) -> None:
267 """
268 Setter method corresponding to both the ``literal:hasLiteralValue`` and the
269 ``datacite:usesIdentifierScheme`` RDF predicate.
270 It implicitly sets the object value ``datacite:intrepid`` for the
271 ``datacite:usesIdentifierScheme`` RDF predicate.
273 **WARNING: this is a functional property, hence any existing value will be overwritten!**
275 :param string: The value that will be set as the object of the property related to this method
276 :type string: str
277 :raises TypeError: if the parameter is of the wrong type
278 :return: None
279 """
280 self._associate_identifier_with_scheme(string, GraphEntity.iri_intrepid)
282 def create_xmlid(self, string: str) -> None:
283 """
284 Setter method corresponding to both the ``literal:hasLiteralValue`` and the
285 ``datacite:usesIdentifierScheme`` RDF predicate.
286 It implicitly sets the object value `datacite:local-resource-identifier-scheme` for the
287 ``datacite:usesIdentifierScheme`` RDF predicate.
289 **WARNING: this is a functional property, hence any existing value will be overwritten!**
291 :param string: The value that will be set as the object of the property related to this method
292 :type string: str
293 :raises TypeError: if the parameter is of the wrong type
294 :return: None
295 """
296 self._associate_identifier_with_scheme(string, GraphEntity.iri_xmlid)
298 def create_wikidata(self, string: str) -> None:
299 """
300 Setter method corresponding to both the ``literal:hasLiteralValue`` and the
301 ``datacite:usesIdentifierScheme`` RDF predicate.
302 It implicitly sets the object value ``datacite:wikidata`` for the
303 ``datacite:usesIdentifierScheme`` RDF predicate.
305 **WARNING: this is a functional property, hence any existing value will be overwritten!**
307 :param string: The value that will be set as the object of the property related to this method
308 :type string: str
309 :raises TypeError: if the parameter is of the wrong type
310 :return: None
311 """
312 self._associate_identifier_with_scheme(string, GraphEntity.iri_wikidata)
314 def create_wikipedia(self, string: str) -> None:
315 """
316 Setter method corresponding to both the ``literal:hasLiteralValue`` and the
317 ``datacite:usesIdentifierScheme`` RDF predicate.
318 It implicitly sets the object value ``datacite:wikipedia`` for the
319 ``datacite:usesIdentifierScheme`` RDF predicate.
321 **WARNING: this is a functional property, hence any existing value will be overwritten!**
323 :param string: The value that will be set as the object of the property related to this method
324 :type string: str
325 :raises TypeError: if the parameter is of the wrong type
326 :return: None
327 """
328 self._associate_identifier_with_scheme(string, GraphEntity.iri_wikipedia)
330 def create_arxiv(self, string: str) -> None:
331 """
332 Setter method corresponding to both the ``literal:hasLiteralValue`` and the
333 ``datacite:usesIdentifierScheme`` RDF predicate.
334 It implicitly sets the object value ``datacite:crossref`` for the
335 ``datacite:usesIdentifierScheme`` RDF predicate.
337 **WARNING: this is a functional property, hence any existing value will be overwritten!**
339 :param string: The value that will be set as the object of the property related to this method
340 :type string: str
341 :raises TypeError: if the parameter is of the wrong type
342 :return: None
343 """
344 self._associate_identifier_with_scheme(string, GraphEntity.iri_arxiv)
346 def create_crossref(self, string: str) -> None:
347 """
348 Setter method corresponding to both the ``literal:hasLiteralValue`` and the
349 ``datacite:usesIdentifierScheme`` RDF predicate.
350 It implicitly sets the object value ``datacite:crossref`` for the
351 ``datacite:usesIdentifierScheme`` RDF predicate.
353 **WARNING: this is a functional property, hence any existing value will be overwritten!**
355 :param string: The value that will be set as the object of the property related to this method
356 :type string: str
357 :raises TypeError: if the parameter is of the wrong type
358 :return: None
359 """
360 self._associate_identifier_with_scheme(string, GraphEntity.iri_crossref)
362 def create_datacite(self, string: str) -> None:
363 """
364 Setter method corresponding to both the ``literal:hasLiteralValue`` and the
365 ``datacite:usesIdentifierScheme`` RDF predicate.
366 It implicitly sets the object value ``datacite:datacite`` for the
367 ``datacite:usesIdentifierScheme`` RDF predicate.
369 **WARNING: this is a functional property, hence any existing value will be overwritten!**
371 :param string: The value that will be set as the object of the property related to this method
372 :type string: str
373 :raises TypeError: if the parameter is of the wrong type
374 :return: None
375 """
376 self._associate_identifier_with_scheme(string, GraphEntity.iri_datacite)
378 def create_viaf(self, string: str) -> None:
379 """
380 Setter method corresponding to both the ``literal:hasLiteralValue`` and the
381 ``datacite:usesIdentifierScheme`` RDF predicate.
382 It implicitly sets the object value ``datacite:viaf`` for the
383 ``datacite:usesIdentifierScheme`` RDF predicate.
385 **WARNING: this is a functional property, hence any existing value will be overwritten!**
387 :param string: The value that will be set as the object of the property related to this method
388 :type string: str
389 :raises TypeError: if the parameter is of the wrong type
390 :return: None
391 """
392 self._associate_identifier_with_scheme(string, GraphEntity.iri_viaf)
394 def _associate_identifier_with_scheme(self, string: str, id_type: str) -> None:
395 if not is_string_empty(string):
396 self.remove_identifier_with_scheme()
397 self._create_literal(GraphEntity.iri_has_literal_value, string)
398 self.g.add((self.res, GraphEntity.iri_uses_identifier_scheme, RDFTerm("uri", str(id_type))))
400 def remove_identifier_with_scheme(self) -> None:
401 """
402 Remover method corresponding to both the ``literal:hasLiteralValue`` and the
403 ``datacite:usesIdentifierScheme`` RDF predicate.
405 :return: None
406 """
407 self.g.remove((self.res, GraphEntity.iri_has_literal_value, None))
408 self.g.remove((self.res, GraphEntity.iri_uses_identifier_scheme, None))