diff --git a/readium/streamer/src/main/java/org/readium/r2/streamer/parser/epub/MetadataParser.kt b/readium/streamer/src/main/java/org/readium/r2/streamer/parser/epub/MetadataParser.kt index d85fbb9bc2..dd00ed2680 100644 --- a/readium/streamer/src/main/java/org/readium/r2/streamer/parser/epub/MetadataParser.kt +++ b/readium/streamer/src/main/java/org/readium/r2/streamer/parser/epub/MetadataParser.kt @@ -23,18 +23,50 @@ internal class MetadataParser( return resolveItemsHierarchy(items) } - private fun parseElements(metadataElement: ElementNode, filePath: Url): List = - metadataElement.getAll().mapNotNull { e -> - when { - e.namespace == Namespaces.DC -> - parseDcElement(e) - e.namespace == Namespaces.OPF && e.name == "meta" -> - parseMetaElement(e) - e.namespace == Namespaces.OPF && e.name == "link" -> - parseLinkElement(e, filePath) - else -> null + private fun parseElements(metadataElement: ElementNode, filePath: Url): List { + val oldMetas: MutableList = mutableListOf() + val newMetas: MutableList = mutableListOf() + val links: MutableList = mutableListOf() + val dcItems: MutableList = mutableListOf() + + metadataElement + .getAll() + .forEach { e -> + when { + e.namespace == Namespaces.DC -> { + dcItems.add(e) + } + e.namespace == Namespaces.OPF && e.name == "meta" -> { + if (e.getAttr("property") == null) { + oldMetas.add(e) + } else { + newMetas.add(e) + } + } + e.namespace == Namespaces.OPF && e.name == "link" -> { + links.add(e) + } + else -> {} + } } - } + + val parsedNewMetas = newMetas + .mapNotNull { parseNewMetaElement(it) } + + val propertiesFromGlobalNewMetas = parsedNewMetas + .filter { it.refines == null } + .map { it.property } + .toSet() + + val parsedOldMetas = oldMetas + .mapNotNull { parseOldMetaElement(it) } + // Ignore EPUB2 fallbacks in EPUB3 + .filter { it.property !in propertiesFromGlobalNewMetas } + + return parsedNewMetas + parsedOldMetas + + dcItems.mapNotNull { parseDcElement(it) } + + links.mapNotNull { parseLinkElement(it, filePath) } + } private fun parseLinkElement(element: ElementNode, filePath: Url): MetadataItem.Link? { val href = element.getAttr("href")?.let { Url.fromEpubHref(it) } ?: return null @@ -60,43 +92,43 @@ internal class MetadataParser( ) } - private fun parseMetaElement(element: ElementNode): MetadataItem.Meta? { - return if (element.getAttr("property") == null) { - val name = element.getAttr("name")?.trim()?.ifEmpty { null } - ?: return null - val content = element.getAttr("content")?.trim()?.ifEmpty { null } - ?: return null - val resolvedName = resolveProperty(name, prefixMap) - MetadataItem.Meta( - id = element.id, - refines = null, - property = resolvedName, - value = content, - lang = element.lang - ) - } else { - val propName = element.getAttr("property")?.trim()?.ifEmpty { null } - ?: return null - val propValue = element.text?.trim()?.ifEmpty { null } - ?: return null - val resolvedProp = resolveProperty(propName, prefixMap, DEFAULT_VOCAB.META) - val resolvedScheme = - element.getAttr("scheme")?.trim()?.ifEmpty { null }?.let { - resolveProperty( - it, - prefixMap - ) - } - val refines = element.getAttr("refines")?.removePrefix("#") - MetadataItem.Meta( - id = element.id, - refines = refines, - property = resolvedProp, - value = propValue, - lang = element.lang, - scheme = resolvedScheme - ) - } + private fun parseNewMetaElement(element: ElementNode): MetadataItem.Meta? { + val propName = element.getAttr("property")?.trim()?.ifEmpty { null } + ?: return null + val propValue = element.text?.trim()?.ifEmpty { null } + ?: return null + val resolvedProp = resolveProperty(propName, prefixMap, DEFAULT_VOCAB.META) + val resolvedScheme = + element.getAttr("scheme")?.trim()?.ifEmpty { null }?.let { + resolveProperty( + it, + prefixMap + ) + } + val refines = element.getAttr("refines")?.removePrefix("#") + return MetadataItem.Meta( + id = element.id, + refines = refines, + property = resolvedProp, + value = propValue, + lang = element.lang, + scheme = resolvedScheme + ) + } + + private fun parseOldMetaElement(element: ElementNode): MetadataItem.Meta? { + val name = element.getAttr("name")?.trim()?.ifEmpty { null } + ?: return null + val content = element.getAttr("content")?.trim()?.ifEmpty { null } + ?: return null + val resolvedName = resolveProperty(name, prefixMap) + return MetadataItem.Meta( + id = element.id, + refines = null, + property = resolvedName, + value = content, + lang = element.lang + ) } private fun parseDcElement(element: ElementNode): MetadataItem.Meta? { diff --git a/readium/streamer/src/test/java/org/readium/r2/streamer/parser/epub/MetadataTest.kt b/readium/streamer/src/test/java/org/readium/r2/streamer/parser/epub/MetadataTest.kt index eae4288dcd..c3729a4fb6 100644 --- a/readium/streamer/src/test/java/org/readium/r2/streamer/parser/epub/MetadataTest.kt +++ b/readium/streamer/src/test/java/org/readium/r2/streamer/parser/epub/MetadataTest.kt @@ -362,9 +362,8 @@ class MetadataMiscTest { entry( Vocabularies.DCTERMS + "source", listOf( - "Feedbooks", mapOf("@value" to "Web", "http://my.url/#scheme" to "http"), - "Internet" + "Feedbooks" ) ), entry(