-
Notifications
You must be signed in to change notification settings - Fork 104
/
XMLStackParser.swift
101 lines (78 loc) · 2.67 KB
/
XMLStackParser.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
//
// XMLStackParser.swift
// XMLCoder
//
// Created by Shawn Moore on 11/14/17.
// Copyright © 2017 Shawn Moore. All rights reserved.
//
import Foundation
class _XMLStackParser: NSObject {
var root: _XMLElement? = nil
var stack: [_XMLElement] = []
var currentNode: _XMLElement? = nil
var currentElementName: String? = nil
var currentElementData = ""
static func parse(with data: Data) throws -> [String: Box] {
let parser = _XMLStackParser()
guard let node = try parser.parse(with: data) else {
throw DecodingError.dataCorrupted(DecodingError.Context(
codingPath: [],
debugDescription: "The given data could not be parsed into XML."
))
}
return node.flatten()
}
func parse(with data: Data) throws -> _XMLElement? {
let xmlParser = XMLParser(data: data)
xmlParser.delegate = self
guard xmlParser.parse() else {
if let error = xmlParser.parserError {
throw error
}
return nil
}
return root
}
}
extension _XMLStackParser: XMLParserDelegate {
func parserDidStartDocument(_: XMLParser) {
root = nil
stack = []
}
func parser(_: XMLParser, didStartElement elementName: String, namespaceURI _: String?, qualifiedName _: String?, attributes attributeDict: [String: String] = [:]) {
let node = _XMLElement(key: elementName, attributes: attributeDict)
stack.append(node)
currentNode?.children[elementName, default: []].append(node)
currentNode = node
}
func parser(_: XMLParser, didEndElement _: String, namespaceURI _: String?, qualifiedName _: String?) {
guard let poppedNode = stack.popLast() else {
return
}
if let value = poppedNode.value {
poppedNode.value = value.isEmpty ? nil : value
}
if stack.isEmpty {
root = poppedNode
}
currentNode = stack.last
}
func parser(_: XMLParser, foundCharacters string: String) {
guard let currentNode = currentNode else {
return
}
currentNode.append(value: string)
}
func parser(_: XMLParser, foundCDATA CDATABlock: Data) {
guard let string = String(data: CDATABlock, encoding: .utf8) else {
return
}
guard let currentNode = currentNode else {
return
}
currentNode.append(value: string)
}
func parser(_: XMLParser, parseErrorOccurred parseError: Error) {
print(parseError)
}
}