You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:27:41