Please read the last thread: Parse XML in SwiftUI - https://developer.apple.com/forums/thread/670984
I've got the code to parse articles from XML courtesy of OOPer...but I need to actually execute it in ArticlesView. How would I call ArticlesParser into ArticlesView and related views and run the parser onto an XML file (THS.xml)?
Here's ArticleInfo.swift and ArticlesView.
ArticleInfo.swift:
//
// ArticleInfo.swift
// Hair Society Go
//
// Created by Joshua Srery on 1/13/21.
// Code provided by OOPer on Apple Developer Forums
//
import Foundation
struct Article {
var title: String = ""
var date: Date?
var author: String?
var img: URL?
/// content in HTML
var content: String = ""
}
class ArticlesParser: XMLParser {
// Public property to hold the result
var articles: [Article] = []
var dateTimeZone = TimeZone(abbreviation: "GMT-6")
lazy var dateFormater: DateFormatter = {
let df = DateFormatter()
//Please set up this DateFormatter for the entry `date`
df.locale = Locale(identifier: "en_US_POSIX")
df.dateFormat = "MMM dd, yyyy"
df.timeZone = dateTimeZone
return df
}()
private var textBuffer: String = ""
private var nextArticle: Article? = nil
override init(data: Data) {
super.init(data: data)
self.delegate = self
}
}
extension ArticlesParser: 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 "posts":
nextArticle = Article()
case "title":
textBuffer = ""
case "date":
textBuffer = ""
case "author":
textBuffer = ""
case "img":
textBuffer = ""
case "content":
textBuffer = ""
default:
print("Ignoring \(elementName)")
break
}
}
// Called when closing tag (`</elementName>`) is found
func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
switch elementName {
case "posts":
if let article = nextArticle {
articles.append(article)
}
case "title":
nextArticle?.title = textBuffer
case "date":
print("date: \(textBuffer)")
nextArticle?.date = dateFormater.date(from: textBuffer)
case "author":
nextArticle?.author = textBuffer
case "img":
print("img: \(textBuffer)")
nextArticle?.img = URL(string: textBuffer)
case "content":
nextArticle?.content = textBuffer
default:
print("Ignoring \(elementName)")
break
}
}
// Called when a character sequence is found
// This may be called multiple times in a single element
func parser(_ parser: XMLParser, foundCharacters string: String) {
textBuffer += string
}
// Called when a CDATA block is found
func parser(_ parser: XMLParser, foundCDATA CDATABlock: Data) {
guard let string = String(data: CDATABlock, encoding: .utf8) else {
print("CDATA contains non-textual data, ignored")
return
}
textBuffer += string
}
// For debugging
func parser(_ parser: XMLParser, parseErrorOccurred parseError: Error) {
print(parseError)
print("on:", parser.lineNumber, "at:", parser.columnNumber)
}
}
ArticlesView:
//
// ArticlesView.swift
// Hair Society Go
//
// Created by Joshua Srery on 11/29/20.
//
import SwiftUI
struct ArticlesView: View {
var body: some View {
NavigationView {
List {
ForEach(0 ..< 5) { item in
NavigationLink(destination: ArticleView(title: "Replace with Title var", image: "Replace with Img var", content: "Replace with Content var", author: "Replace with Author var", date: "Replace with Date var")) {
ArticleRow(image: "Replace with Img var", title: "Replace with Title var", author: "Replace with Author var", date: "Replace with Date var")
}
}
}
.navigationTitle("Articles")
.toolbar(content: {
Menu {
Button("Date", action: {})
Button("Title", action: {})
Button("Customize…", action: {})
} label: {
Label("Filter", systemImage: "line.horizontal.3.decrease.circle")
}
})
// Ignore the filter Menu for right now
}
}
}
struct ArticleRow: View {
let image: String
let title: String
let author: String
let date: String
var body: some View {
HStack {
Image(image)
.resizable()
.frame(minWidth: 75, maxWidth: 100, maxHeight: 75)
.cornerRadius(12)
VStack(alignment: .leading, content: {
Text(title)
.font(.headline)
Text("\(author) • \(date)")
.font(.subheadline)
})
}
}
}