37.%d Xcode — RSS 裡的 XML
目錄
⦿ HTML、XML
⦿ RSS
⦿ xmlParser
⦿ Xcode
HTML、XML
大家都知道寫網頁用的 HTML,它是一種標籤式的語言,用來註記分行段落的內容,是一個骨幹,把內容放進去後才會成為網頁內容,而 XML 也是用來做同樣的事情,不過前者是用來編排網頁架構,後者更多是為了資料的交換、傳輸。
不久之前因為案子將送調光,需要 xml
檔,夥伴發現 Premiere 轉眼就輸出便問是否尋常,我們大概都被轉檔時間嚇過,過長或過短的輸出時間,創作者都會心慌。
而 xml
其實就是專案檔裡的一些資訊,用以標註物件
的位置、形貌等,可以想像它是記錄畫框大小、xy 軸位置,或是段落、色彩資訊,所以這樣的檔案大小就不會太大,更不會因為渲染
耗時。
當然,上頭是以剪接軟體來說,因為 xml 能夠應用在許多地方,就如各大網站提供 API 的原貌是 json
,或是 m3u8
檔案的串流分段標註一樣,xml 也是一堆資料的標註,端看怎麼使用它。
xml 的結構蠻單純的,會令我想起二十多年前就玩過的 html 跑馬燈:
<marquee>跑動的物件</marquee>
所以我們可以簡單歸類成,html 用來寫網頁
,xml 用來做資料彙整
。
繼續閱讀|回目錄
RSS
講到 xml
就得提到從 web2.0
起步,直到現在不知是否消失了的 RSS,如前述的 API,網站常提供 RSS,API 是用來連接伺服器的資源,以取得想要的特定資料,而 RSS 是訂閱內容,以篩選出想要特定內容。
雖然人們常把演算法掛在嘴邊,但其實我們不懂 bubble sort,若不想被演算法綁架,沒關係!我們還有RSS。
使用 RSS reader 訂閱專屬自己的內容(這句太像廣告
),以免被網站、APP 等有的沒的廣告資訊綁架,不確定在資訊過載的年代,為了過濾資訊,能不能再起 RSS 的榮光。
繼續閱讀|回目錄
xmlParser
在 Xcode 中,若要練習解析 xml 格式的檔案,首先,我們透過下面兩個網站的 xml 樣貌,可以理解訂閱 RSS 後能夠看到什麼樣的資訊,一個是 PTT
,一個是自由時報的電子報
。
Xcode
這篇除了 tableView 自適應高度,多數是照影片練習操作,首先,我們需要一個 parser class,如下:
class FeedParser: NSObject, XMLParserDelegate {
private var rssItems = [RSSItem]()
private var currentElement = ""
}
NSObject 可以這樣理解,如果你實作過 viewModel,想透過 viewModel 做到一些 tableViewCell 的操作,如 dataSource
、delegate
,由於自己寫的 viewModel 不是 CocoaTouchClass,那必須要先繼承 NSObject,我們才可以透過 Delegation
去編寫裡面的程式。
在這邊就是 conform XMLParserDelegate,而 rssItems 是用來接解析出來的 data 的 property。
然後在這個 class 裡需要一個基礎的 func,如下:
func parseFeed(url: String,
completionHandler: ( ([RSSItem]) -> Void)? ) { self.parserCompletionHandler = completionHandler guard let urlStr = URL(string: url) else { return } URLSession.shared.dataTask(with: urlStr) { (data, _, error) in
guard let data = data else {
if let error = error {
print(error.localizedDescription)
}
return
}
let parser = XMLParser(data: data)
parser.delegate = self
parser.parse()
}.resume()
}
也就是透過 URLSession 去接網路溝通回來的 data,再使用 XMLParser 去解析,而使用 completionHandler 的意思是,使用這個 func 在接回來的資料並解析完,我們最終可以得到 RSSItems 這樣的資料。
最後,在 VC 寫一個 fecthData 的函式,並放在 viewDidLoad 呼叫。
private func fetchData() {
let feedParser = FeedParser()
feedParser.parseFeed(url: "https://news.ltn.com.tw/rss/business.xml") { rssItems in
self.rssItems = rssItems
OperationQueue.main.addOperation {
self.myTableView.reloadData()
}
}
創建實例後將 url 代入,便可以將解析得到的 rssItems,同時,我們在閉包內更新 tableView 的 data。
再來看看 parserDelegate 中的主要三個
func:
func parser(_ parser: XMLParser,
didStartElement elementName: String,
namespaceURI: String?,
qualifiedName qName: String?,
attributes attributeDict: [String : String] = [:]) {
}func parser(_ parser: XMLParser,
foundCharacters string: String) {
}func parser(_ parser: XMLParser,
didEndElement elementName: String,
namespaceURI: String?,
qualifiedName qName: String?) {
}
開始時,透過 elementName 去比對
找到 elementName 下一層的 elementName 的 string,最後賦值
給用來接的 property,而 rssItem 如下:
struct RSSItem {
let title: String
let pubDate: String
let description: String
}
在自由時報的電子報的 RSSItem 裡,需有三個 String 的屬性,分別是 title
、pubDate
、description
,即是標題、發佈時間、描述。
當你得到第一個資料,即第一個 rssItem,於是用 rssItems append
,每當 append 一次,它會從頭開始比對,所以用來接值的 Object Model 需淨空再重新 += string
,見 RSS xml 結構如下:
即 item 下,有 title
、description
、pubDate
,所以上述三個 function 裡分別放入如下:
currentElement = elementName
if currentElement == "item" {
currentTitle = ""
currentPubDate = ""
currentDescription = ""
}switch currentElement {
case "title": currentTitle += string
case "pubDate": currentPubDate += string
case "description": currentDescription += string
default: break
}if elementName == "item" {
let rssItem = RSSItem(title: currentTitle,
pubDate: currentPubDate,
description: currentDescription)
self.rssItems.append(rssItem)
}
最後成果
繼續閱讀|回目錄
Reference:
並附上