我正在绞尽脑汁如何将这个解析过的xml转换为数组或词典。 xml标签没有帮助,因为标签是通用的,并且有大约10个标头。我可以根据标签的顺序做一些事情。任何想法?
NSXMLParser方法代码:
class MyXMLParserDelegate: NSObject, NSXMLParserDelegate {
@objc func parserDidStartDocument(parser: NSXMLParser) {
print("parserDidStartDocument")
}
@objc func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) {
print("didStartElement --> \(elementName)")
}
@objc func parser(parser: NSXMLParser, foundCharacters string: String) {
print("foundCharacters --> \(string)")
}
@objc func parser(parser: NSXMLParser, didEndElement elementName: String,
namespaceURI: String?, qualifiedName qName: String?) {
print("didEndElement --> \(elementName)")
}
@objc func parser(parser: NSXMLParser, didStartMappingPrefix prefix: String,
toURI namespaceURI: String) {
print("didStartMappingPrefix --> Prefix: \(prefix) toURI: \(namespaceURI)")
}
@objc func parser(parser: NSXMLParser, didEndMappingPrefix prefix: String) {
print("didEndMappingPrefix --> Prefix: \(prefix)")
}
@objc func parserDidEndDocument(parser: NSXMLParser) {
//reload table with array
print("parserDidEndDocument")
}
}
使用NSXMLParser方法进行XML解析的示例结果:
<result>
<header>
<col>
<label>Tree Name</label>
</col>
<col>
<label>Num Levels</label>
</col>
<col>
<label>Defaults Weight</label>
</col>
<col>
<label>Name</label>
</col>
<col>
<label>Abbrev</label>
</col>
<col>
<label>Level</label>
</col>
<col>
<label>Full Name</label>
</col>
</header>
<body>
<row>
<col>Cost Center 1</col>
<col>2</col>
<col>5</col>
<col>Miami Dolphins Front Office</col>
<col/>
<col>0</col>
<col/>
</row>
<row>
<col>Cost Center 1</col>
<col>2</col>
<col>5</col>
<col>Accounts Receivable</col>
<col>A/R</col>
<col>1</col>
<col>Accounts Receivable</col>
</row>
<row>
<col>Cost Center 1</col>
<col>2</col>
<col>5</col>
<col>06</col>
<col>06</col>
<col>1</col>
<col>06</col>
</row>
<row>
<col>Cost Center 2</col>
<col>3</col>
<col>5</col>
<col>Cost Center 2</col>
<col/>
<col>0</col>
<col/>
</row>
<row>
<col>Cost Center 2</col>
<col>3</col>
<col>5</col>
<col>test2</col>
<col/>
<col>1</col>
<col>test2</col>
</row>
<row>
<col>Cost Center 2</col>
<col>3</col>
<col>5</col>
<col>test</col>
<col/>
<col>1</col>
<col>test</col>
</row>
<row>
<col>Cost Center 3</col>
<col>3</col>
<col>5</col>
<col>Cost Center 3</col>
<col/>
<col>0</col>
<col/>
</row>
<row>
<col>Cost Center 3</col>
<col>3</col>
<col>5</col>
<col>test</col>
<col/>
<col>1</col>
<col>test</col>
</row>
</body>
<footer/>
</result>
parserDidStartDocument
didStartElement - &gt;结果
foundCharacters - &gt;
didStartElement - &gt;头的
foundCharacters - &gt;
didStartElement - &gt;山口
foundCharacters - &gt;
didStartElement - &gt;标签
foundCharacters - &gt;树名
didEndElement - &gt;标签
foundCharacters - &gt;
didEndElement - &gt;山口
foundCharacters - &gt;
didStartElement - &gt;山口
foundCharacters - &gt;
didStartElement - &gt;标签
foundCharacters - &gt; Num Levels
didEndElement - &gt;标签
foundCharacters - &gt;
didEndElement - &gt;山口
foundCharacters - &gt;
didStartElement - &gt;山口
foundCharacters - &gt;
didStartElement - &gt;标签
foundCharacters - &gt;默认值重量
didEndElement - &gt;标签
foundCharacters - &gt;
didEndElement - &gt;山口
foundCharacters - &gt;
didStartElement - &gt;山口
foundCharacters - &gt;
didStartElement - &gt;标签
foundCharacters - &gt;名称
didEndElement - &gt;标签
foundCharacters - &gt;
didEndElement - &gt;山口
foundCharacters - &gt;
didStartElement - &gt;山口
foundCharacters - &gt;
didStartElement - &gt;标签
foundCharacters - &gt;缩写
didEndElement - &gt;标签
foundCharacters - &gt;
didEndElement - &gt;山口
foundCharacters - &gt;
didStartElement - &gt;山口
foundCharacters - &gt;
didStartElement - &gt;标签
foundCharacters - &gt;水平
didEndElement - &gt;标签
foundCharacters - &gt;
didEndElement - &gt;山口
foundCharacters - &gt;
didStartElement - &gt;山口
foundCharacters - &gt;
didStartElement - &gt;标签
foundCharacters - &gt;全名
didEndElement - &gt;标签
foundCharacters - &gt;
didEndElement - &gt;山口
foundCharacters - &gt;
didEndElement - &gt;头的
foundCharacters - &gt;
didStartElement - &gt;体
foundCharacters - &gt;
didStartElement - &gt;行
foundCharacters - &gt;
didStartElement - &gt;山口
foundCharacters - &gt;成本中心1
didEndElement - &gt;山口
foundCharacters - &gt;
didStartElement - &gt;山口
foundCharacters - &gt; 2
didEndElement - &gt;山口
foundCharacters - &gt;
...
答案 0 :(得分:1)
查看https://github.com/nicklockwood/XMLDictionary图书馆
库已用Obj-C
编写,但在Swift
中使用它不是问题。
在iOS和Mac OS上解析和生成XML的简单方法。将XML文件转换为NSDictionary,然后可以使用标准Cocoa keyPath机制轻松遍历该文件。也可以将任何字典的内容输出为XML。
答案 1 :(得分:1)
我需要这样的东西来测试生成的XML,但我必须自己动手。我创建了一个嵌套的元素树,每个元素都包含有关xml标记的信息。
fileprivate class XmlToDictionaryParserDelegate: NSObject, XMLParserDelegate {
private var currentElement: XmlElement?
fileprivate init(_ element: XmlElement) {
self.currentElement = element
}
public func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
self.currentElement = self.currentElement?.pop(elementName)
}
public func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
self.currentElement = self.currentElement?.push(elementName)
self.currentElement?.attributeDict = attributeDict
}
func parser(_ parser: XMLParser, foundCharacters string: String) {
self.currentElement?.text += string
}
}
public class XmlElement {
public private(set) var name = "unnamed"
public private(set) var children = [String: XmlElement]()
public private(set) var parent: XmlElement? = nil
public fileprivate(set) var text = ""
public fileprivate(set) var attributeDict: [String : String] = [:]
private init(_ parent: XmlElement? = nil, name: String = "") {
self.parent = parent
self.name = name
}
public convenience init?(fromString: String) {
guard let data = fromString.data(using: .utf8) else {
return nil
}
self.init(fromData: data)
}
public init(fromData: Data) {
let parser = XMLParser(data: fromData)
let delegate = XmlToDictionaryParserDelegate(self)
parser.delegate = delegate
parser.parse()
}
fileprivate func push(_ elementName: String) -> XmlElement {
let childElement = XmlElement(self, name: elementName)
children[elementName] = childElement
return childElement
}
fileprivate func pop(_ elementName: String) -> XmlElement? {
assert(elementName == self.name)
return self.parent
}
public subscript(name: String) -> XmlElement? {
return self.children[name]
}
}
使用从字符串(或数据)创建元素
let xml = XmlElement(fromString: "<first>text<second bar="foo"/></first>")
然后像这样使用:
XCTAssert(xml["first"]?.text == "text")
XCTAssert(xml["first"]?["second"].attributeDict["bar"] == "foo")
答案 2 :(得分:-1)
这太长了,所以我不建议你按原样使用它。 只是为了告诉你使用NSXMLParser有时会像这样一团糟。
import Foundation
let url = NSBundle.mainBundle().URLForResource("complex", withExtension: "xml")!
protocol ElementParserType: class {
func startElement(
elementName: String,
namespaceURI: String?,
qualifiedName qName: String?,
attributes attributeDict: [String : String],
in parserController: MyXMLParserController)
func endElement(
elementName: String,
namespaceURI: String?,
qualifiedName qName: String?,
in parserController: MyXMLParserController)
func foundCharacters(string: String, in parserController: MyXMLParserController)
}
class HeaderCol {
var label: String = ""
}
class Header {
var cols: [HeaderCol] = []
}
class Row {
var cols: [String] = []
}
class Body {
var rows: [Row] = []
}
class Result {
var header: Header?
var body: Body?
}
class LabelParser: ElementParserType {
var label: String?
let parent: HeaderColParser
init(parent: HeaderColParser) {
self.parent = parent
}
func startElement(
elementName: String,
namespaceURI: String?,
qualifiedName qName: String?,
attributes attributeDict: [String : String],
in parserController: MyXMLParserController)
{
parserController.didFail("Invalid start element `\(elementName)` in label")
}
func endElement(
elementName: String,
namespaceURI: String?,
qualifiedName qName: String?,
in parserController: MyXMLParserController)
{
guard elementName == "label" else {
parserController.didFail("Invalid end element `\(elementName)` in label")
return
}
parent.col.label = self.label ?? ""
parserController.popParser()
}
func foundCharacters(string: String,
in parserController: MyXMLParserController)
{
self.label = string
}
}
class HeaderColParser: ElementParserType {
let col = HeaderCol()
let parent: HeaderParser
init(parent: HeaderParser) {
self.parent = parent
}
func startElement(
elementName: String,
namespaceURI: String?,
qualifiedName qName: String?,
attributes attributeDict: [String : String],
in parserController: MyXMLParserController)
{
switch elementName {
case "label":
let labelParser = LabelParser(parent: self)
parserController.pushParser(labelParser)
default:
parserController.didFail("Invalid start element `\(elementName)` in col")
}
}
func endElement(
elementName: String,
namespaceURI: String?,
qualifiedName qName: String?,
in parserController: MyXMLParserController)
{
guard elementName == "col" else {
parserController.didFail("Invalid end element `\(elementName)` in col")
return
}
parent.header.cols.append(self.col)
parserController.popParser()
}
func foundCharacters(string: String,
in parserController: MyXMLParserController)
{
if string.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet()).isEmpty {
parserController.didFail("Invalid characters '\(string)' in col")
}
}
}
class HeaderParser: ElementParserType {
let header = Header()
let parent: ResultParser
init(parent: ResultParser) {
self.parent = parent
}
func startElement(
elementName: String,
namespaceURI: String?,
qualifiedName qName: String?,
attributes attributeDict: [String : String],
in parserController: MyXMLParserController)
{
switch elementName {
case "col":
let headerColParser = HeaderColParser(parent: self)
parserController.pushParser(headerColParser)
default:
parserController.didFail("Invalid start element `\(elementName)` in header")
}
}
func endElement(
elementName: String,
namespaceURI: String?,
qualifiedName qName: String?,
in parserController: MyXMLParserController)
{
guard elementName == "header" else {
parserController.didFail("Invalid end element `\(elementName)` in header")
return
}
parent.result.header = self.header
parserController.popParser()
}
func foundCharacters(string: String,
in parserController: MyXMLParserController)
{
if string.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet()).isEmpty {
parserController.didFail("Invalid characters '\(string)' in header")
}
}
}
class RowColParser: ElementParserType {
var col: String?
let parent: RowParser
init(parent: RowParser) {
self.parent = parent
}
func startElement(
elementName: String,
namespaceURI: String?,
qualifiedName qName: String?,
attributes attributeDict: [String : String],
in parserController: MyXMLParserController)
{
parserController.didFail("Invalid start element `\(elementName)` in col")
}
func endElement(
elementName: String,
namespaceURI: String?,
qualifiedName qName: String?,
in parserController: MyXMLParserController)
{
guard elementName == "col" else {
parserController.didFail("Invalid end element `\(elementName)` in col")
return
}
parent.row.cols.append(self.col ?? "")
parserController.popParser()
}
func foundCharacters(string: String,
in parserController: MyXMLParserController)
{
self.col = string
}
}
class RowParser: ElementParserType {
let row = Row()
let parent: BodyParser
init(parent: BodyParser) {
self.parent = parent
}
func startElement(
elementName: String,
namespaceURI: String?,
qualifiedName qName: String?,
attributes attributeDict: [String : String],
in parserController: MyXMLParserController)
{
switch elementName {
case "col":
let rowColParser = RowColParser(parent: self)
parserController.pushParser(rowColParser)
default:
parserController.didFail("Invalid start element `\(elementName)` in row")
}
}
func endElement(
elementName: String,
namespaceURI: String?,
qualifiedName qName: String?,
in parserController: MyXMLParserController)
{
guard elementName == "row" else {
parserController.didFail("Invalid end element `\(elementName)` in row")
return
}
parent.body.rows.append(self.row)
parserController.popParser()
}
func foundCharacters(string: String,
in parserController: MyXMLParserController)
{
if string.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet()).isEmpty {
parserController.didFail("Invalid characters '\(string)' in row")
}
}
}
class BodyParser: ElementParserType {
let body = Body()
let parent: ResultParser
init(parent: ResultParser) {
self.parent = parent
}
func startElement(
elementName: String,
namespaceURI: String?,
qualifiedName qName: String?,
attributes attributeDict: [String : String],
in parserController: MyXMLParserController)
{
switch elementName {
case "row":
let rowParser = RowParser(parent: self)
parserController.pushParser(rowParser)
default:
parserController.didFail("Invalid start element `\(elementName)` in body")
}
}
func endElement(
elementName: String,
namespaceURI: String?,
qualifiedName qName: String?,
in parserController: MyXMLParserController)
{
guard elementName == "body" else {
parserController.didFail("Invalid end element `\(elementName)` in body")
return
}
parent.result.body = self.body
parserController.popParser()
}
func foundCharacters(string: String,
in parserController: MyXMLParserController)
{
if string.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet()).isEmpty {
parserController.didFail("Invalid characters '\(string)' in footer")
}
}
}
class FooterParser: ElementParserType {
let parent: ResultParser
init(parent: ResultParser) {
self.parent = parent
}
func startElement(
elementName: String,
namespaceURI: String?,
qualifiedName qName: String?,
attributes attributeDict: [String : String],
in parserController: MyXMLParserController)
{
switch elementName {
default:
parserController.didFail("Invalid start element `\(elementName)` in footer")
}
}
func endElement(
elementName: String,
namespaceURI: String?,
qualifiedName qName: String?,
in parserController: MyXMLParserController)
{
guard elementName == "footer" else {
parserController.didFail("Invalid end element `\(elementName)` in footer")
return
}
//Do nothing
parserController.popParser()
}
func foundCharacters(string: String,
in parserController: MyXMLParserController)
{
if string.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet()).isEmpty {
parserController.didFail("Invalid characters '\(string)' in footer")
}
}
}
class ResultParser: ElementParserType {
let result = Result()
func startElement(
elementName: String,
namespaceURI: String?,
qualifiedName qName: String?,
attributes attributeDict: [String : String],
in parserController: MyXMLParserController)
{
switch elementName {
case "header":
let headerParser = HeaderParser(parent: self)
parserController.pushParser(headerParser)
case "body":
let headerParser = BodyParser(parent: self)
parserController.pushParser(headerParser)
case "footer":
let headerParser = FooterParser(parent: self)
parserController.pushParser(headerParser)
default:
parserController.didFail("Invalid start element `\(elementName)` in result")
}
}
func endElement(
elementName: String,
namespaceURI: String?,
qualifiedName qName: String?,
in parserController: MyXMLParserController)
{
guard elementName == "result" else {
parserController.didFail("Invalid end element `\(elementName)` in result")
return
}
parserController.result = self.result
parserController.popParser()
}
func foundCharacters(string: String,
in parserController: MyXMLParserController)
{
if string.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet()).isEmpty {
parserController.didFail("Invalid characters '\(string)' in footer")
}
}
}
class MyXMLParserController: NSObject, NSXMLParserDelegate {
let xmlParser: NSXMLParser
var result: AnyObject?
var parserStack: [ElementParserType] = []
var currentParser: ElementParserType? {
return parserStack.last
}
init?(url: NSURL) {
if let xmlParser = NSXMLParser(contentsOfURL: url) {
self.xmlParser = xmlParser
super.init()
self.xmlParser.delegate = self //The delegate is not retained.
} else {
return nil
}
}
func pushParser(parser: ElementParserType) {
parserStack.append(parser)
}
func popParser() {
parserStack.removeLast()
}
func parse() {
self.xmlParser.parse()
}
func parserDidStartDocument(parser: NSXMLParser) {
print(#function)
}
func parserDidEndDocument(parser: NSXMLParser) {
print(#function)
}
func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) {
print(#function, elementName)
if let parser = currentParser {
parser.startElement(elementName,
namespaceURI: namespaceURI,
qualifiedName: qName,
attributes: attributeDict,
in: self)
} else {
guard elementName == "result" else {
print("Root element needs to be `result`")
parser.abortParsing()
return
}
pushParser(ResultParser())
}
}
func parser(parser: NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
if let parser = currentParser {
parser.endElement(elementName,
namespaceURI: namespaceURI,
qualifiedName: qName,
in: self)
} else {
didFail("Invalid end element \(elementName) at top level")
}
}
func parser(parser: NSXMLParser, foundCharacters string: String) {
if let parser = currentParser {
parser.foundCharacters(string,
in: self)
} else {
didFail("Invalid characters '\(string)' at top level")
}
}
func didFail(error: String) {
xmlParser.abortParsing()
}
}
let parserController = MyXMLParserController(url: url)!
parserController.parse()
let result = parserController.result as! Result
if let header = result.header, body = result.body {
var rowArray: [[String: String]] = []
for row in body.rows {
assert(header.cols.count == row.cols.count)
var rowDict: [String: String] = [:]
for i in 0..<header.cols.count {
rowDict[header.cols[i].label] = row.cols[i]
}
rowArray.append(rowDict)
}
print(rowArray as NSArray)
} else {
print("header or body is missing")
}
答案 3 :(得分:-1)
计算出来,虽然可能有更多的复杂性,但稍后会进行优化:
UIColor(