我需要解析本地XML文件。我想我拥有显示代码所需的一切,问题是它的实际解析。我有一个先前项目的代码,它解析了一个xml文件的链接,但是这是一个名为" Recipes.xml"
的本地文件需要转移的是parseFeed()
功能,我已经尝试了几种方法将其解析为本地文件,但仍未找到解决方案。
XMLParser类:
struct Recipe {
let title: String
let calories: String
let ingredients: String
}
class FeedParser: NSObject, XMLParserDelegate {
private var rssItems: [Recipe] = []
private var currentElement = ""
private var currentTitle: String = "" {
didSet {
currentTitle =
currentTitle.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
}
}
private var currentCalories: String = "" {
didSet {
currentCalories =
currentCalories.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
}
}
private var currentIngredients: String = "" {
didSet {
currentIngredients =
currentIngredients.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
}
}
private var parserCompletionHandler: (([Recipe]) -> Void)?
func parseFeed(url: String, completionHandler: (([Recipe]) -> Void)?) {
self.parserCompletionHandler = completionHandler
let request = URLRequest(url: URL(string: url)!)
let urlSession = URLSession.shared
let task = urlSession.dataTask(with: request) { (data, response, error) in
guard let data = data else {
if let error = error {
print (error.localizedDescription)
}
return
}
/// Parse our xml data
let parser = XMLParser(data: data)
parser.delegate = self
parser.parse()
}
task.resume()
}
// MARK: - XML Parser Delegate
func parser(_ parser: XMLParser, didStartElement elementName: String,
namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict:
[String : String] = [:]) {
currentElement = elementName
if currentElement == "dish" {
currentTitle = ""
currentCalories = ""
currentIngredients = ""
}
}
func parser(_ parser: XMLParser, foundCharacters string: String) {
switch currentElement {
case "title": currentTitle += string
case "calories": currentCalories += string
case "ingredients": currentIngredients += string
default: break
}
}
func parser(_ parser: XMLParser, didEndElement elementName: String,
namespaceURI: String?, qualifiedName qName: String?) {
if elementName == "item" {
let rssItem = Recipe(title: currentTitle,
calories: currentCalories, ingredients: currentIngredients)
self.rssItems.append(rssItem)
print(rssItem)
}
}
func parserDidEndDocument(_ parser: XMLParser) {
parserCompletionHandler?(rssItems)
}
func parser(_ parser: XMLParser, parseErrorOccurred parseError: Error) {
print(parseError.localizedDescription)
}
}
这是接收并显示xml文件的表视图。这里,fetchData()
函数调用parseFeed()
函数来返回xml数据。 " Recipes.xml" fetchData()
中的字符串将是一个链接。我知道用本地文件名替换它不会起作用,它只是一个占位符。
RecipeTableViewController:
class RecipeTableViewController: UITableViewController, XMLParserDelegate {
@IBOutlet var myTableView: UITableView!
private var recipeItems: [Recipe]?
override func viewDidLoad() {
super.viewDidLoad()
myTableView.dataSource = self
myTableView.delegate = self
fetchData()
/* if let path = Bundle.main.url(forResource: "Recipes", withExtension: "xml") {
if let parser = XMLParser(contentsOf: path) {
parser.delegate = self
parser.parse()
}
} */
}
private func fetchData() {
let feedParser = FeedParser()
feedParser.parseFeed(url:
"Recipes.xml") { (recipeItems) in
self.recipeItems = recipeItems
OperationQueue.main.addOperation {
self.tableView.reloadSections(IndexSet(integer: 0), with: .left)
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// Table View Delegates
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
guard let recipeItems = recipeItems else {
return 0
}
print(recipeItems.count)
return recipeItems.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! RecipeTableViewCell
if let item = recipeItems?[indexPath.item] {
cell.item = item
}
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let Storyboard = UIStoryboard(name: "Main", bundle: nil)
let resultsVC = Storyboard.instantiateViewController(withIdentifier: "ResultsViewController") as! ResultsViewController
// Information to be passed to ResultsViewController
resultsVC.getTitle = recipeItems![indexPath.row].title
resultsVC.getIngredients = recipeItems![indexPath.row].ingredients
// Push to next view
self.navigationController?.pushViewController(resultsVC, animated: true)
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
}
来自print(recipeItems.count)
的结果返回0