Skip to content

Commit

Permalink
Mapping of subject
Browse files Browse the repository at this point in the history
  • Loading branch information
torleifg committed Jan 14, 2025
1 parent a81b9b2 commit 34041ef
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 86 deletions.
69 changes: 44 additions & 25 deletions src/main/kotlin/no/fdk/concept_catalog/rdf/SkosApNoImport.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package no.fdk.concept_catalog.rdf

import no.fdk.concept_catalog.model.*
import no.fdk.concept_catalog.service.isValidURI
import org.apache.jena.rdf.model.*
import org.apache.jena.vocabulary.DCTerms
import org.apache.jena.vocabulary.OWL
Expand All @@ -25,7 +26,9 @@ fun Model.extractBegreper(catalogId: String): List<Begrep> {
definisjonForAllmennheten = it.extractDefinisjonForAllmennheten(),
definisjonForSpesialister = it.extractDefinisjonForSpesialister(),
merknad = it.extractMerknad(),
eksempel = it.extractEksempel()
eksempel = it.extractEksempel(),
fagområde = it.extractFagområde(),
fagområdeKoder = it.extractFagområdeKoder()
)
}

Expand All @@ -35,7 +38,7 @@ fun Model.extractBegreper(catalogId: String): List<Begrep> {
fun Resource.extractVersjonr(): SemVer? {
return this.getProperty(OWL.versionInfo)
?.let { it.`object`.asLiteralOrNull()?.string }
?.takeIf { it.isNotBlank() and SEM_VAR_REGEX.matches(it) }
?.takeIf { it.isNotBlank() && SEM_VAR_REGEX.matches(it) }
?.let {
SEM_VAR_REGEX.matchEntire(it)?.destructured?.let { (major, minor, patch) ->
SemVer(major.toInt(), minor.toInt(), patch.toInt())
Expand All @@ -45,30 +48,20 @@ fun Resource.extractVersjonr(): SemVer? {

fun Resource.extractStatusUri(): String? {
return this.getProperty(EUVOC.status)
?.let { it.`object`.asResourceOrNull()?.uri }
?.let { it.`object`.asResourceUriOrNull()?.uri }
}

fun Resource.extractAnbefaltTerm(): Term? {
return extractLocalizesStrings(SKOS.prefLabel)
return extractLocalizedStrings(SKOS.prefLabel)
?.let { Term(it) }
}

fun Resource.extractTillattTerm(): Map<String, List<String>>? {
return extractTerm(SKOS.altLabel)
return extractLocalizedStringsAsGrouping(SKOS.altLabel)
}

fun Resource.extractFrarådetTerm(): Map<String, List<String>>? {
return extractTerm(SKOS.hiddenLabel)
}

private fun Resource.extractTerm(property: Property): Map<String, List<String>>? {
return this.listProperties(property)
.toList()
.mapNotNull { it.`object`.asLiteralOrNull() }
.filter { it.language.isNotBlank() and it.string.isNotBlank() }
.groupBy { it.language }
.mapValues { (_, literals) -> literals.map { it.string } }
.takeIf { it.isNotEmpty() }
return extractLocalizedStringsAsGrouping(SKOS.hiddenLabel)
}

fun Resource.extractDefinisjon(): Definisjon? {
Expand All @@ -86,7 +79,7 @@ fun Resource.extractDefinisjonForAllmennheten(): Definisjon? {
.filter {
it.getProperty(DCTerms.audience)
?.`object`
?.asResourceOrNull()
?.asResourceUriOrNull()
?.hasURI(AUDIENCE_TYPE.public.uri) == true
}
.firstNotNullOfOrNull { it.extractDefinition() }
Expand All @@ -99,24 +92,36 @@ fun Resource.extractDefinisjonForSpesialister(): Definisjon? {
.filter {
it.getProperty(DCTerms.audience)
?.`object`
?.asResourceOrNull()
?.asResourceUriOrNull()
?.hasURI(AUDIENCE_TYPE.specialist.uri) == true
}
.firstNotNullOfOrNull { it.extractDefinition() }
}

fun Resource.extractMerknad(): Map<String, String>? {
return extractLocalizesStrings(SKOS.scopeNote)
return extractLocalizedStrings(SKOS.scopeNote)
}

fun Resource.extractEksempel(): Map<String, String>? {
return extractLocalizesStrings(SKOS.example)
return extractLocalizedStrings(SKOS.example)
}

fun Resource.extractFagområde(): Map<String, List<String>>? {
return extractLocalizedStringsAsGrouping(DCTerms.subject)
}

fun Resource.extractFagområdeKoder(): List<String>? {
return this.listProperties(DCTerms.subject)
.toList()
.mapNotNull { it.`object`.asResourceUriOrNull() }
.map { it.toString() }
.takeIf { it.isNotEmpty() }
}

private fun Resource.extractDefinition(): Definisjon? {
val relationshipWithSource: ForholdTilKildeEnum? = this.getProperty(SKOSNO.relationshipWithSource)
?.let { statement ->
statement.`object`.asResourceOrNull()?.let {
statement.`object`.asResourceUriOrNull()?.let {
when {
it.hasURI(RELATIONSHIP.selfComposed.uri) -> ForholdTilKildeEnum.EGENDEFINERT
it.hasURI(RELATIONSHIP.directFromSource.uri) -> ForholdTilKildeEnum.BASERTPAAKILDE
Expand All @@ -132,7 +137,7 @@ private fun Resource.extractDefinition(): Definisjon? {
statement.`object`.let { obj ->
when {
obj.isLiteral -> URITekst(tekst = obj.asLiteralOrNull()?.string)
obj.isResource -> URITekst(uri = obj.asResourceOrNull()?.uri)
obj.isURIResource -> URITekst(uri = obj.asResourceUriOrNull()?.uri)
else -> null

Check warning on line 141 in src/main/kotlin/no/fdk/concept_catalog/rdf/SkosApNoImport.kt

View check run for this annotation

Codecov / codecov/patch

src/main/kotlin/no/fdk/concept_catalog/rdf/SkosApNoImport.kt#L141

Added line #L141 was not covered by tests
}
}
Expand All @@ -143,16 +148,26 @@ private fun Resource.extractDefinition(): Definisjon? {
Kildebeskrivelse(forholdTilKilde = relationshipWithSource, kilde = source)
}

val value: Map<String, String>? = this.extractLocalizesStrings(RDF.value)
val value: Map<String, String>? = this.extractLocalizedStrings(RDF.value)

return value?.let { Definisjon(tekst = it, kildebeskrivelse = sourceDescription) }
}

private fun Resource.extractLocalizesStrings(property: Property): Map<String, String>? {
private fun Resource.extractLocalizedStringsAsGrouping(property: Property): Map<String, List<String>>? {
return this.listProperties(property)
.toList()
.mapNotNull { it.`object`.asLiteralOrNull() }
.filter { it.language.isNotBlank() && it.string.isNotBlank() }
.groupBy { it.language }
.mapValues { (_, literals) -> literals.map { it.string } }
.takeIf { it.isNotEmpty() }
}

private fun Resource.extractLocalizedStrings(property: Property): Map<String, String>? {
return this.listProperties(property)
.toList()
.mapNotNull { it.`object`.asLiteralOrNull() }
.filter { it.language.isNotBlank() and it.string.isNotBlank() }
.filter { it.language.isNotBlank() && it.string.isNotBlank() }
.associate { it.language to it.string }
.takeIf { it.isNotEmpty() }
}
Expand All @@ -164,3 +179,7 @@ private fun RDFNode.asLiteralOrNull(): Literal? {
private fun RDFNode.asResourceOrNull(): Resource? {
return if (this.isResource) this.asResource() else null
}

private fun RDFNode.asResourceUriOrNull(): Resource? {
return if (this.isURIResource && this.asResource().uri.isValidURI()) this.asResource() else null
}
131 changes: 79 additions & 52 deletions src/test/kotlin/no/fdk/concept_catalog/rdf/SkosApNoImportTests.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import no.fdk.concept_catalog.model.URITekst
import org.apache.jena.rdf.model.Model
import org.apache.jena.rdf.model.ModelFactory
import org.apache.jena.riot.Lang
import org.apache.jena.vocabulary.DCTerms
import org.apache.jena.vocabulary.OWL
import org.apache.jena.vocabulary.SKOS
import org.junit.jupiter.api.Assertions.*
Expand All @@ -30,15 +31,17 @@ class SkosApNoImportTests {
assertNotNull(concept.statusURI)

assertNotNull(concept.anbefaltTerm)
concept.tillattTerm?.let { assertFalse(it.isEmpty()) }
concept.frarådetTerm?.let { assertFalse(it.isEmpty()) }
assertFalse(concept.tillattTerm!!.isEmpty())
assertFalse(concept.frarådetTerm!!.isEmpty())

assertNotNull(concept.definisjon)
assertNotNull(concept.definisjonForAllmennheten)
assertNotNull(concept.definisjonForSpesialister)

concept.merknad?.let { assertFalse(it.isEmpty()) }
concept.eksempel?.let { assertFalse(it.isEmpty()) }
assertFalse(concept.merknad!!.isEmpty())
assertFalse(concept.eksempel!!.isEmpty())
assertFalse(concept.fagområde!!.isEmpty())
assertFalse(concept.fagområdeKoder!!.isEmpty())
}
}

Expand Down Expand Up @@ -76,12 +79,12 @@ class SkosApNoImportTests {

assertEquals(1, terms.size)

terms.first()?.navn?.let { localizedTerms ->
assertEquals(2, localizedTerms.size)
assertTrue(localizedTerms.containsKey("nb"))
assertEquals("anbefaltTerm", localizedTerms["nb"])
assertTrue(localizedTerms.containsKey("en"))
assertEquals("recommendedTerm", localizedTerms["en"])
terms.first()!!.navn.let {
assertEquals(2, it.size)
assertTrue(it.containsKey("nb"))
assertEquals("anbefaltTerm", it["nb"])
assertTrue(it.containsKey("en"))
assertEquals("recommendedTerm", it["en"])
}
}

Expand All @@ -95,9 +98,9 @@ class SkosApNoImportTests {

assertEquals(1, terms.size)

terms.first()?.let { localizedTerms ->
assertTrue(localizedTerms.containsKey("nn"))
assertEquals(localizedTerms.getValue("nn").toSet(), setOf("tillattTerm", "tillattTerm2"))
terms.first().let {
assertTrue(it!!.containsKey("nn"))
assertEquals(it.getValue("nn").toSet(), setOf("tillattTerm", "tillattTerm2"))
}
}

Expand All @@ -111,9 +114,9 @@ class SkosApNoImportTests {

assertEquals(1, terms.size)

terms.first()?.let { localizedTerms ->
assertTrue(localizedTerms.containsKey("nb"))
assertEquals(localizedTerms.getValue("nb").toSet(), setOf("fraraadetTerm", "fraraadetTerm2", "Lorem ipsum"))
terms.first().let {
assertTrue(it!!.containsKey("nb"))
assertEquals(it.getValue("nb").toSet(), setOf("fraraadetTerm", "fraraadetTerm2", "Lorem ipsum"))
}
}

Expand All @@ -127,20 +130,20 @@ class SkosApNoImportTests {

assertEquals(1, definitions.size)

definitions.first()?.let {
it.tekst?.let { text ->
assertEquals(2, text.size)
definitions.first().let {
it!!.tekst.let { text ->
assertEquals(2, text!!.size)
assertTrue(text.containsKey("nb"))
assertEquals("definisjon", text["nb"])
assertTrue(text.containsKey("nb"))
assertEquals("definition", text["en"])
}

it.kildebeskrivelse?.let { sourceDescription ->
assertEquals(ForholdTilKildeEnum.EGENDEFINERT, sourceDescription.forholdTilKilde)
it.kildebeskrivelse.let { sourceDescription ->
assertEquals(ForholdTilKildeEnum.EGENDEFINERT, sourceDescription!!.forholdTilKilde)

sourceDescription.kilde?.let { source ->
assertEquals(2, source.size)
sourceDescription.kilde.let { source ->
assertEquals(2, source!!.size)
assertEquals(URITekst(tekst = "kap14"), source.first())
assertEquals(
URITekst(uri = "https://lovdata.no/dokument/NL/lov/1997-02-28-19/kap14#kap14"),
Expand All @@ -161,16 +164,14 @@ class SkosApNoImportTests {

assertEquals(1, definitions.size)

definitions.first()?.let {
it.tekst?.let { text ->
assertEquals(1, text.size)
definitions.first().let {
it!!.tekst.let { text ->
assertEquals(1, text!!.size)
assertTrue(text.containsKey("nb"))
assertEquals("definisjon for allmennheten", text["nb"])
}

it.kildebeskrivelse?.let { sourceDescription ->
assertEquals(ForholdTilKildeEnum.SITATFRAKILDE, sourceDescription.forholdTilKilde)
}
assertEquals(ForholdTilKildeEnum.SITATFRAKILDE, it.kildebeskrivelse!!.forholdTilKilde)
}
}

Expand All @@ -184,16 +185,14 @@ class SkosApNoImportTests {

assertEquals(1, definitions.size)

definitions.first()?.let {
it.tekst?.let { text ->
assertEquals(1, text.size)
definitions.first().let {
it!!.tekst.let { text ->
assertEquals(1, text!!.size)
assertTrue(text.containsKey("nb"))
assertEquals("definisjon for spesialister", text["nb"])
}

it.kildebeskrivelse?.let { sourceDescription ->
assertEquals(ForholdTilKildeEnum.BASERTPAAKILDE, sourceDescription.forholdTilKilde)
}
assertEquals(ForholdTilKildeEnum.BASERTPAAKILDE, it.kildebeskrivelse!!.forholdTilKilde)
}
}

Expand All @@ -207,40 +206,68 @@ class SkosApNoImportTests {

assertEquals(1, notes.size)

notes.first()?.let { localizedNote ->
assertEquals(2, localizedNote.size)
assertTrue(localizedNote.containsKey("nb"))
assertEquals("merknad", localizedNote["nb"])
assertTrue(localizedNote.containsKey("nn"))
assertEquals("merknad", localizedNote["nn"])
notes.first().let {
assertEquals(2, it!!.size)
assertTrue(it.containsKey("nb"))
assertEquals("merknad", it["nb"])
assertTrue(it.containsKey("nn"))
assertEquals("merknad", it["nn"])
}
}

@Test
fun `should extract eksempel`() {
val model = readModel("import_concept.ttl")

val notes = model.listResourcesWithProperty(SKOS.example)
val examples = model.listResourcesWithProperty(SKOS.example)
.toList()
.map { it.extractEksempel() }

assertEquals(1, notes.size)
assertEquals(1, examples.size)

examples.first().let {
assertEquals(2, it!!.size)
assertTrue(it.containsKey("nb"))
assertEquals("eksempel", it["nb"])
assertTrue(it.containsKey("nn"))
assertEquals("eksempel", it["nn"])
}
}

@Test
fun `should extract fagområde`() {
val model = readModel("import_concept.ttl")

val subjects = model.listResourcesWithProperty(DCTerms.subject)
.toList()
.map { it.extractFagområde() }

assertEquals(1, subjects.size)

notes.first()?.let { localizedNote ->
assertEquals(2, localizedNote.size)
assertTrue(localizedNote.containsKey("nb"))
assertEquals("eksempel", localizedNote["nb"])
assertTrue(localizedNote.containsKey("nn"))
assertEquals("eksempel", localizedNote["nn"])
subjects.first().let {
assertTrue(it!!.containsKey("nb"))
assertEquals(it.getValue("nb").toSet(), setOf("fagområde"))
}
}

@Test
fun `should extract fagområdeKoder`() {
val model = readModel("import_concept.ttl")

val subjects = model.listResourcesWithProperty(DCTerms.subject)
.toList()
.map { it.extractFagområdeKoder() }

assertEquals(1, subjects.size)

assertTrue(subjects.first()!!.contains("https://example.com/fagområdekode"))
}

private fun readModel(file: String): Model {
val turtle = javaClass.classLoader.getResourceAsStream(file)
?.let { String(it.readAllBytes(), StandardCharsets.UTF_8) }
val turtle = String(javaClass.classLoader.getResourceAsStream(file)!!.readAllBytes(), StandardCharsets.UTF_8)

val model = ModelFactory.createDefaultModel()
model.read(StringReader(turtle!!), "http://example.com", Lang.TURTLE.name)
model.read(StringReader(turtle), "http://example.com", Lang.TURTLE.name)

return model
}
Expand Down
Loading

0 comments on commit 34041ef

Please sign in to comment.