I had a quick try, as I never done XML with Swift before.
This is the code that worked for me, reading my test.xml
file,
decoding into an array of memos: [Memo]
, and displaying in a List(memos)
. Hope it helps.
import Foundation
import SwiftUI
struct Memo: Identifiable {
let id = UUID()
var identification: String
var pilot: String
var text: String
var time: String
}
struct ContentView: View {
@State var memos: [Memo] = []
var body: some View {
VStack {
List(memos) { memo in
HStack {
Text(memo.identification).foregroundColor(.red)
Text(memo.text).foregroundColor(.blue)
Text(memo.pilot).foregroundColor(.green)
Text(memo.time)
}
}
}
.onAppear {
if let url = Bundle.main.url(forResource: "test", withExtension: "xml") {
do {
let data = try Data(contentsOf: url)
let parser = MemoParser(data: data)
if parser.parse() {
memos = parser.memos
} else {
print("\n---> parser error: \(parser.parserError as Optional)")
}
} catch {
print("\n---> data error: \(error)")
}
}
}
}
}
class MemoParser: XMLParser {
var memos: [Memo] = []
override init(data: Data) {
super.init(data: data)
self.delegate = self
}
}
extension MemoParser: XMLParserDelegate {
// Called when opening tag (`<elementName>`) is found
func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
switch elementName {
case "memorandum":
let memo = Memo(
identification: attributeDict["identification"] ?? "",
pilot: attributeDict["pilot"] ?? "",
text: attributeDict["text"] ?? "",
time: attributeDict["time"] ?? "")
memos.append(memo)
default: break
}
}
// Called when closing tag (`</elementName>`) is found
func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
//...
}
// Called when a character sequence is found
func parser(_ parser: XMLParser, foundCharacters string: String) {
//...
}
// Called when a CDATA block is found
func parser(_ parser: XMLParser, foundCDATA CDATABlock: Data) {
guard String(data: CDATABlock, encoding: .utf8) != nil else {
print("CDATA contains non-textual data, ignored")
return
}
}
}
The test.xml
file
<?xml version="1.0" encoding="utf-8"?>
<memorandums>
<memorandum identification="ABC" pilot="2" text="ABC TEXT" time="00:02:00"/>
<memorandum identification="DEF" pilot="1" text="DEF TEXT" time="00:05:00"/>
<memorandum identification="GHI" pilot="1" text="GHI TEXT" time="00:10:00"/>
</memorandums>