如何将本地XML文件中的备忘录数据解析到SwiftUI视图中
解决方案
1. 定义备忘录数据模型
先创建一个适配SwiftUI列表的结构体,存储单个备忘录的属性:
struct Memorandum: Identifiable { let id = UUID() // SwiftUI列表所需的唯一标识 let identification: String let text: String let time: String }
2. 编写XML解析器类
实现一个可被SwiftUI观察的解析器,用系统XMLParser处理XML解析逻辑,自动收集所有备忘录数据:
import Foundation import Combine class XMLParserManager: ObservableObject { @Published var memorandums: [Memorandum] = [] @Published var errorMessage: String? private var currentIdentification = "" private var currentText = "" private var currentTime = "" func parseXML(from fileName: String) { guard let filePath = Bundle.main.path(forResource: fileName, ofType: "xml") else { errorMessage = "找不到指定的XML文件" return } let fileURL = URL(fileURLWithPath: filePath) let parser = XMLParser(contentsOf: fileURL) parser?.delegate = self parser?.parse() } } extension XMLParserManager: XMLParserDelegate { func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) { // 遇到<memorandum>节点时提取属性值 if elementName == "memorandum" { currentIdentification = attributeDict["identification"] ?? "" currentText = attributeDict["text"] ?? "" currentTime = attributeDict["time"] ?? "" } } func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { // 结束<memorandum>节点时,将数据存入数组 if elementName == "memorandum" { let memo = Memorandum( identification: currentIdentification, text: currentText, time: currentTime ) memorandums.append(memo) // 重置临时变量 currentIdentification = "" currentText = "" currentTime = "" } } func parser(_ parser: XMLParser, parseErrorOccurred parseError: Error) { errorMessage = "解析错误:\(parseError.localizedDescription)" } }
3. SwiftUI视图实现
构建展示列表的视图,自动触发解析并展示结果,同时处理错误提示:
import SwiftUI struct MemorandumListView: View { @StateObject private var parserManager = XMLParserManager() var body: some View { NavigationStack { // iOS 16+使用,iOS 15及以下替换为NavigationView List(parserManager.memorandums) { memo in Text("\(memo.identification) - \(memo.text) - \(memo.time)") .padding(.vertical, 8) } .navigationTitle("备忘录列表") .onAppear { // 加载解析指定XML文件,可替换为其他文件名 parserManager.parseXML(from: "test") } .alert(item: $parserManager.errorMessage) { message in Alert(title: Text("错误"), message: Text(message), dismissButton: .default(Text("确定"))) } } } } // 让String适配Alert的Identifiable要求 extension String: Identifiable { public var id: String { self } } struct MemorandumListView_Previews: PreviewProvider { static var previews: some View { MemorandumListView() } }
4. 灵活扩展说明
- 解析多文件:只需重复调用
parserManager.parseXML(from: "文件名"),若需保留多文件数据,可修改解析器去掉数组清空逻辑,或新增分组存储结构。 - 适配XML结构变更:修改
XMLParserDelegate中的元素名、属性名即可,无需改动视图层。 - 大文件性能优化:将解析逻辑移至后台队列,避免阻塞UI,修改
parseXML方法:
func parseXML(from fileName: String) { DispatchQueue.global(qos: .background).async { guard let filePath = Bundle.main.path(forResource: fileName, ofType: "xml") else { DispatchQueue.main.async { errorMessage = "找不到指定的XML文件" } return } let fileURL = URL(fileURLWithPath: filePath) let parser = XMLParser(contentsOf: fileURL) parser?.delegate = self let success = parser?.parse() ?? false DispatchQueue.main.async { if !success { errorMessage = "解析失败" } } } }
内容的提问来源于stack exchange,提问作者kostodian
相关产品推荐
相关产品推荐

