如何在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.
相关产品推荐
相关产品推荐

