import Foundation class MoebooruPostXMLParser: NSObject, XMLParserDelegate { private var posts: [MoebooruPost] = [] private var currentPost: MoebooruPost? private var parser: XMLParser init(data: Data) { parser = XMLParser(data: data) super.init() parser.delegate = self } func parse() -> [MoebooruPost] { parser.parse() return posts } func parser(_: XMLParser, didStartElement elementName: String, namespaceURI _: String?, qualifiedName _: String?, attributes attributeDict: [String: String] = [:]) { if elementName == "post" { guard let id = attributeDict["id"], let tags = attributeDict["tags"], let createdAtStr = attributeDict["created_at"], let createdAt = Int(createdAtStr), let updatedAtStr = attributeDict["updated_at"], let updatedAt = Int(updatedAtStr), let creatorId = attributeDict["creator_id"], let approverId = attributeDict["approver_id"], let author = attributeDict["author"], let change = attributeDict["change"], let source = attributeDict["source"], let score = attributeDict["score"], let md5 = attributeDict["md5"], let fileSizeStr = attributeDict["file_size"], let fileSize = Int(fileSizeStr), let fileExt = attributeDict["file_ext"], let fileUrl = attributeDict["file_url"], let isShownStr = attributeDict["is_shown_in_index"], let previewUrl = attributeDict["preview_url"], let previewWidthStr = attributeDict["preview_width"], let previewWidth = Int(previewWidthStr), let previewHeightStr = attributeDict["preview_height"], let previewHeight = Int(previewHeightStr), let actualPreviewWidthStr = attributeDict["actual_preview_width"], let actualPreviewWidth = Int(actualPreviewWidthStr), let actualPreviewHeightStr = attributeDict["actual_preview_height"], let actualPreviewHeight = Int(actualPreviewHeightStr), let sampleUrl = attributeDict["sample_url"], let sampleWidthStr = attributeDict["sample_width"], let sampleWidth = Int(sampleWidthStr), let sampleHeightStr = attributeDict["sample_height"], let sampleHeight = Int(sampleHeightStr), let sampleFileSizeStr = attributeDict["sample_file_size"], let sampleFileSize = Int(sampleFileSizeStr), let jpegUrl = attributeDict["jpeg_url"], let jpegWidthStr = attributeDict["jpeg_width"], let jpegWidth = Int(jpegWidthStr), let jpegHeightStr = attributeDict["jpeg_height"], let jpegHeight = Int(jpegHeightStr), let jpegFileSizeStr = attributeDict["jpeg_file_size"], let jpegFileSize = Int(jpegFileSizeStr), let rating = attributeDict["rating"], let isRatingLockedStr = attributeDict["is_rating_locked"], let hasChildrenStr = attributeDict["has_children"], let parentId = attributeDict["parent_id"], let status = attributeDict["status"], let isPendingStr = attributeDict["is_pending"], let widthStr = attributeDict["width"], let width = Int(widthStr), let heightStr = attributeDict["height"], let height = Int(heightStr), let isHeldStr = attributeDict["is_held"], let framesPendingString = attributeDict["frames_pending_string"], let framesString = attributeDict["frames_string"], let isNoteLockedStr = attributeDict["is_note_locked"], let lastNotedAtStr = attributeDict["last_noted_at"], let lastNotedAt = Int(lastNotedAtStr), let lastCommentedAtStr = attributeDict["last_commented_at"], let lastCommentedAt = Int(lastCommentedAtStr) else { return } currentPost = MoebooruPost( id: id, tags: tags.components(separatedBy: " "), createdAt: createdAt, updatedAt: updatedAt, creatorID: creatorId, approverID: approverId, author: author, change: change, source: source, score: score, md5: md5, fileSize: fileSize, fileExtension: fileExt, fileURL: URL(string: fileUrl)!, isShownInIndex: isShownStr == "true", previewURL: URL(string: previewUrl)!, previewWidth: previewWidth, previewHeight: previewHeight, actualPreviewWidth: actualPreviewWidth, actualPreviewHeight: actualPreviewHeight, sampleURL: URL(string: sampleUrl)!, sampleWidth: sampleWidth, sampleHeight: sampleHeight, sampleFileSize: sampleFileSize, jpegURL: URL(string: jpegUrl)!, jpegWidth: jpegWidth, jpegHeight: jpegHeight, jpegFileSize: jpegFileSize, rating: rating, isRatingLocked: isRatingLockedStr == "true", hasChildren: hasChildrenStr == "true", parentId: parentId, status: status, isPending: isPendingStr == "true", width: width, height: height, isHeld: isHeldStr == "true", framesPendingString: framesPendingString, framesString: framesString, isNoteLocked: isNoteLockedStr == "true", lastNotedAt: lastNotedAt, lastCommentedAt: lastCommentedAt ) } } func parser(_: XMLParser, didEndElement elementName: String, namespaceURI _: String?, qualifiedName _: String?) { if elementName == "post", let post = currentPost { posts.append(post) currentPost = nil } } #if DEBUG func parser(_: XMLParser, parseErrorOccurred parseError: any Error) { print(parseError) } #endif }