Swift开发:如何展示XML文件中解析得到的数组?
XML解析后展示数组的实现方案
嘿,刚好之前我也处理过类似的Swift解析XML后展示数组的需求,给你分享下具体的实现思路和代码示例,应该能帮到你~
首先,咱们得确保解析后的数据模型是正确的,把XML里的数组字段(比如<ingredients>下的<item>、<description>下的<step>)对应成Swift里的数组类型。比如定义这样的结构体:
struct Dish { var type: String var title: String var duration: String var calories: String var ingredients: [String] // 对应食材数组 var imageURL: String var steps: [String] // 对应步骤数组 }
一、用UIKit展示数组(UITableView示例)
如果是用UIKit开发,最常用的就是用UITableView来展示列表型的数组,比如把食材和步骤分成两个分区来展示:
class DishDetailViewController: UIViewController, UITableViewDataSource { // 假设这里已经通过XML解析得到了Dish实例 let dish: Dish private let tableView = UITableView() init(dish: Dish) { self.dish = dish super.init(nibName: nil, bundle: nil) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func viewDidLoad() { super.viewDidLoad() setupTableView() title = dish.title } private func setupTableView() { tableView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(tableView) // 设置约束,让tableView铺满整个视图 NSLayoutConstraint.activate([ tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor), tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor), tableView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor) ]) tableView.dataSource = self // 注册单元格 tableView.register(UITableViewCell.self, forCellReuseIdentifier: "DishCell") } // 设置分区数:食材和步骤两个分区 func numberOfSections(in tableView: UITableView) -> Int { return 2 } // 设置分区标题 func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { return section == 0 ? "食材列表" : "制作步骤" } // 每个分区的行数对应数组的元素数量 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return section == 0 ? dish.ingredients.count : dish.steps.count } // 配置单元格内容 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "DishCell", for: indexPath) let contentText: String if indexPath.section == 0 { contentText = "- \(dish.ingredients[indexPath.row])" } else { contentText = "\(indexPath.row + 1). \(dish.steps[indexPath.row])" } cell.textLabel?.text = contentText return cell } }
二、用SwiftUI展示数组(更简洁)
如果是用SwiftUI开发,那就更简单了,直接用ForEach遍历数组即可,配合VStack或者List来展示:
struct DishDetailView: View { let dish: Dish // 解析后的Dish实例 var body: some View { ScrollView { VStack(alignment: .leading, spacing: 18) { // 展示基础信息 Text(dish.title) .font(.largeTitle) .bold() HStack { Text("类型: \(dish.type)") Spacer() Text("耗时: \(dish.duration)") Spacer() Text("热量: \(dish.calories)") } .font(.subheadline) // 展示食材数组 VStack(alignment: .leading, spacing: 8) { Text("食材列表") .font(.headline) ForEach(dish.ingredients, id: \.self) { ingredient in Text("- \(ingredient)") } } // 展示步骤数组 VStack(alignment: .leading, spacing: 8) { Text("制作步骤") .font(.headline) ForEach(dish.steps.indices, id: \.self) { index in Text("\(index + 1). \(dish.steps[index])") .multilineTextAlignment(.leading) } } // 展示图片 AsyncImage(url: URL(string: dish.imageURL)) { phase in switch phase { case .success(let image): image.resizable() .scaledToFit() .cornerRadius(8) case .failure: Image(systemName: "photo") .resizable() .scaledToFit() .foregroundColor(.gray) case .empty: ProgressView() @unknown default: EmptyView() } } } .padding() } .navigationTitle(dish.title) } }
额外注意:解析时要正确收集数组元素
最后再提一下,解析XML的时候要确保数组元素被正确收集,比如在XMLParserDelegate的实现里,要标记当前是否在<ingredients>或<description>节点内,然后把<item>和<step>的内容添加到对应的数组里,示例代码如下:
class DishXMLParser: NSObject, XMLParserDelegate { private var currentElement = "" private var currentDish = Dish(type: "", title: "", duration: "", calories: "", ingredients: [], imageURL: "", steps: []) private var currentIngredient = "" private var currentStep = "" private var isInsideIngredients = false private var isInsideDescription = false // 解析开始时的回调 func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) { currentElement = elementName switch elementName { case "ingredients": isInsideIngredients = true case "description": isInsideDescription = true default: break } } // 读取节点内容的回调 func parser(_ parser: XMLParser, foundCharacters string: String) { let trimmedText = string.trimmingCharacters(in: .whitespacesAndNewlines) guard !trimmedText.isEmpty else { return } switch currentElement { case "type": currentDish.type += trimmedText case "title": currentDish.title += trimmedText case "duration": currentDish.duration += trimmedText case "calories": currentDish.calories += trimmedText case "item" where isInsideIngredients: currentIngredient += trimmedText case "step" where isInsideDescription: currentStep += trimmedText case "image": currentDish.imageURL += trimmedText default: break } } // 节点结束时的回调 func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { switch elementName { case "item": if isInsideIngredients { currentDish.ingredients.append(currentIngredient) currentIngredient = "" } case "step": if isInsideDescription { currentDish.steps.append(currentStep) currentStep = "" } case "ingredients": isInsideIngredients = false case "description": isInsideDescription = false default: break } } // 解析完成后返回Dish实例 func parsedDish() -> Dish { return currentDish } }
这样一套流程下来,就能顺利把XML里的数组内容展示在界面上啦~
内容的提问来源于stack exchange,提问作者miranda
相关产品推荐
相关产品推荐

