Skip to content

Instantly share code, notes, and snippets.

@nickdaigler

nickdaigler/XMLToDict.swift Secret

Last active Feb 15, 2021
Embed
What would you like to do?
XML
public class XMLToDict: NSObject {
public static let kText = "XMLToDictTextKey"
public static let kAttributes = "_XMLAttributes"
private var stack = [NSMutableDictionary]()
private var textBeingProcessed = ""
}
public extension XMLToDict {
static func makeDict(data: Data) -> [String:Any]? {
let parser = XMLToDict()
return parser.dictFrom(data: data)
}
}
public extension XMLToDict {
func dictFrom(data: Data) -> [String : Any]? {
stack = [NSMutableDictionary]()
textBeingProcessed = ""
stack.append(NSMutableDictionary())
let parser = XMLParser(data: data)
parser.delegate = self
parser.parse()
return stack.first as? [String : Any]
}
}
// MARK: - XMLParserDelegate
extension XMLToDict: XMLParserDelegate {
public func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
guard let parent = stack.last else {
fatalError()
}
let child = NSMutableDictionary()
if attributeDict.count > 0 {
child.setObject(attributeDict, forKey: XMLToDict.kAttributes as NSString)
}
if let existingValue = parent[elementName] {
let array: NSMutableArray
if let currentArray = existingValue as? NSMutableArray {
array = currentArray
} else {
array = NSMutableArray()
array.add(existingValue)
parent[elementName] = array
}
array.add(child)
} else {
parent[elementName] = child
stack[stack.endIndex - 1] = parent
}
stack.append(child)
}
public func parser(_ parser: XMLParser, foundCharacters string: String) {
let trimmedString = string.trimmingCharacters(in: .whitespacesAndNewlines)
textBeingProcessed.append(trimmedString)
}
public func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
guard let lastDict = stack.last else {
fatalError()
}
let parent = stack[stack.endIndex - 2]
if textBeingProcessed.count > 0 {
if lastDict.count > 0 {
lastDict[XMLToDict.kText] = textBeingProcessed
} else if let array = parent[elementName] as? NSMutableArray {
array.removeLastObject()
array.add(textBeingProcessed)
} else {
parent[elementName] = textBeingProcessed
}
} else if lastDict.count == 0 {
parent.removeObject(forKey: elementName)
}
textBeingProcessed = ""
stack.removeLast()
}
public func parser(_ parser: XMLParser, parseErrorOccurred parseError: Error) {
print(parseError)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment