如何在 iOS Swift 中获取 XML 数据并在 tableview 中绑定?
Posted
技术标签:
【中文标题】如何在 iOS Swift 中获取 XML 数据并在 tableview 中绑定?【英文标题】:How to get XML data and bind in tableview in iOS Swift? 【发布时间】:2019-08-16 20:26:08 【问题描述】:我一直在使用具有基本授权的 oData url。 oXML 格式的数据响应。我可以使用 Alamofire 从 oData url 响应数据。但我无法从 XML 中获取特定值。
这是我的 XML 响应数据:
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xml:base="http://hostname:portNumber/sap/opu/odata/sap/ZPRJ_PM_APPS_IH_SRV/">
<id>hostname:portNumber/sap/opu/odata/sap/ZPRJ_PM_APPS_IH_SRV/WorkOrder</id>
<title type="text">WorkOrderF4Set</title>
<updated>2019-08-16T15:37:48Z</updated>
<author>
<name/>
</author>
<link href="WorkOrderF4Set" rel="self" title="WorkOrderF4Set"/>
<entry>
<id>hostname:portNumber/sap/opu/odata/sap/ZPRJ_PM_APPS_IH_SRV/WorkOrder('000000504780')</id>
<title type="text">WorkOrder('000000504780')</title>
<updated>2019-08-16T15:37:48Z</updated>
<category term="ZPRJ_PM_APPS_IH_SRV.WorkOrder" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme"/>
<link href="WorkOrder('000000504780')" rel="self" title="WorkOrder"/>
<content type="application/xml">
<m:properties xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices">
<d:WorkOrder>000000504780</d:WorkOrder>
<d:Description>General Maintenance testing</d:Description>
</m:properties>
</content>
</entry>
<entry>
<id>http://hostname:portNumber/sap/opu/odata/sap/ZPRJ_PM_APPS_IH_SRV/WorkOrder('000000821400')</id>
<title type="text">WorkOrderF4Set('000000821400')</title>
<updated>2019-08-16T15:37:48Z</updated>
<category term="ZPRJ_PM_APPS_IH_SRV.WorkOrder" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme"/>
<link href="WorkOrder('000000821400')" rel="self" title="WorkOrder"/>
<content type="application/xml">
<m:properties xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices">
<d:WorkOrder>000000821400</d:WorkOrder>
<d:Description>PUMP LEAKING</d:Description>
</m:properties>
</content>
</entry>
</feed>
我在这里尝试获取 d:WorkOrder 和 d:Description 值并绑定到表格视图单元格中。
这是我从 alamofire 获得响应的代码:
func loadData()
let user = "raXXXXXX"
let password = "xxxxxxx"
let url = "http://hostname:portNumber/sap/opu/odata/sap/ZPRJ_PM_APPS_IH_SRV/WorkOrder"
let loginString = "\(user):\(password)"
guard let loginData = loginString.data(using: String.Encoding.utf8) else
return
let base64LoginString = loginData.base64EncodedString()
print("base 64 login :\(base64LoginString)")
let headers = ["Authorization": "Basic \(base64LoginString)"]
Alamofire.request(url, method: .get, encoding: URLEncoding.default, headers: headers)
.responseString response in
print(" - API url: \(String(describing: response.request!))") // original url request
var statusCode = response.response?.statusCode
switch response.result
case .success:
print("status code is: \(String(describing: statusCode))")
if let stringg = response.result.value
print("XML: \(stringg)")
let data = stringg.data(using: .utf8)
let xml = try! XML.parse(data!)
print("xml value:\(xml)")
let element = xml.feed.entry
print("element xml :\(element)")
let results = xml["feed", "entry"]
print("result xml :\(results)")
for result in results["entry"]
if let jobtitle = result["d:WorkOrder"].text
print("job::\(jobtitle)")
if let attributeValue = xml.feed.entry[0].attributes["d:WorkOrder"]
print("attributeValue\(attributeValue)") // -> 2
let work = "d:WorkOrder"
print("feed:\(xml.feed.entry[0].WorkOrder)")
guard let jsonData = stringg.data(using: .utf8) else return
guard let jsonResponse = (try? JSONSerialization.jsonObject(with: jsonData)) as? [[String:Any]] else return
let idArray = jsonResponse.flatMap$0["d:WorkOrder"] as? String
print("idarray::\(idArray)")
if let data = response.data, let utf8Text = String(data: data, encoding: .utf8)
print("Data: \(utf8Text)") // original server data as UTF8 string
case .failure(let error):
statusCode = error._code // statusCode private
print("status code is: \(String(describing: statusCode))")
print(error)
//loaddata
也尝试使用 XMLSwiftyParser pod,但效果不佳。
let data = stringg.data(using: .utf8)
let xml = try! XML.parse(data!)
print("xml value:\(xml)")
let element = xml.feed.entry
print("element xml :\(element)")
let results = xml["feed", "entry"]
print("result xml :\(results)")
for result in results["entry"]
if let jobtitle = result["d:WorkOrder"].text
print("job::\(jobtitle)")
如何在表格视图中解析 d:WorkOrder 和 d:Description。
任何帮助都非常感谢...
【问题讨论】:
【参考方案1】:您可以使用此代码解析任何 xml 数据。然后您可以访问 parsedData 变量中的数据。使用辅助功能“搜索”,您可以获得任意键的任意值。
class ViewController: UIViewController, XMLParserDelegate
var parsedData = Dictionary<String,Any>()
var openElements = [String]()
override func viewDidLoad()
super.viewDidLoad()
if let path = Bundle.main.url(forResource: "Feed", withExtension: "xml")
if let parser = XMLParser(contentsOf: path)
parser.delegate = self
parser.parse()
func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:])
openElements.append(elementName)
parsedData[elementName] = attributeDict
func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?)
_ = openElements.popLast()
if let last = openElements.last, var dict = parsedData[last] as? [String:Any], let data = parsedData[elementName]
if let prevData = dict[elementName]
dict[elementName] = [prevData, data]
else
dict[elementName] = data
parsedData[last] = dict
parsedData.removeValue(forKey: elementName)
func parser(_ parser: XMLParser, foundCharacters string: String)
let string = string.trimmingCharacters(in: .whitespacesAndNewlines)
if !string.isEmpty, let last = openElements.last, var dict = parsedData[last] as? [String:Any]
dict["text"] = string
parsedData[last] = dict
func parserDidEndDocument(_ parser: XMLParser)
search(key: "d:WorkOrder", in: parsedData, completion: print($0) )
search(key: "d:Description", in: parsedData, completion: print($0) )
func search(key:String, in dict:[String:Any], completion:((Any) -> ()))
if let foundValue = dict[key]
completion(foundValue)
else
dict.values.enumerated().forEach
if let innerDict = $0.element as? [String:Any]
search(key: key, in: innerDict, completion: completion)
if let innerArray = $0.element as? [[String:Any]]
innerArray.forEach( innerDict in
search(key: key, in: innerDict, completion: completion)
)
【讨论】:
如何在 tableview 中使用效果很好。我需要在 tableview 中加载 d:WorkOrder 和 d:Description【参考方案2】:基于@Hamza Öztürk 的回答,尝试使用 XMLParse:
import UIKit
struct Book
var workOrder: String
var description: String
class TableViewController: UITableViewController, XMLParserDelegate
var books: [Book] = []
var elementName: String = String()
var bookWorkOrder = String()
var bookdescription = String()
override func viewDidLoad()
super.viewDidLoad()
if let path = Bundle.main.url(forResource: "Feed", withExtension: "xml")
if let parser = XMLParser(contentsOf: path)
parser.delegate = self
parser.parse()
// 1
func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:])
if elementName == "entry"
bookWorkOrder = String()
bookdescription = String()
self.elementName = elementName
// 2
func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?)
if elementName == "entry"
let book = Book(workOrder: bookWorkOrder, description: bookdescription)
books.append(book)
print("count::\(books.count)")
// 3
func parser(_ parser: XMLParser, foundCharacters string: String)
let data = string.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
if (!data.isEmpty)
if self.elementName == "d:WorkOrder"
bookWorkOrder += data
else if self.elementName == "d:Description"
bookdescription += data
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int
// return the number of sections
return 1
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
// return the number of rows
return books.count
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! cellTableViewCell
let book = books[indexPath.row]
print("book::\(book.workOrder)")
cell.workorfer.text = book.workOrder
cell.descriptor.text = book.description
return cell
【讨论】:
【参考方案3】:你也可以试试XMLMapper pod。
使用嵌套映射功能,您的模型可能如下所示:
class Feed: XMLMappable
var nodeName: String!
var entries: [Entry]?
required init?(map: XMLMap)
func mapping(map: XMLMap)
entries <- map["entry"]
class Entry: XMLMappable
var nodeName: String!
var workOrder: String?
var description: String?
required init?(map: XMLMap)
func mapping(map: XMLMap)
workOrder <- map["content.m:properties.d:WorkOrder"]
description <- map["content.m:properties.d:Description"]
您可以将您的 XML 映射到此模型,例如:
let feed = Feed(XMLString: xmlString)
或使用Requests 子规范:
Alamofire.request(url, method: .get, encoding: URLEncoding.default, headers: headers)
.responseXMLObject (dataResponse: DataResponse<Feed>) in
let feed = dataResponse.result.value
print(feed?.toXMLString() ?? "nil")
【讨论】:
以上是关于如何在 iOS Swift 中获取 XML 数据并在 tableview 中绑定?的主要内容,如果未能解决你的问题,请参考以下文章
从 api 获取所有数据以及如何在 swift ios 中仅在单元格上附加标题
使用 alamofire 和 Swift4 IOS 获取 XML HTTP url 的响应