Я пытаюсь разобрать файл metadata.opf, который Caliber использует для управления электронными книгами с помощью Swift.
Мне удалось разобрать документ на игровой площадке:
import Foundation
class Metadata: CustomStringConvertible {
var uuid = ""
var title = ""
var creators = [""]
var serie = ""
var serieIndex = 0
var description: String { return
"UUID: \(uuid)\nTitre: \(title)\nAuteur(s): \(creators)\nSérie: Tome \(serieIndex) de la série \(serie)"
}
}
class OPFParser: NSObject {
var xmlParser: XMLParser?
var metadata: [Metadata] = []
var xmlText = ""
var currentMetadata: Metadata?
var calibreAttributes: [String: String] = [:]
var isUUID = false
init(withXML xml: String) {
if let data = xml.data(using: .utf8){
xmlParser = XMLParser(data: data)
}
}
func parse() -> [Metadata] {
xmlParser?.delegate = self
xmlParser?.parse()
return metadata
}
}
extension OPFParser: XMLParserDelegate {
func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
xmlText = ""
if elementName == "metadata" {
currentMetadata = Metadata()
}
if elementName == "meta" {
//print("\(attributeDict["content"]) : \(attributeDict["name"])")
if attributeDict["name"] == "calibre:series" {
if let serie = attributeDict["content"] {
currentMetadata?.serie = serie
}
}
if attributeDict["name"] == "calibre:series_index" {
if let serieIndex = attributeDict["content"] {
currentMetadata?.serieIndex = Int(serieIndex) ?? 0
}
}
}
if elementName == "dc:identifier" {
if let uuuid = attributeDict["opf:scheme"]{
if uuuid == "uuid" {
isUUID = true
} else {isUUID = false}
}
}
}
func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
switch elementName {
case "dc:identifier":
if isUUID == true {
currentMetadata?.uuid = xmlText.trimmingCharacters(in: .whitespacesAndNewlines)
}
case "dc:title":
currentMetadata?.title = xmlText.trimmingCharacters(in: .whitespacesAndNewlines)
case "dc:creator":
currentMetadata?.creators.append(xmlText.trimmingCharacters(in: .whitespacesAndNewlines))
case "metadata":
if let meta = currentMetadata {
metadata.append(meta)
}
default:
break
}
}
func parser(_ parser: XMLParser, foundCharacters string: String) {
xmlText += string
}
}
class TestMetadata {
func metadataDisplay() {
if let xmlUrl = Bundle.main.url(forResource: "metadata1", withExtension: "opf") {
let xml = try! String(contentsOf: xmlUrl)
let opfParser = OPFParser(withXML: xml)
let bandeDessinees = opfParser.parse()
for bandeDessinee in bandeDessinees {
bandeDessinee.creators = bandeDessinee.creators.filter({ $0 != ""})
print(bandeDessinee)
}
} else {print("fichier non trouvé")}
}
}
let testMetadata = TestMetadata()
testMetadata.metadataDisplay()
Функция metadataDisplay работает и печатает отформатированные метаданные. К сожалению, при переключении на мой проект metadataDisplay ничего не печатает. Массив bandedessinees
пуст. Я использую тот же код, за исключением того, что вызываю metadataDisplay с помощью кнопки в файле swiftUI. Я несколько раз пытался реорганизовать код, изменяя класс init () function of my
OPFParser, но, к сожалению, не могу понять, почему мои метаданные не выводятся на консоль.
Спасибо за вашу помощь, Айман.
Пример файла metadata.opf:
<?xml version='1.0' encoding='utf-8'?>
<package xmlns="http://www.idpf.org/2007/opf" unique-identifier="uuid_id" version="2.0">
<metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf">
<dc:identifier opf:scheme="calibre" id="calibre_id">143</dc:identifier>
<dc:identifier opf:scheme="uuid" id="uuid_id">03badde9-0932-41ab-bd31-2dbba989a7f5</dc:identifier>
<dc:title>Tome 1</dc:title>
<dc:creator opf:file-as="Debeurme, Ludovic" opf:role="aut">Ludovic Debeurme</dc:creator>
<dc:contributor opf:file-as="calibre" opf:role="bkp">calibre (4.15.0) [https://calibre-ebook.com]</dc:contributor>
<dc:date>2018-05-20T16:16:27+00:00</dc:date>
<dc:language>en</dc:language>
<meta content="{"Ludovic Debeurme": ""}" name="calibre:author_link_map"/>
<meta content="Epiphania" name="calibre:series"/>
<meta content="1" name="calibre:series_index"/>
<meta content="2020-05-16T13:01:05.580464+00:00" name="calibre:timestamp"/>
<meta content="Tome 1" name="calibre:title_sort"/>
<meta name="calibre:user_metadata:#shelves" content="{"table": "custom_column_1", "is_editable": true, "is_custom": true, "rec_index": 22, "is_category": true, "is_multiple2": {"ui_to_list": ",", "list_to_ui": ", ", "cache_to_list": "|"}, "name": "Shelves", "is_multiple": "|", "is_csp": false, "category_sort": "value", "#extra#": null, "kind": "field", "#value#": [], "display": {"is_names": false, "description": ""}, "search_terms": ["#shelves"], "datatype": "text", "colnum": 1, "label": "shelves", "link_column": "value", "column": "value"}"/>
</metadata>
<guide>
<reference href="cover.jpg" title="Cover" type="cover"/>
</guide>
</package>