0

I have data in an XML file of some 2500 lines where I want to extract/parse only a small section into a swiftui view. An example of the data I need is below. It exists on my local bundle as file test.xml:

...other data before...

<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>

...other data after...

I would like an output into a swiftui view that takes the strings inside each memorandum and displays them like this:

ABC - ABC TEXT - 00:02:00

DEF - DEF TEXT - 00:05:00

GHI - GHI TEXT - 00:10:00

There are multiple XML files from the system I am using with a varying number of memos, so I need something that is able to be flexible and perhaps loop? through the memos and parse into swift.

I'm a complete rookie and have built some basic navigation views for my project, but this data part is beyond my knowledge and I've searched the internet far and wide for a solution with no avail! Any suggestions would be greatly appreciated. Thanks!

Joakim Danielson
  • 43,251
  • 5
  • 22
  • 52
kostodian
  • 1
  • 2

1 Answers1

0

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>