Add support for some basic standard P5 elements
Change-Id: I70fcc2c2d6222d75c9baa59c1eb3311c171d6ed6
diff --git a/app/src/main/kotlin/de/ids_mannheim/korapxmltools/KorapXmlTool.kt b/app/src/main/kotlin/de/ids_mannheim/korapxmltools/KorapXmlTool.kt
index 066c0a8..f4c8425 100644
--- a/app/src/main/kotlin/de/ids_mannheim/korapxmltools/KorapXmlTool.kt
+++ b/app/src/main/kotlin/de/ids_mannheim/korapxmltools/KorapXmlTool.kt
@@ -2090,9 +2090,23 @@
val headerRoot = headerDoc.documentElement
headerRoot.normalize()
- val textSigle = headerRoot.firstText("textSigle")
- val docSigle = headerRoot.firstText("dokumentSigle")
- val corpusSigle = headerRoot.firstText("korpusSigle")
+ val entryPath = headerEntry.name
+ val pathParts = entryPath.split('/').filter { it.isNotEmpty() && !it.endsWith("header.xml") }
+
+ var textSigle = headerRoot.firstText("textSigle")
+ var docSigle = headerRoot.firstText("dokumentSigle")
+ var corpusSigle = headerRoot.firstText("korpusSigle")
+
+ if (textSigle == null && docSigle == null && corpusSigle == null) {
+ if (pathParts.size == 1) {
+ corpusSigle = pathParts[0]
+ } else if (pathParts.size == 2) {
+ docSigle = "${pathParts[0]}/${pathParts[1]}"
+ } else if (pathParts.size >= 3) {
+ textSigle = getTextIdFromPath(entryPath)
+ }
+ }
+
val docId = textSigle?.replace('/', '_')
// Call appropriate metadata collection function based on what the header contains
@@ -3261,9 +3275,22 @@
val headerRoot = headerDoc.documentElement
headerRoot.normalize()
- val textSigle = headerRoot.firstText("textSigle")
- val docSigle = headerRoot.firstText("dokumentSigle")
- val corpusSigle = headerRoot.firstText("korpusSigle")
+ val entryPath = zipEntry.name
+ val pathParts = entryPath.split('/').filter { it.isNotEmpty() && !it.endsWith("header.xml") }
+
+ var textSigle = headerRoot.firstText("textSigle")
+ var docSigle = headerRoot.firstText("dokumentSigle")
+ var corpusSigle = headerRoot.firstText("korpusSigle")
+
+ if (textSigle == null && docSigle == null && corpusSigle == null) {
+ if (pathParts.size == 1) {
+ corpusSigle = pathParts[0]
+ } else if (pathParts.size == 2) {
+ docSigle = "${pathParts[0]}/${pathParts[1]}"
+ } else if (pathParts.size >= 3) {
+ textSigle = getTextIdFromPath(entryPath)
+ }
+ }
val docId = textSigle?.replace('/', '_')
LOGGER.fine("Processing header file: " + zipEntry.name + " docId: " + docId + " corpusSigle: " + corpusSigle + " docSigle: " + docSigle)
@@ -5414,7 +5441,12 @@
val textDesc = headerRoot.firstElement("textDesc")
val textClassElement = headerRoot.firstElement("textClass")
- metadata.putIfNotBlank("author", analytic.firstText("h.author") ?: monogr.firstText("h.author") ?: headerRoot.firstText("h.author"))
+ val author = analytic.firstText("h.author")
+ ?: monogr.firstText("h.author")
+ ?: headerRoot.firstText("h.author")
+ ?: headerRoot.firstText("author") { it.getAttribute("role") == "primary" }
+ ?: headerRoot.firstText("author")
+ metadata.putIfNotBlank("author", author)
val mainTitle = analytic.firstText("h.title") { it.getAttribute("type") == "main" }
?: analytic.firstText("h.title")
@@ -5423,6 +5455,8 @@
?: headerRoot.firstText("d.title")
?: headerRoot.firstText("c.title") { it.getAttribute("type") == "main" }
?: headerRoot.firstText("c.title")
+ ?: headerRoot.firstText("title") { it.getAttribute("type") == "main" }
+ ?: headerRoot.firstText("title")
metadata.putIfNotBlank("title", mainTitle)
metadata.putIfNotBlank(
@@ -5430,6 +5464,7 @@
analytic.firstText("h.title") { it.getAttribute("type") == "sub" }
?: monogr.firstText("h.title") { it.getAttribute("type") == "sub" }
?: headerRoot.firstText("c.title") { it.getAttribute("type") == "sub" }
+ ?: headerRoot.firstText("title") { it.getAttribute("type") == "sub" }
)
val translator = headerRoot.firstText("editor") { it.getAttribute("role") == "translator" }
@@ -5505,9 +5540,25 @@
}
composeKrillPubDate(year, month, day, plainPubDate)?.let { metadata["pubDate"] = it }
+ if (!metadata.containsKey("pubDate")) {
+ val dateEl = headerRoot.firstElement("date")
+ val dateVal = dateEl?.getAttribute("when")?.trim()?.takeIf { it.isNotEmpty() }
+ ?: dateEl?.textContent?.trim()?.takeIf { it.isNotEmpty() }
+ if (dateVal != null) {
+ metadata["pubDate"] = dateVal
+ }
+ }
+
headerRoot.firstElement("ref") { it.getAttribute("type") == "page_url" }
?.getAttribute("target")?.takeIf { it.isNotBlank() }?.let { metadata["externalLink"] = it }
+ if (!metadata.containsKey("externalLink")) {
+ headerRoot.firstElement("link") { it.hasAttribute("target") }
+ ?.getAttribute("target")?.trim()?.takeIf { it.isNotEmpty() }?.let {
+ metadata["externalLink"] = it
+ }
+ }
+
val biblNoteElement = analytic.firstElement("biblNote") { it.getAttribute("n") == "url" }
?: monogr.firstElement("biblNote") { it.getAttribute("n") == "url" }
biblNoteElement?.let {
diff --git a/app/src/test/kotlin/de/ids_mannheim/korapxmltools/KrillJsonGeneratorTest.kt b/app/src/test/kotlin/de/ids_mannheim/korapxmltools/KrillJsonGeneratorTest.kt
index b121a44..fb742fb 100644
--- a/app/src/test/kotlin/de/ids_mannheim/korapxmltools/KrillJsonGeneratorTest.kt
+++ b/app/src/test/kotlin/de/ids_mannheim/korapxmltools/KrillJsonGeneratorTest.kt
@@ -640,6 +640,118 @@
}
@Test
+ fun krillStandardTeiP5MetadataFallbacks() {
+ val tool = KorapXmlTool()
+
+ // 1. Check basic P5 typical structure from the example
+ val p5Metadata = collectKrillMetadata(
+ tool,
+ "SK_UL.19811",
+ headerElement(
+ """
+ <teiHeader>
+ <fileDesc>
+ <titleStmt>
+ <title>Affenstern</title>
+ <author role="primary">Udo Lindenberg</author>
+ <author role="text">Another Author</author>
+ </titleStmt>
+ <publicationStmt>
+ <publisher>Unbekannt</publisher>
+ <date>1981</date>
+ <ref>
+ <name>Udopia</name>
+ </ref>
+ </publicationStmt>
+ <sourceDesc>
+ <ab>
+ <link target="https://www.udo-lindenberg.de/affenstern.57680.htm" />
+ </ab>
+ </sourceDesc>
+ </fileDesc>
+ </teiHeader>
+ """
+ )
+ )
+
+ assertEquals("Udo Lindenberg", p5Metadata["author"], "Should prefer primary role author")
+ assertEquals("Affenstern", p5Metadata["title"])
+ assertEquals("1981", p5Metadata["pubDate"])
+ assertEquals("https://www.udo-lindenberg.de/affenstern.57680.htm", p5Metadata["externalLink"])
+
+ // 2. Check <date when="..."> fallback
+ val p5MetadataDateWhen = collectKrillMetadata(
+ KorapXmlTool(),
+ "SK_UL.19812",
+ headerElement(
+ """
+ <teiHeader>
+ <fileDesc>
+ <publicationStmt>
+ <date when="1982-03-04"/>
+ </publicationStmt>
+ </fileDesc>
+ </teiHeader>
+ """
+ )
+ )
+ assertEquals("1982-03-04", p5MetadataDateWhen["pubDate"])
+
+ // 3. Check author without role (first author)
+ val p5MetadataNoRole = collectKrillMetadata(
+ KorapXmlTool(),
+ "SK_UL.19813",
+ headerElement(
+ """
+ <teiHeader>
+ <fileDesc>
+ <titleStmt>
+ <author>First Author</author>
+ <author>Second Author</author>
+ </titleStmt>
+ </fileDesc>
+ </teiHeader>
+ """
+ )
+ )
+ assertEquals("First Author", p5MetadataNoRole["author"])
+ }
+
+ @Test
+ fun testSkZipExtraction() {
+ val skZip = loadResource("sk.zip").path
+
+ val generatedTar = ensureKrillTar("sk_test", "sk.krill.tar") { outputDir ->
+ arrayOf(
+ "-t", "krill",
+ "-q",
+ "-D", outputDir.path,
+ skZip
+ )
+ }
+ assertTrue(generatedTar.exists())
+
+ val jsonByFile = readKrillJson(generatedTar)
+ assertTrue(jsonByFile.containsKey("SK-UL-19811.json"))
+ val json = jsonByFile.getValue("SK-UL-19811.json")
+
+ // Assert our fallbacks were correctly populated in the output JSON
+ assertEquals("Udo Lindenberg", krillFieldValue(json, "author"))
+ assertEquals("Affenstern", krillFieldValue(json, "title"))
+ assertEquals("1981", krillFieldValue(json, "pubDate"))
+
+ // Assert docTitle, docAuthor, corpusTitle, and corpusAuthor are empty/null
+ kotlin.test.assertNull(krillFieldValue(json, "docTitle"))
+ kotlin.test.assertNull(krillFieldValue(json, "docAuthor"))
+ kotlin.test.assertNull(krillFieldValue(json, "corpusTitle"))
+ kotlin.test.assertNull(krillFieldValue(json, "corpusAuthor"))
+
+ // Check externalLink contains the encoded URL
+ assertTrue(json.contains("https%3A%2F%2Fwww.udo-lindenberg.de%2Faffenstern.57680.htm"),
+ "JSON should contain the encoded url in the externalLink field")
+ }
+
+ @Test
fun testCorrectTextCount() {
val baseZip = loadResource("wud24_sample.zip").path
diff --git a/app/src/test/resources/sk.zip b/app/src/test/resources/sk.zip
new file mode 100644
index 0000000..cd51faf
--- /dev/null
+++ b/app/src/test/resources/sk.zip
Binary files differ