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

如何在SwiftUI Mac应用中运行嵌入式二进制文件并实现XML验证?

解决Xidel XML验证器的文件选择与结果展示问题

我来帮你搞定这个XML验证器的开发!你当前的代码已经能成功调用嵌入式的Xidel二进制文件,但在本地XML文件选择和捕获验证结果展示这两个核心需求上需要调整,下面是具体的修改方案:

1. 添加本地XML文件选择功能

首先我们需要在SwiftUI中集成文件选择器,通过UIDocumentPickerViewController来实现,先创建一个包装它的View:

struct DocumentPicker: UIViewControllerRepresentable {
    @Binding var selectedFileURL: URL?
    
    func makeUIViewController(context: Context) -> UIDocumentPickerViewController {
        let picker = UIDocumentPickerViewController(forOpeningContentTypes: [.xml])
        picker.delegate = context.coordinator
        return picker
    }
    
    func updateUIViewController(_ uiViewController: UIDocumentPickerViewController, context: Context) {}
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    class Coordinator: NSObject, UIDocumentPickerDelegate {
        let parent: DocumentPicker
        
        init(_ parent: DocumentPicker) {
            self.parent = parent
        }
        
        func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
            guard let url = urls.first else { return }
            // 给沙箱授权访问这个文件
            url.startAccessingSecurityScopedResource()
            parent.selectedFileURL = url
        }
        
        func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
            parent.selectedFileURL = nil
        }
    }
}

2. 修改ContentView,实现文件选择、Xidel调用与结果展示

接下来调整你的ContentView,添加文件选择按钮、存储选中文件的状态、捕获Xidel的输出并展示:

struct ContentView: View {
    @State var selectedFileURL: URL?
    @State var validationResult = "请选择XML文件并点击验证"
    @State var isRunning = false
    
    var body: some View {
        VStack(spacing: 20) {
            Text("XML Validator")
                .font(.largeTitle)
                .padding()
            
            // 文件选择按钮
            Button(action: {}) {
                Text(selectedFileURL?.lastPathComponent ?? "选择XML文件")
                    .padding()
                    .background(Color.blue)
                    .foregroundColor(.white)
                    .cornerRadius(8)
            }
            .sheet(isPresented: .constant(false)) {
                DocumentPicker(selectedFileURL: $selectedFileURL)
            }
            .sheet(item: $selectedFileURL) { _ in
                DocumentPicker(selectedFileURL: $selectedFileURL)
            }
            
            // 验证按钮
            Button(action: validateXML) {
                Text("验证")
                    .padding()
                    .background(Color.green)
                    .foregroundColor(.white)
                    .cornerRadius(8)
            }
            .disabled(isRunning || selectedFileURL == nil)
            
            // 展示验证结果
            Text(validationResult)
                .padding()
                .frame(maxWidth: .infinity, maxHeight: .infinity)
                .background(Color.gray.opacity(0.1))
                .cornerRadius(8)
                .padding()
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .padding()
    }
    
    private func validateXML() {
        guard let fileURL = selectedFileURL else { return }
        isRunning = true
        validationResult = "正在验证..."
        
        let task = Process()
        let bundle = Bundle.main
        guard let execURL = bundle.url(forResource: "xidel", withExtension: nil) else {
            validationResult = "XIDEL executable could not be found!"
            isRunning = false
            return
        }
        
        task.executableURL = execURL
        // 正确设置Xidel参数:用--validate执行XML验证,传入选中文件的路径
        task.arguments = ["--validate", fileURL.path]
        
        // 捕获标准输出和错误输出
        let outputPipe = Pipe()
        let errorPipe = Pipe()
        task.standardOutput = outputPipe
        task.standardError = errorPipe
        
        do {
            try task.run()
            
            // 读取输出内容
            let outputData = outputPipe.fileHandleForReading.readDataToEndOfFile()
            let errorData = errorPipe.fileHandleForReading.readDataToEndOfFile()
            
            task.waitUntilExit()
            
            let outputString = String(data: outputData, encoding: .utf8) ?? ""
            let errorString = String(data: errorData, encoding: .utf8) ?? ""
            
            if task.terminationStatus == 0 {
                validationResult = "✅ XML验证通过!\n\(outputString)"
            } else {
                validationResult = "❌ XML验证失败!\n错误信息:\(errorString)"
            }
        } catch {
            validationResult = "运行XIDEL出错:\(error.localizedDescription)"
        }
        
        isRunning = false
        // 释放文件访问权限
        selectedFileURL?.stopAccessingSecurityScopedResource()
    }
}

关键修改点说明

  • 文件选择:通过UIDocumentPickerViewController让用户选择本地XML文件,同时处理了沙箱环境下的文件访问权限(startAccessingSecurityScopedResource和stopAccessingSecurityScopedResource)。
  • Xidel参数优化:把原来硬编码的查询参数改成了["--validate", fileURL.path],专门调用Xidel的XML验证功能,直接传入选中文件的路径。
  • 结果捕获展示:使用Pipe重定向Process的标准输出和错误输出,读取后转换成字符串展示在界面上,替代了原来仅打印到控制台的方式。
  • 状态管理:通过isRunning状态控制验证按钮的禁用状态,避免重复点击,同时实时更新界面提示用户当前验证状态。

内容的提问来源于stack exchange,提问作者Marc H.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 21:43:15