Мне нужно разобрать локальный 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
читает ошибку, в которой говорится, что значение типа "Рецепт" не имеет элемента "счетчик". Однако он все равно ничего не печатал, потому что я еще не подключил локальный файл, это моя единственная проблема. Если бы мой локальный файл был ссылкой, все бы запустилось, но это не так.





добавьте print (rssItems.count) внутри parserDidEndDocument () перед обработчиком и напишите о результате