mirror of
https://github.com/exyte/Macaw.git
synced 2024-10-04 00:08:34 +03:00
#769 Update SWXMLHash
This commit is contained in:
parent
2b406e55f2
commit
cc7513b663
396
Dependencies/SWXMLHash/SWXMLHash.swift → Dependencies/SWXMLHash/XMLHash.swift
vendored
Executable file → Normal file
396
Dependencies/SWXMLHash/SWXMLHash.swift → Dependencies/SWXMLHash/XMLHash.swift
vendored
Executable file → Normal file
@ -1,5 +1,5 @@
|
||||
//
|
||||
// SWXMLHash.swift
|
||||
// XMLHash.swift
|
||||
// SWXMLHash
|
||||
//
|
||||
// Copyright (c) 2014 David Mohundro
|
||||
@ -30,11 +30,14 @@
|
||||
// swiftlint:disable file_length
|
||||
|
||||
import Foundation
|
||||
#if canImport(FoundationXML)
|
||||
import FoundationXML
|
||||
#endif
|
||||
|
||||
let rootElementName = "SWXMLHash_Root_Element"
|
||||
|
||||
/// Parser options
|
||||
public class SWXMLHashOptions {
|
||||
public class XMLHashOptions {
|
||||
internal init() {}
|
||||
|
||||
/// determines whether to parse the XML with lazy parsing or not
|
||||
@ -50,13 +53,20 @@ public class SWXMLHashOptions {
|
||||
|
||||
/// Encoding used for XML parsing. Default is set to UTF8
|
||||
public var encoding = String.Encoding.utf8
|
||||
|
||||
/// Any contextual information set by the user for encoding
|
||||
public var userInfo = [CodingUserInfoKey: Any]()
|
||||
|
||||
/// Detect XML parsing errors... defaults to false as this library will
|
||||
/// attempt to handle HTML which isn't always XML-compatible
|
||||
public var detectParsingErrors = false
|
||||
}
|
||||
|
||||
/// Simple XML parser
|
||||
public class SWXMLHash {
|
||||
let options: SWXMLHashOptions
|
||||
public class XMLHash {
|
||||
let options: XMLHashOptions
|
||||
|
||||
private init(_ options: SWXMLHashOptions = SWXMLHashOptions()) {
|
||||
private init(_ options: XMLHashOptions = XMLHashOptions()) {
|
||||
self.options = options
|
||||
}
|
||||
|
||||
@ -64,14 +74,14 @@ public class SWXMLHash {
|
||||
Method to configure how parsing works.
|
||||
|
||||
- parameters:
|
||||
- configAction: a block that passes in an `SWXMLHashOptions` object with
|
||||
- configAction: a block that passes in an `XMLHashOptions` object with
|
||||
options to be set
|
||||
- returns: an `SWXMLHash` instance
|
||||
- returns: an `XMLHash` instance
|
||||
*/
|
||||
class public func config(_ configAction: (SWXMLHashOptions) -> Void) -> SWXMLHash {
|
||||
let opts = SWXMLHashOptions()
|
||||
class public func config(_ configAction: (XMLHashOptions) -> Void) -> XMLHash {
|
||||
let opts = XMLHashOptions()
|
||||
configAction(opts)
|
||||
return SWXMLHash(opts)
|
||||
return XMLHash(opts)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -110,7 +120,7 @@ public class SWXMLHash {
|
||||
- returns: An XMLIndexer instance that is used to look up elements in the XML
|
||||
*/
|
||||
class public func parse(_ xml: String) -> XMLIndexer {
|
||||
return SWXMLHash().parse(xml)
|
||||
XMLHash().parse(xml)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -120,7 +130,7 @@ public class SWXMLHash {
|
||||
- returns: An XMLIndexer instance that is used to look up elements in the XML
|
||||
*/
|
||||
class public func parse(_ data: Data) -> XMLIndexer {
|
||||
return SWXMLHash().parse(data)
|
||||
XMLHash().parse(data)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -130,7 +140,7 @@ public class SWXMLHash {
|
||||
- returns: An XMLIndexer instance that is used to look up elements in the XML
|
||||
*/
|
||||
class public func lazy(_ xml: String) -> XMLIndexer {
|
||||
return config { conf in conf.shouldProcessLazily = true }.parse(xml)
|
||||
config { conf in conf.shouldProcessLazily = true }.parse(xml)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -140,128 +150,137 @@ public class SWXMLHash {
|
||||
- returns: An XMLIndexer instance that is used to look up elements in the XML
|
||||
*/
|
||||
class public func lazy(_ data: Data) -> XMLIndexer {
|
||||
return config { conf in conf.shouldProcessLazily = true }.parse(data)
|
||||
config { conf in conf.shouldProcessLazily = true }.parse(data)
|
||||
}
|
||||
}
|
||||
|
||||
struct Stack<T> {
|
||||
var items = [T]()
|
||||
|
||||
mutating func push(_ item: T) {
|
||||
items.append(item)
|
||||
}
|
||||
|
||||
mutating func pop() -> T {
|
||||
return items.removeLast()
|
||||
items.removeLast()
|
||||
}
|
||||
|
||||
mutating func drop() {
|
||||
_ = pop()
|
||||
}
|
||||
|
||||
mutating func removeAll() {
|
||||
items.removeAll(keepingCapacity: false)
|
||||
}
|
||||
|
||||
func top() -> T {
|
||||
return items[items.count - 1]
|
||||
items[items.count - 1]
|
||||
}
|
||||
}
|
||||
|
||||
protocol SimpleXmlParser {
|
||||
init(_ options: SWXMLHashOptions)
|
||||
init(_ options: XMLHashOptions)
|
||||
func parse(_ data: Data) -> XMLIndexer
|
||||
}
|
||||
|
||||
#if os(Linux)
|
||||
|
||||
extension XMLParserDelegate {
|
||||
func parserDidStartDocument(_ parser: XMLParser) { }
|
||||
func parserDidEndDocument(_ parser: XMLParser) { }
|
||||
|
||||
func parserDidStartDocument(_ parser: Foundation.XMLParser) { }
|
||||
func parserDidEndDocument(_ parser: Foundation.XMLParser) { }
|
||||
|
||||
func parser(_ parser: Foundation.XMLParser,
|
||||
func parser(_ parser: XMLParser,
|
||||
foundNotationDeclarationWithName name: String,
|
||||
publicID: String?,
|
||||
systemID: String?) { }
|
||||
|
||||
func parser(_ parser: Foundation.XMLParser,
|
||||
func parser(_ parser: XMLParser,
|
||||
foundUnparsedEntityDeclarationWithName name: String,
|
||||
publicID: String?,
|
||||
systemID: String?,
|
||||
notationName: String?) { }
|
||||
|
||||
func parser(_ parser: Foundation.XMLParser,
|
||||
func parser(_ parser: XMLParser,
|
||||
foundAttributeDeclarationWithName attributeName: String,
|
||||
forElement elementName: String,
|
||||
type: String?,
|
||||
defaultValue: String?) { }
|
||||
|
||||
func parser(_ parser: Foundation.XMLParser,
|
||||
func parser(_ parser: XMLParser,
|
||||
foundElementDeclarationWithName elementName: String,
|
||||
model: String) { }
|
||||
|
||||
func parser(_ parser: Foundation.XMLParser,
|
||||
func parser(_ parser: XMLParser,
|
||||
foundInternalEntityDeclarationWithName name: String,
|
||||
value: String?) { }
|
||||
|
||||
func parser(_ parser: Foundation.XMLParser,
|
||||
func parser(_ parser: XMLParser,
|
||||
foundExternalEntityDeclarationWithName name: String,
|
||||
publicID: String?,
|
||||
systemID: String?) { }
|
||||
|
||||
func parser(_ parser: Foundation.XMLParser,
|
||||
func parser(_ parser: XMLParser,
|
||||
didStartElement elementName: String,
|
||||
namespaceURI: String?,
|
||||
qualifiedName qName: String?,
|
||||
attributes attributeDict: [String : String]) { }
|
||||
attributes attributeDict: [String: String]) { }
|
||||
|
||||
func parser(_ parser: Foundation.XMLParser,
|
||||
func parser(_ parser: XMLParser,
|
||||
didEndElement elementName: String,
|
||||
namespaceURI: String?,
|
||||
qualifiedName qName: String?) { }
|
||||
|
||||
func parser(_ parser: Foundation.XMLParser,
|
||||
func parser(_ parser: XMLParser,
|
||||
didStartMappingPrefix prefix: String,
|
||||
toURI namespaceURI: String) { }
|
||||
|
||||
func parser(_ parser: Foundation.XMLParser, didEndMappingPrefix prefix: String) { }
|
||||
func parser(_ parser: XMLParser,
|
||||
didEndMappingPrefix prefix: String) { }
|
||||
|
||||
func parser(_ parser: Foundation.XMLParser, foundCharacters string: String) { }
|
||||
func parser(_ parser: XMLParser,
|
||||
foundCharacters string: String) { }
|
||||
|
||||
func parser(_ parser: Foundation.XMLParser,
|
||||
func parser(_ parser: XMLParser,
|
||||
foundIgnorableWhitespace whitespaceString: String) { }
|
||||
|
||||
func parser(_ parser: Foundation.XMLParser,
|
||||
func parser(_ parser: XMLParser,
|
||||
foundProcessingInstructionWithTarget target: String,
|
||||
data: String?) { }
|
||||
|
||||
func parser(_ parser: Foundation.XMLParser, foundComment comment: String) { }
|
||||
func parser(_ parser: XMLParser,
|
||||
foundComment comment: String) { }
|
||||
|
||||
func parser(_ parser: Foundation.XMLParser, foundCDATA CDATABlock: Data) { }
|
||||
func parser(_ parser: XMLParser,
|
||||
foundCDATA CDATABlock: Data) { }
|
||||
|
||||
func parser(_ parser: Foundation.XMLParser,
|
||||
func parser(_ parser: XMLParser,
|
||||
resolveExternalEntityName name: String,
|
||||
systemID: String?) -> Data? { return nil }
|
||||
systemID: String?) -> Data? { nil }
|
||||
|
||||
func parser(_ parser: Foundation.XMLParser, parseErrorOccurred parseError: NSError) { }
|
||||
func parser(_ parser: XMLParser,
|
||||
parseErrorOccurred parseError: Error) { }
|
||||
|
||||
func parser(_ parser: Foundation.XMLParser,
|
||||
validationErrorOccurred validationError: NSError) { }
|
||||
func parser(_ parser: XMLParser,
|
||||
validationErrorOccurred validationError: Error) { }
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/// The implementation of XMLParserDelegate and where the lazy parsing actually happens.
|
||||
class LazyXMLParser: NSObject, SimpleXmlParser, XMLParserDelegate {
|
||||
required init(_ options: SWXMLHashOptions) {
|
||||
required init(_ options: XMLHashOptions) {
|
||||
root = XMLElement(name: rootElementName, options: options)
|
||||
self.options = options
|
||||
self.root.caseInsensitive = options.caseInsensitive
|
||||
super.init()
|
||||
}
|
||||
|
||||
var root = XMLElement(name: rootElementName, caseInsensitive: false)
|
||||
var root: XMLElement
|
||||
var parentStack = Stack<XMLElement>()
|
||||
var elementStack = Stack<String>()
|
||||
|
||||
var data: Data?
|
||||
var ops: [IndexOp] = []
|
||||
let options: SWXMLHashOptions
|
||||
let options: XMLHashOptions
|
||||
|
||||
func parse(_ data: Data) -> XMLIndexer {
|
||||
self.data = data
|
||||
@ -269,25 +288,23 @@ class LazyXMLParser: NSObject, SimpleXmlParser, XMLParserDelegate {
|
||||
}
|
||||
|
||||
func startParsing(_ ops: [IndexOp]) {
|
||||
// clear any prior runs of parse... expected that this won't be necessary,
|
||||
// but you never know
|
||||
// reset state for a new lazy parsing run
|
||||
root = XMLElement(name: rootElementName, options: root.options)
|
||||
parentStack.removeAll()
|
||||
root = XMLElement(name: rootElementName, caseInsensitive: options.caseInsensitive)
|
||||
parentStack.push(root)
|
||||
|
||||
self.ops = ops
|
||||
let parser = Foundation.XMLParser(data: data!)
|
||||
let parser = XMLParser(data: data!)
|
||||
parser.shouldProcessNamespaces = options.shouldProcessNamespaces
|
||||
parser.delegate = self
|
||||
_ = parser.parse()
|
||||
}
|
||||
|
||||
func parser(_ parser: Foundation.XMLParser,
|
||||
func parser(_ parser: XMLParser,
|
||||
didStartElement elementName: String,
|
||||
namespaceURI: String?,
|
||||
qualifiedName qName: String?,
|
||||
attributes attributeDict: [String: String]) {
|
||||
|
||||
elementStack.push(elementName)
|
||||
|
||||
if !onMatch() {
|
||||
@ -300,7 +317,7 @@ class LazyXMLParser: NSObject, SimpleXmlParser, XMLParserDelegate {
|
||||
parentStack.push(currentNode)
|
||||
}
|
||||
|
||||
func parser(_ parser: Foundation.XMLParser, foundCharacters string: String) {
|
||||
func parser(_ parser: XMLParser, foundCharacters string: String) {
|
||||
if !onMatch() {
|
||||
return
|
||||
}
|
||||
@ -310,11 +327,22 @@ class LazyXMLParser: NSObject, SimpleXmlParser, XMLParserDelegate {
|
||||
current.addText(string)
|
||||
}
|
||||
|
||||
func parser(_ parser: Foundation.XMLParser,
|
||||
func parser(_ parser: XMLParser, foundCDATA CDATABlock: Data) {
|
||||
if !onMatch() {
|
||||
return
|
||||
}
|
||||
|
||||
if let cdataText = String(data: CDATABlock, encoding: String.Encoding.utf8) {
|
||||
let current = parentStack.top()
|
||||
|
||||
current.addText(cdataText)
|
||||
}
|
||||
}
|
||||
|
||||
func parser(_ parser: XMLParser,
|
||||
didEndElement elementName: String,
|
||||
namespaceURI: String?,
|
||||
qualifiedName qName: String?) {
|
||||
|
||||
let match = onMatch()
|
||||
|
||||
elementStack.drop()
|
||||
@ -337,15 +365,16 @@ class LazyXMLParser: NSObject, SimpleXmlParser, XMLParserDelegate {
|
||||
|
||||
/// The implementation of XMLParserDelegate and where the parsing actually happens.
|
||||
class FullXMLParser: NSObject, SimpleXmlParser, XMLParserDelegate {
|
||||
required init(_ options: SWXMLHashOptions) {
|
||||
required init(_ options: XMLHashOptions) {
|
||||
root = XMLElement(name: rootElementName, options: options)
|
||||
self.options = options
|
||||
self.root.caseInsensitive = options.caseInsensitive
|
||||
super.init()
|
||||
}
|
||||
|
||||
var root = XMLElement(name: rootElementName, caseInsensitive: false)
|
||||
let root: XMLElement
|
||||
var parentStack = Stack<XMLElement>()
|
||||
let options: SWXMLHashOptions
|
||||
let options: XMLHashOptions
|
||||
var parsingError: ParsingError?
|
||||
|
||||
func parse(_ data: Data) -> XMLIndexer {
|
||||
// clear any prior runs of parse... expected that this won't be necessary,
|
||||
@ -354,20 +383,23 @@ class FullXMLParser: NSObject, SimpleXmlParser, XMLParserDelegate {
|
||||
|
||||
parentStack.push(root)
|
||||
|
||||
let parser = Foundation.XMLParser(data: data)
|
||||
let parser = XMLParser(data: data)
|
||||
parser.shouldProcessNamespaces = options.shouldProcessNamespaces
|
||||
parser.delegate = self
|
||||
_ = parser.parse()
|
||||
|
||||
return XMLIndexer(root)
|
||||
if options.detectParsingErrors, let err = parsingError {
|
||||
return XMLIndexer.parsingError(err)
|
||||
} else {
|
||||
return XMLIndexer(root)
|
||||
}
|
||||
}
|
||||
|
||||
func parser(_ parser: Foundation.XMLParser,
|
||||
func parser(_ parser: XMLParser,
|
||||
didStartElement elementName: String,
|
||||
namespaceURI: String?,
|
||||
qualifiedName qName: String?,
|
||||
attributes attributeDict: [String: String]) {
|
||||
|
||||
let currentNode = parentStack
|
||||
.top()
|
||||
.addElement(elementName, withAttributes: attributeDict, caseInsensitive: self.options.caseInsensitive)
|
||||
@ -375,19 +407,39 @@ class FullXMLParser: NSObject, SimpleXmlParser, XMLParserDelegate {
|
||||
parentStack.push(currentNode)
|
||||
}
|
||||
|
||||
func parser(_ parser: Foundation.XMLParser, foundCharacters string: String) {
|
||||
func parser(_ parser: XMLParser, foundCharacters string: String) {
|
||||
let current = parentStack.top()
|
||||
|
||||
current.addText(string)
|
||||
}
|
||||
|
||||
func parser(_ parser: Foundation.XMLParser,
|
||||
func parser(_ parser: XMLParser,
|
||||
didEndElement elementName: String,
|
||||
namespaceURI: String?,
|
||||
qualifiedName qName: String?) {
|
||||
|
||||
parentStack.drop()
|
||||
}
|
||||
|
||||
func parser(_ parser: XMLParser, foundCDATA CDATABlock: Data) {
|
||||
if let cdataText = String(data: CDATABlock, encoding: String.Encoding.utf8) {
|
||||
let current = parentStack.top()
|
||||
|
||||
current.addText(cdataText)
|
||||
}
|
||||
}
|
||||
|
||||
func parser(_ parser: XMLParser, parseErrorOccurred parseError: Error) {
|
||||
#if os(Linux) && !swift(>=4.1.50)
|
||||
if let err = parseError as? NSError {
|
||||
parsingError = ParsingError(line: err.userInfo["NSXMLParserErrorLineNumber"] as? Int ?? 0,
|
||||
column: err.userInfo["NSXMLParserErrorColumn"] as? Int ?? 0)
|
||||
}
|
||||
#else
|
||||
let err = parseError as NSError
|
||||
parsingError = ParsingError(line: err.userInfo["NSXMLParserErrorLineNumber"] as? Int ?? 0,
|
||||
column: err.userInfo["NSXMLParserErrorColumn"] as? Int ?? 0)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents an indexed operation against a lazily parsed `XMLIndexer`
|
||||
@ -424,10 +476,10 @@ public class IndexOps {
|
||||
parser.startParsing(ops)
|
||||
let indexer = XMLIndexer(parser.root)
|
||||
var childIndex = indexer
|
||||
for op in ops {
|
||||
childIndex = childIndex[op.key]
|
||||
if op.index >= 0 {
|
||||
childIndex = childIndex[op.index]
|
||||
for oper in ops {
|
||||
childIndex = childIndex[oper.key]
|
||||
if oper.index >= 0 {
|
||||
childIndex = childIndex[oper.index]
|
||||
}
|
||||
}
|
||||
ops.removeAll(keepingCapacity: false)
|
||||
@ -435,14 +487,19 @@ public class IndexOps {
|
||||
}
|
||||
|
||||
func stringify() -> String {
|
||||
var s = ""
|
||||
for op in ops {
|
||||
s += "[" + op.toString() + "]"
|
||||
var ret = ""
|
||||
for oper in ops {
|
||||
ret += "[" + oper.toString() + "]"
|
||||
}
|
||||
return s
|
||||
return ret
|
||||
}
|
||||
}
|
||||
|
||||
public struct ParsingError: Error {
|
||||
public let line: Int
|
||||
public let column: Int
|
||||
}
|
||||
|
||||
/// Error type that is thrown when an indexing or parsing operation fails.
|
||||
public enum IndexingError: Error {
|
||||
case attribute(attr: String)
|
||||
@ -459,22 +516,27 @@ public enum IndexingError: Error {
|
||||
public static func Attribute(attr: String) -> IndexingError {
|
||||
fatalError("unavailable")
|
||||
}
|
||||
|
||||
@available(*, unavailable, renamed: "attributeValue(attr:value:)")
|
||||
public static func AttributeValue(attr: String, value: String) -> IndexingError {
|
||||
fatalError("unavailable")
|
||||
}
|
||||
|
||||
@available(*, unavailable, renamed: "key(key:)")
|
||||
public static func Key(key: String) -> IndexingError {
|
||||
fatalError("unavailable")
|
||||
}
|
||||
|
||||
@available(*, unavailable, renamed: "index(idx:)")
|
||||
public static func Index(idx: Int) -> IndexingError {
|
||||
fatalError("unavailable")
|
||||
}
|
||||
|
||||
@available(*, unavailable, renamed: "initialize(instance:)")
|
||||
public static func Init(instance: AnyObject) -> IndexingError {
|
||||
fatalError("unavailable")
|
||||
}
|
||||
|
||||
@available(*, unavailable, renamed: "error")
|
||||
public static var Error: IndexingError {
|
||||
fatalError("unavailable")
|
||||
@ -482,12 +544,13 @@ public enum IndexingError: Error {
|
||||
// swiftlint:enable identifier_name
|
||||
}
|
||||
|
||||
/// Returned from SWXMLHash, allows easy element lookup into XML data.
|
||||
/// Returned from XMLHash, allows easy element lookup into XML data.
|
||||
public enum XMLIndexer {
|
||||
case element(XMLElement)
|
||||
case list([XMLElement])
|
||||
case stream(IndexOps)
|
||||
case xmlError(IndexingError)
|
||||
case parsingError(ParsingError)
|
||||
|
||||
// swiftlint:disable identifier_name
|
||||
// unavailable
|
||||
@ -528,18 +591,18 @@ public enum XMLIndexer {
|
||||
|
||||
/// All elements at the currently indexed level
|
||||
public var all: [XMLIndexer] {
|
||||
allElements.map { XMLIndexer($0) }
|
||||
}
|
||||
|
||||
private var allElements: [XMLElement] {
|
||||
switch self {
|
||||
case .list(let list):
|
||||
var xmlList = [XMLIndexer]()
|
||||
for elem in list {
|
||||
xmlList.append(XMLIndexer(elem))
|
||||
}
|
||||
return xmlList
|
||||
return list
|
||||
case .element(let elem):
|
||||
return [XMLIndexer(elem)]
|
||||
return [elem]
|
||||
case .stream(let ops):
|
||||
let list = ops.findElements()
|
||||
return list.all
|
||||
return list.allElements
|
||||
default:
|
||||
return []
|
||||
}
|
||||
@ -547,15 +610,56 @@ public enum XMLIndexer {
|
||||
|
||||
/// All child elements from the currently indexed level
|
||||
public var children: [XMLIndexer] {
|
||||
var list = [XMLIndexer]()
|
||||
childElements.map { XMLIndexer($0) }
|
||||
}
|
||||
|
||||
private var childElements: [XMLElement] {
|
||||
var list = [XMLElement]()
|
||||
for elem in all.compactMap({ $0.element }) {
|
||||
for elem in elem.xmlChildren {
|
||||
list.append(XMLIndexer(elem))
|
||||
list.append(elem)
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
@available(*, unavailable, renamed: "filterChildren(_:)")
|
||||
public func filter(_ included: (_ elem: XMLElement, _ index: Int) -> Bool) -> XMLIndexer {
|
||||
filterChildren(included)
|
||||
}
|
||||
|
||||
public func filterChildren(_ included: (_ elem: XMLElement, _ index: Int) -> Bool) -> XMLIndexer {
|
||||
let children = handleFilteredResults(list: childElements, included: included)
|
||||
if let current = self.element {
|
||||
let filteredElem = XMLElement(name: current.name, index: current.index, options: current.options)
|
||||
filteredElem.children = children.allElements
|
||||
return .element(filteredElem)
|
||||
}
|
||||
return .xmlError(IndexingError.error)
|
||||
}
|
||||
|
||||
public func filterAll(_ included: (_ elem: XMLElement, _ index: Int) -> Bool) -> XMLIndexer {
|
||||
handleFilteredResults(list: allElements, included: included)
|
||||
}
|
||||
|
||||
private func handleFilteredResults(list: [XMLElement],
|
||||
included: (_ elem: XMLElement, _ index: Int) -> Bool) -> XMLIndexer {
|
||||
let results = zip(list.indices, list).filter { included($1, $0) }.map { $1 }
|
||||
if results.count == 1 {
|
||||
return .element(results.first!)
|
||||
}
|
||||
return .list(results)
|
||||
}
|
||||
|
||||
public var userInfo: [CodingUserInfoKey: Any] {
|
||||
switch self {
|
||||
case .element(let elem):
|
||||
return elem.userInfo
|
||||
default:
|
||||
return [:]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Allows for element lookup by matching attribute values.
|
||||
|
||||
@ -627,8 +731,8 @@ public enum XMLIndexer {
|
||||
public func byKey(_ key: String) throws -> XMLIndexer {
|
||||
switch self {
|
||||
case .stream(let opStream):
|
||||
let op = IndexOp(key)
|
||||
opStream.ops.append(op)
|
||||
let oper = IndexOp(key)
|
||||
opStream.ops.append(oper)
|
||||
return .stream(opStream)
|
||||
case .element(let elem):
|
||||
let match = elem.xmlChildren.filter({
|
||||
@ -641,7 +745,7 @@ public enum XMLIndexer {
|
||||
return .list(match)
|
||||
}
|
||||
}
|
||||
fallthrough
|
||||
throw IndexingError.key(key: key)
|
||||
default:
|
||||
throw IndexingError.key(key: key)
|
||||
}
|
||||
@ -676,7 +780,7 @@ public enum XMLIndexer {
|
||||
opStream.ops[opStream.ops.count - 1].index = index
|
||||
return .stream(opStream)
|
||||
case .list(let list):
|
||||
if index <= list.count {
|
||||
if index < list.count {
|
||||
return .element(list[index])
|
||||
}
|
||||
return .xmlError(IndexingError.index(idx: index))
|
||||
@ -684,7 +788,7 @@ public enum XMLIndexer {
|
||||
if index == 0 {
|
||||
return .element(elem)
|
||||
}
|
||||
fallthrough
|
||||
return .xmlError(IndexingError.index(idx: index))
|
||||
default:
|
||||
return .xmlError(IndexingError.index(idx: index))
|
||||
}
|
||||
@ -733,7 +837,7 @@ extension IndexingError: CustomStringConvertible {
|
||||
switch self {
|
||||
case .attribute(let attr):
|
||||
return "XML Attribute Error: Missing attribute [\"\(attr)\"]"
|
||||
case .attributeValue(let attr, let value):
|
||||
case let .attributeValue(attr, value):
|
||||
return "XML Attribute Error: Missing attribute [\"\(attr)\"] with value [\"\(value)\"]"
|
||||
case .key(let key):
|
||||
return "XML Element Error: Incorrect key [\"\(key)\"]"
|
||||
@ -756,6 +860,7 @@ public protocol XMLContent: CustomStringConvertible { }
|
||||
public class TextElement: XMLContent {
|
||||
/// The underlying text value
|
||||
public let text: String
|
||||
|
||||
init(text: String) {
|
||||
self.text = text
|
||||
}
|
||||
@ -764,6 +869,7 @@ public class TextElement: XMLContent {
|
||||
public struct XMLAttribute {
|
||||
public let name: String
|
||||
public let text: String
|
||||
|
||||
init(name: String, text: String) {
|
||||
self.name = name
|
||||
self.text = text
|
||||
@ -775,11 +881,19 @@ public class XMLElement: XMLContent {
|
||||
/// The name of the element
|
||||
public let name: String
|
||||
|
||||
public var caseInsensitive: Bool
|
||||
/// Whether the element is case insensitive or not
|
||||
public var caseInsensitive: Bool {
|
||||
options.caseInsensitive
|
||||
}
|
||||
|
||||
var userInfo: [CodingUserInfoKey: Any] {
|
||||
options.userInfo
|
||||
}
|
||||
|
||||
/// All attributes
|
||||
public var allAttributes = [String: XMLAttribute]()
|
||||
|
||||
/// Find an attribute by name
|
||||
public func attribute(by name: String) -> XMLAttribute? {
|
||||
if caseInsensitive {
|
||||
return allAttributes.first(where: { $0.key.compare(name, true) })?.value
|
||||
@ -789,7 +903,7 @@ public class XMLElement: XMLContent {
|
||||
|
||||
/// The inner text of the element, if it exists
|
||||
public var text: String {
|
||||
return children.reduce("", {
|
||||
children.reduce("", {
|
||||
if let element = $1 as? TextElement {
|
||||
return $0 + element.text
|
||||
}
|
||||
@ -800,7 +914,7 @@ public class XMLElement: XMLContent {
|
||||
|
||||
/// The inner text of the element and its children
|
||||
public var recursiveText: String {
|
||||
return children.reduce("", {
|
||||
children.reduce("", {
|
||||
if let textElement = $1 as? TextElement {
|
||||
return $0 + textElement.text
|
||||
} else if let xmlElement = $1 as? XMLElement {
|
||||
@ -811,13 +925,21 @@ public class XMLElement: XMLContent {
|
||||
})
|
||||
}
|
||||
|
||||
public var innerXML: String {
|
||||
children.reduce("", {
|
||||
$0.description + $1.description
|
||||
})
|
||||
}
|
||||
|
||||
/// All child elements (text or XML)
|
||||
public var children = [XMLContent]()
|
||||
|
||||
var count: Int = 0
|
||||
var index: Int
|
||||
let options: XMLHashOptions
|
||||
|
||||
var xmlChildren: [XMLElement] {
|
||||
return children.compactMap { $0 as? XMLElement }
|
||||
children.compactMap { $0 as? XMLElement }
|
||||
}
|
||||
|
||||
/**
|
||||
@ -826,11 +948,12 @@ public class XMLElement: XMLContent {
|
||||
- parameters:
|
||||
- name: The name of the element to be initialized
|
||||
- index: The index of the element to be initialized
|
||||
- options: The XMLHash options
|
||||
*/
|
||||
init(name: String, index: Int = 0, caseInsensitive: Bool) {
|
||||
init(name: String, index: Int = 0, options: XMLHashOptions) {
|
||||
self.name = name
|
||||
self.caseInsensitive = caseInsensitive
|
||||
self.index = index
|
||||
self.options = options
|
||||
}
|
||||
|
||||
/**
|
||||
@ -843,7 +966,7 @@ public class XMLElement: XMLContent {
|
||||
*/
|
||||
|
||||
func addElement(_ name: String, withAttributes attributes: [String: String], caseInsensitive: Bool) -> XMLElement {
|
||||
let element = XMLElement(name: name, index: count, caseInsensitive: caseInsensitive)
|
||||
let element = XMLElement(name: name, index: count, options: options)
|
||||
count += 1
|
||||
|
||||
children.append(element)
|
||||
@ -865,14 +988,14 @@ public class XMLElement: XMLContent {
|
||||
extension TextElement: CustomStringConvertible {
|
||||
/// The text value for a `TextElement` instance.
|
||||
public var description: String {
|
||||
return text
|
||||
text
|
||||
}
|
||||
}
|
||||
|
||||
extension XMLAttribute: CustomStringConvertible {
|
||||
/// The textual representation of an `XMLAttribute` instance.
|
||||
public var description: String {
|
||||
return "\(name)=\"\(text)\""
|
||||
"\(name)=\"\(text)\""
|
||||
}
|
||||
}
|
||||
|
||||
@ -888,7 +1011,7 @@ extension XMLElement: CustomStringConvertible {
|
||||
xmlReturn.append(child.description)
|
||||
}
|
||||
xmlReturn.append("</\(name)>")
|
||||
return xmlReturn.joined(separator: "")
|
||||
return xmlReturn.joined()
|
||||
}
|
||||
|
||||
return "<\(name)\(attributesString)>\(text)</\(name)>"
|
||||
@ -900,11 +1023,11 @@ extension XMLElement: CustomStringConvertible {
|
||||
// On macOS, `XMLElement` is defined in Foundation.
|
||||
// So, the code referencing `XMLElement` generates above error.
|
||||
// Following code allow to using `SWXMLhash.XMLElement` in client codes.
|
||||
extension SWXMLHash {
|
||||
public typealias XMLElement = SWXMLHashXMLElement
|
||||
extension XMLHash {
|
||||
public typealias XMLElement = XMLHashXMLElement
|
||||
}
|
||||
|
||||
public typealias SWXMLHashXMLElement = XMLElement
|
||||
public typealias XMLHashXMLElement = XMLElement
|
||||
|
||||
fileprivate extension String {
|
||||
func compare(_ str2: String?, _ insensitive: Bool) -> Bool {
|
||||
@ -918,3 +1041,72 @@ fileprivate extension String {
|
||||
return str1 == str2
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - XMLIndexer String RawRepresentables
|
||||
|
||||
/*: Provides XMLIndexer Serialization/Deserialization using String backed RawRepresentables
|
||||
Added by [PeeJWeeJ](https://github.com/PeeJWeeJ) */
|
||||
extension XMLIndexer {
|
||||
/**
|
||||
Allows for element lookup by matching attribute values
|
||||
using a String backed RawRepresentables (E.g. `String` backed `enum` cases)
|
||||
|
||||
- Note:
|
||||
Convenience for withAttribute(String, String)
|
||||
|
||||
- parameters:
|
||||
- attr: should the name of the attribute to match on
|
||||
- value: should be the value of the attribute to match on
|
||||
- throws: an XMLIndexer.XMLError if an element with the specified attribute isn't found
|
||||
- returns: instance of XMLIndexer
|
||||
*/
|
||||
public func withAttribute<A: RawRepresentable, V: RawRepresentable>(_ attr: A, _ value: V) throws -> XMLIndexer
|
||||
where A.RawValue == String, V.RawValue == String {
|
||||
try withAttribute(attr.rawValue, value.rawValue)
|
||||
}
|
||||
|
||||
/**
|
||||
Find an XML element at the current level by element name
|
||||
using a String backed RawRepresentable (E.g. `String` backed `enum` cases)
|
||||
|
||||
- Note:
|
||||
Convenience for byKey(String)
|
||||
|
||||
- parameter key: The element name to index by
|
||||
- returns: instance of XMLIndexer to match the element (or elements) found by key
|
||||
- throws: Throws an XMLIndexingError.Key if no element was found
|
||||
*/
|
||||
public func byKey<K: RawRepresentable>(_ key: K) throws -> XMLIndexer where K.RawValue == String {
|
||||
try byKey(key.rawValue)
|
||||
}
|
||||
|
||||
/**
|
||||
Find an XML element at the current level by element name
|
||||
using a String backed RawRepresentable (E.g. `String` backed `enum` cases)
|
||||
|
||||
- Note:
|
||||
Convenience for self[String]
|
||||
|
||||
- parameter key: The element name to index by
|
||||
- returns: instance of XMLIndexer to match the element (or elements) found by
|
||||
*/
|
||||
public subscript<K: RawRepresentable>(key: K) -> XMLIndexer where K.RawValue == String {
|
||||
self[key.rawValue]
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - XMLElement String RawRepresentables
|
||||
|
||||
/*: Provides XMLIndexer Serialization/Deserialization using String backed RawRepresentables
|
||||
Added by [PeeJWeeJ](https://github.com/PeeJWeeJ) */
|
||||
extension XMLElement {
|
||||
/**
|
||||
Find an attribute by name using a String backed RawRepresentable (E.g. `String` backed `enum` cases)
|
||||
|
||||
- Note:
|
||||
Convenience for self[String]
|
||||
*/
|
||||
public func attribute<N: RawRepresentable>(by name: N) -> XMLAttribute? where N.RawValue == String {
|
||||
attribute(by: name.rawValue)
|
||||
}
|
||||
}
|
259
Dependencies/SWXMLHash/SWXMLHash+TypeConversion.swift → Dependencies/SWXMLHash/XMLIndexer+XMLIndexerDeserializable.swift
vendored
Executable file → Normal file
259
Dependencies/SWXMLHash/SWXMLHash+TypeConversion.swift → Dependencies/SWXMLHash/XMLIndexer+XMLIndexerDeserializable.swift
vendored
Executable file → Normal file
@ -1,5 +1,5 @@
|
||||
//
|
||||
// SWXMLHash+TypeConversion.swift
|
||||
// XMLHash+TypeConversion.swift
|
||||
// SWXMLHash
|
||||
//
|
||||
// Copyright (c) 2016 Maciek Grzybowskio
|
||||
@ -34,6 +34,8 @@ import Foundation
|
||||
public protocol XMLIndexerDeserializable {
|
||||
/// Method for deserializing elements from XMLIndexer
|
||||
static func deserialize(_ element: XMLIndexer) throws -> Self
|
||||
/// Method for validating elements post deserialization
|
||||
func validate() throws
|
||||
}
|
||||
|
||||
/// Provides XMLIndexer deserialization / type transformation support
|
||||
@ -50,6 +52,12 @@ public extension XMLIndexerDeserializable {
|
||||
throw XMLDeserializationError.implementationIsMissing(
|
||||
method: "XMLIndexerDeserializable.deserialize(element: XMLIndexer)")
|
||||
}
|
||||
|
||||
/**
|
||||
A default do nothing implementation of validation.
|
||||
- throws: nothing
|
||||
*/
|
||||
func validate() throws {}
|
||||
}
|
||||
|
||||
// MARK: - XMLElementDeserializable
|
||||
@ -58,6 +66,8 @@ public extension XMLIndexerDeserializable {
|
||||
public protocol XMLElementDeserializable {
|
||||
/// Method for deserializing elements from XMLElement
|
||||
static func deserialize(_ element: XMLElement) throws -> Self
|
||||
/// Method for validating elements from XMLElement post deserialization
|
||||
func validate() throws
|
||||
}
|
||||
|
||||
/// Provides XMLElement deserialization / type transformation support
|
||||
@ -74,13 +84,22 @@ public extension XMLElementDeserializable {
|
||||
throw XMLDeserializationError.implementationIsMissing(
|
||||
method: "XMLElementDeserializable.deserialize(element: XMLElement)")
|
||||
}
|
||||
|
||||
/**
|
||||
A default do nothing implementation of validation.
|
||||
- throws: nothing
|
||||
*/
|
||||
func validate() throws {}
|
||||
}
|
||||
|
||||
// MARK: - XMLAttributeDeserializable
|
||||
|
||||
/// Provides XMLAttribute deserialization / type transformation support
|
||||
public protocol XMLAttributeDeserializable {
|
||||
/// Method for deserializing elements from XMLAttribute
|
||||
static func deserialize(_ attribute: XMLAttribute) throws -> Self
|
||||
/// Method for validating elements from XMLAttribute post deserialization
|
||||
func validate() throws
|
||||
}
|
||||
|
||||
/// Provides XMLAttribute deserialization / type transformation support
|
||||
@ -97,12 +116,16 @@ public extension XMLAttributeDeserializable {
|
||||
throw XMLDeserializationError.implementationIsMissing(
|
||||
method: "XMLAttributeDeserializable(element: XMLAttribute)")
|
||||
}
|
||||
/**
|
||||
A default do nothing implementation of validation.
|
||||
- throws: nothing
|
||||
*/
|
||||
func validate() throws {}
|
||||
}
|
||||
|
||||
// MARK: - XMLIndexer Extensions
|
||||
|
||||
public extension XMLIndexer {
|
||||
|
||||
// MARK: - XMLAttributeDeserializable
|
||||
|
||||
/**
|
||||
@ -216,7 +239,9 @@ public extension XMLIndexer {
|
||||
func value<T: XMLElementDeserializable>() throws -> T {
|
||||
switch self {
|
||||
case .element(let element):
|
||||
return try T.deserialize(element)
|
||||
let deserialized = try T.deserialize(element)
|
||||
try deserialized.validate()
|
||||
return deserialized
|
||||
case .stream(let opStream):
|
||||
return try opStream.findElements().value()
|
||||
default:
|
||||
@ -233,7 +258,9 @@ public extension XMLIndexer {
|
||||
func value<T: XMLElementDeserializable>() throws -> T? {
|
||||
switch self {
|
||||
case .element(let element):
|
||||
return try T.deserialize(element)
|
||||
let deserialized = try T.deserialize(element)
|
||||
try deserialized.validate()
|
||||
return deserialized
|
||||
case .stream(let opStream):
|
||||
return try opStream.findElements().value()
|
||||
default:
|
||||
@ -250,9 +277,17 @@ public extension XMLIndexer {
|
||||
func value<T: XMLElementDeserializable>() throws -> [T] {
|
||||
switch self {
|
||||
case .list(let elements):
|
||||
return try elements.map { try T.deserialize($0) }
|
||||
return try elements.map {
|
||||
let deserialized = try T.deserialize($0)
|
||||
try deserialized.validate()
|
||||
return deserialized
|
||||
}
|
||||
case .element(let element):
|
||||
return try [element].map { try T.deserialize($0) }
|
||||
return try [element].map {
|
||||
let deserialized = try T.deserialize($0)
|
||||
try deserialized.validate()
|
||||
return deserialized
|
||||
}
|
||||
case .stream(let opStream):
|
||||
return try opStream.findElements().value()
|
||||
default:
|
||||
@ -269,9 +304,17 @@ public extension XMLIndexer {
|
||||
func value<T: XMLElementDeserializable>() throws -> [T]? {
|
||||
switch self {
|
||||
case .list(let elements):
|
||||
return try elements.map { try T.deserialize($0) }
|
||||
return try elements.map {
|
||||
let deserialized = try T.deserialize($0)
|
||||
try deserialized.validate()
|
||||
return deserialized
|
||||
}
|
||||
case .element(let element):
|
||||
return try [element].map { try T.deserialize($0) }
|
||||
return try [element].map {
|
||||
let deserialized = try T.deserialize($0)
|
||||
try deserialized.validate()
|
||||
return deserialized
|
||||
}
|
||||
case .stream(let opStream):
|
||||
return try opStream.findElements().value()
|
||||
default:
|
||||
@ -288,9 +331,17 @@ public extension XMLIndexer {
|
||||
func value<T: XMLElementDeserializable>() throws -> [T?] {
|
||||
switch self {
|
||||
case .list(let elements):
|
||||
return try elements.map { try T.deserialize($0) }
|
||||
return try elements.map {
|
||||
let deserialized = try T.deserialize($0)
|
||||
try deserialized.validate()
|
||||
return deserialized
|
||||
}
|
||||
case .element(let element):
|
||||
return try [element].map { try T.deserialize($0) }
|
||||
return try [element].map {
|
||||
let deserialized = try T.deserialize($0)
|
||||
try deserialized.validate()
|
||||
return deserialized
|
||||
}
|
||||
case .stream(let opStream):
|
||||
return try opStream.findElements().value()
|
||||
default:
|
||||
@ -309,7 +360,9 @@ public extension XMLIndexer {
|
||||
func value<T: XMLIndexerDeserializable>() throws -> T {
|
||||
switch self {
|
||||
case .element:
|
||||
return try T.deserialize(self)
|
||||
let deserialized = try T.deserialize(self)
|
||||
try deserialized.validate()
|
||||
return deserialized
|
||||
case .stream(let opStream):
|
||||
return try opStream.findElements().value()
|
||||
default:
|
||||
@ -326,7 +379,9 @@ public extension XMLIndexer {
|
||||
func value<T: XMLIndexerDeserializable>() throws -> T? {
|
||||
switch self {
|
||||
case .element:
|
||||
return try T.deserialize(self)
|
||||
let deserialized = try T.deserialize(self)
|
||||
try deserialized.validate()
|
||||
return deserialized
|
||||
case .stream(let opStream):
|
||||
return try opStream.findElements().value()
|
||||
default:
|
||||
@ -343,9 +398,17 @@ public extension XMLIndexer {
|
||||
func value<T>() throws -> [T] where T: XMLIndexerDeserializable {
|
||||
switch self {
|
||||
case .list(let elements):
|
||||
return try elements.map { try T.deserialize( XMLIndexer($0) ) }
|
||||
return try elements.map {
|
||||
let deserialized = try T.deserialize( XMLIndexer($0) )
|
||||
try deserialized.validate()
|
||||
return deserialized
|
||||
}
|
||||
case .element(let element):
|
||||
return try [element].map { try T.deserialize( XMLIndexer($0) ) }
|
||||
return try [element].map {
|
||||
let deserialized = try T.deserialize( XMLIndexer($0) )
|
||||
try deserialized.validate()
|
||||
return deserialized
|
||||
}
|
||||
case .stream(let opStream):
|
||||
return try opStream.findElements().value()
|
||||
default:
|
||||
@ -362,9 +425,17 @@ public extension XMLIndexer {
|
||||
func value<T: XMLIndexerDeserializable>() throws -> [T]? {
|
||||
switch self {
|
||||
case .list(let elements):
|
||||
return try elements.map { try T.deserialize( XMLIndexer($0) ) }
|
||||
return try elements.map {
|
||||
let deserialized = try T.deserialize(XMLIndexer($0))
|
||||
try deserialized.validate()
|
||||
return deserialized
|
||||
}
|
||||
case .element(let element):
|
||||
return try [element].map { try T.deserialize( XMLIndexer($0) ) }
|
||||
return try [element].map {
|
||||
let deserialized = try T.deserialize(XMLIndexer($0))
|
||||
try deserialized.validate()
|
||||
return deserialized
|
||||
}
|
||||
case .stream(let opStream):
|
||||
return try opStream.findElements().value()
|
||||
default:
|
||||
@ -381,9 +452,17 @@ public extension XMLIndexer {
|
||||
func value<T: XMLIndexerDeserializable>() throws -> [T?] {
|
||||
switch self {
|
||||
case .list(let elements):
|
||||
return try elements.map { try T.deserialize( XMLIndexer($0) ) }
|
||||
return try elements.map {
|
||||
let deserialized = try T.deserialize(XMLIndexer($0))
|
||||
try deserialized.validate()
|
||||
return deserialized
|
||||
}
|
||||
case .element(let element):
|
||||
return try [element].map { try T.deserialize( XMLIndexer($0) ) }
|
||||
return try [element].map {
|
||||
let deserialized = try T.deserialize(XMLIndexer($0))
|
||||
try deserialized.validate()
|
||||
return deserialized
|
||||
}
|
||||
case .stream(let opStream):
|
||||
return try opStream.findElements().value()
|
||||
default:
|
||||
@ -392,10 +471,89 @@ public extension XMLIndexer {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - XMLAttributeDeserializable String RawRepresentable
|
||||
|
||||
/*: Provides XMLIndexer XMLAttributeDeserializable deserialization from String backed RawRepresentables
|
||||
Added by [PeeJWeeJ](https://github.com/PeeJWeeJ) */
|
||||
public extension XMLIndexer {
|
||||
/**
|
||||
Attempts to deserialize the value of the specified attribute of the current XMLIndexer
|
||||
element to `T` using a String backed RawRepresentable (E.g. `String` backed `enum` cases)
|
||||
|
||||
- Note:
|
||||
Convenience for value(ofAttribute: String)
|
||||
|
||||
- parameter attr: The attribute to deserialize
|
||||
- throws: an XMLDeserializationError if there is a problem with deserialization
|
||||
- returns: The deserialized `T` value
|
||||
*/
|
||||
func value<T: XMLAttributeDeserializable, A: RawRepresentable>(ofAttribute attr: A) throws -> T where A.RawValue == String {
|
||||
try value(ofAttribute: attr.rawValue)
|
||||
}
|
||||
|
||||
/**
|
||||
Attempts to deserialize the value of the specified attribute of the current XMLIndexer
|
||||
element to `T?` using a String backed RawRepresentable (E.g. `String` backed `enum` cases)
|
||||
|
||||
- Note:
|
||||
Convenience for value(ofAttribute: String)
|
||||
|
||||
- parameter attr: The attribute to deserialize
|
||||
- returns: The deserialized `T?` value, or nil if the attribute does not exist
|
||||
*/
|
||||
func value<T: XMLAttributeDeserializable, A: RawRepresentable>(ofAttribute attr: A) -> T? where A.RawValue == String {
|
||||
value(ofAttribute: attr.rawValue)
|
||||
}
|
||||
|
||||
/**
|
||||
Attempts to deserialize the value of the specified attribute of the current XMLIndexer
|
||||
element to `[T]` using a String backed RawRepresentable (E.g. `String` backed `enum` cases)
|
||||
|
||||
- Note:
|
||||
Convenience for value(ofAttribute: String)
|
||||
|
||||
- parameter attr: The attribute to deserialize
|
||||
- throws: an XMLDeserializationError if there is a problem with deserialization
|
||||
- returns: The deserialized `[T]` value
|
||||
*/
|
||||
func value<T: XMLAttributeDeserializable, A: RawRepresentable>(ofAttribute attr: A) throws -> [T] where A.RawValue == String {
|
||||
try value(ofAttribute: attr.rawValue)
|
||||
}
|
||||
|
||||
/**
|
||||
Attempts to deserialize the value of the specified attribute of the current XMLIndexer
|
||||
element to `[T]?` using a String backed RawRepresentable (E.g. `String` backed `enum` cases)
|
||||
|
||||
- Note:
|
||||
Convenience for value(ofAttribute: String)
|
||||
|
||||
- parameter attr: The attribute to deserialize
|
||||
- throws: an XMLDeserializationError if there is a problem with deserialization
|
||||
- returns: The deserialized `[T]?` value
|
||||
*/
|
||||
func value<T: XMLAttributeDeserializable, A: RawRepresentable>(ofAttribute attr: A) throws -> [T]? where A.RawValue == String {
|
||||
try value(ofAttribute: attr.rawValue)
|
||||
}
|
||||
|
||||
/**
|
||||
Attempts to deserialize the value of the specified attribute of the current XMLIndexer
|
||||
element to `[T?]` using a String backed RawRepresentable (E.g. `String` backed `enum` cases)
|
||||
|
||||
- Note:
|
||||
Convenience for value(ofAttribute: String)
|
||||
|
||||
- parameter attr: The attribute to deserialize
|
||||
- throws: an XMLDeserializationError if there is a problem with deserialization
|
||||
- returns: The deserialized `[T?]` value
|
||||
*/
|
||||
func value<T: XMLAttributeDeserializable, A: RawRepresentable>(ofAttribute attr: A) throws -> [T?] where A.RawValue == String {
|
||||
try value(ofAttribute: attr.rawValue)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - XMLElement Extensions
|
||||
|
||||
extension XMLElement {
|
||||
|
||||
/**
|
||||
Attempts to deserialize the specified attribute of the current XMLElement to `T`
|
||||
|
||||
@ -405,7 +563,9 @@ extension XMLElement {
|
||||
*/
|
||||
public func value<T: XMLAttributeDeserializable>(ofAttribute attr: String) throws -> T {
|
||||
if let attr = self.attribute(by: attr) {
|
||||
return try T.deserialize(attr)
|
||||
let deserialized = try T.deserialize(attr)
|
||||
try deserialized.validate()
|
||||
return deserialized
|
||||
} else {
|
||||
throw XMLDeserializationError.attributeDoesNotExist(element: self, attribute: attr)
|
||||
}
|
||||
@ -419,7 +579,9 @@ extension XMLElement {
|
||||
*/
|
||||
public func value<T: XMLAttributeDeserializable>(ofAttribute attr: String) -> T? {
|
||||
if let attr = self.attribute(by: attr) {
|
||||
return try? T.deserialize(attr)
|
||||
let deserialized = try? T.deserialize(attr)
|
||||
if deserialized != nil { try? deserialized?.validate() }
|
||||
return deserialized
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
@ -441,6 +603,41 @@ extension XMLElement {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: String RawRepresentable
|
||||
|
||||
/*: Provides XMLElement XMLAttributeDeserializable deserialization from String backed RawRepresentables
|
||||
Added by [PeeJWeeJ](https://github.com/PeeJWeeJ) */
|
||||
public extension XMLElement {
|
||||
/**
|
||||
Attempts to deserialize the specified attribute of the current XMLElement to `T`
|
||||
using a String backed RawRepresentable (E.g. `String` backed `enum` cases)
|
||||
|
||||
- Note:
|
||||
Convenience for value(ofAttribute: String)
|
||||
|
||||
- parameter attr: The attribute to deserialize
|
||||
- throws: an XMLDeserializationError if there is a problem with deserialization
|
||||
- returns: The deserialized `T` value
|
||||
*/
|
||||
func value<T: XMLAttributeDeserializable, A: RawRepresentable>(ofAttribute attr: A) throws -> T where A.RawValue == String {
|
||||
try value(ofAttribute: attr.rawValue)
|
||||
}
|
||||
|
||||
/**
|
||||
Attempts to deserialize the specified attribute of the current XMLElement to `T?`
|
||||
using a String backed RawRepresentable (E.g. `String` backed `enum` cases)
|
||||
|
||||
- Note:
|
||||
Convenience for value(ofAttribute: String)
|
||||
|
||||
- parameter attr: The attribute to deserialize
|
||||
- returns: The deserialized `T?` value, or nil if the attribute does not exist.
|
||||
*/
|
||||
func value<T: XMLAttributeDeserializable, A: RawRepresentable>(ofAttribute attr: A) -> T? where A.RawValue == String {
|
||||
value(ofAttribute: attr.rawValue)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - XMLDeserializationError
|
||||
|
||||
/// The error that is thrown if there is a problem with deserialization
|
||||
@ -484,11 +681,11 @@ public enum XMLDeserializationError: Error, CustomStringConvertible {
|
||||
return "This node is invalid: \(node)"
|
||||
case .nodeHasNoValue:
|
||||
return "This node is empty"
|
||||
case .typeConversionFailed(let type, let node):
|
||||
case let .typeConversionFailed(type, node):
|
||||
return "Can't convert node \(node) to value of type \(type)"
|
||||
case .attributeDoesNotExist(let element, let attribute):
|
||||
case let .attributeDoesNotExist(element, attribute):
|
||||
return "Element \(element) does not contain attribute: \(attribute)"
|
||||
case .attributeDeserializationFailed(let type, let attribute):
|
||||
case let .attributeDeserializationFailed(type, attribute):
|
||||
return "Can't convert attribute \(attribute) to value of type \(type)"
|
||||
}
|
||||
}
|
||||
@ -506,7 +703,7 @@ extension String: XMLElementDeserializable, XMLAttributeDeserializable {
|
||||
- returns: the deserialized String value
|
||||
*/
|
||||
public static func deserialize(_ element: XMLElement) -> String {
|
||||
return element.text
|
||||
element.text
|
||||
}
|
||||
|
||||
/**
|
||||
@ -516,8 +713,10 @@ extension String: XMLElementDeserializable, XMLAttributeDeserializable {
|
||||
- returns: the deserialized String value
|
||||
*/
|
||||
public static func deserialize(_ attribute: XMLAttribute) -> String {
|
||||
return attribute.text
|
||||
attribute.text
|
||||
}
|
||||
|
||||
public func validate() {}
|
||||
}
|
||||
|
||||
extension Int: XMLElementDeserializable, XMLAttributeDeserializable {
|
||||
@ -551,6 +750,8 @@ extension Int: XMLElementDeserializable, XMLAttributeDeserializable {
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
public func validate() {}
|
||||
}
|
||||
|
||||
extension Double: XMLElementDeserializable, XMLAttributeDeserializable {
|
||||
@ -584,6 +785,8 @@ extension Double: XMLElementDeserializable, XMLAttributeDeserializable {
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
public func validate() {}
|
||||
}
|
||||
|
||||
extension Float: XMLElementDeserializable, XMLAttributeDeserializable {
|
||||
@ -617,6 +820,8 @@ extension Float: XMLElementDeserializable, XMLAttributeDeserializable {
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
public func validate() {}
|
||||
}
|
||||
|
||||
extension Bool: XMLElementDeserializable, XMLAttributeDeserializable {
|
||||
@ -649,4 +854,6 @@ extension Bool: XMLElementDeserializable, XMLAttributeDeserializable {
|
||||
return value
|
||||
}
|
||||
// swiftlint:enable line_length
|
||||
|
||||
public func validate() {}
|
||||
}
|
36
Dependencies/SWXMLHash/shim.swift
vendored
Normal file
36
Dependencies/SWXMLHash/shim.swift
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
//
|
||||
// shim.swift
|
||||
// SWXMLHash
|
||||
//
|
||||
// Copyright (c) 2018 David Mohundro
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
#if (!swift(>=4.1) && swift(>=4.0)) || !swift(>=3.3)
|
||||
|
||||
extension Sequence {
|
||||
func compactMap<ElementOfResult>(
|
||||
_ transform: (Self.Element
|
||||
) throws -> ElementOfResult?) rethrows -> [ElementOfResult] {
|
||||
try flatMap(transform)
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -147,15 +147,12 @@
|
||||
5713C4F51E5AE2C300BBA4D9 /* CombineAnimationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5713C4F41E5AE2C300BBA4D9 /* CombineAnimationTests.swift */; };
|
||||
5713C4F71E5C34C700BBA4D9 /* SequenceAnimationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5713C4F61E5C34C700BBA4D9 /* SequenceAnimationTests.swift */; };
|
||||
5713C4F91E5C3FEE00BBA4D9 /* DelayedAnimationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5713C4F81E5C3FEE00BBA4D9 /* DelayedAnimationTests.swift */; };
|
||||
572CEFC71E2CED4B008C7C83 /* SWXMLHash+TypeConversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 572CEFC51E2CED4B008C7C83 /* SWXMLHash+TypeConversion.swift */; };
|
||||
572CEFC81E2CED4B008C7C83 /* SWXMLHash.swift in Sources */ = {isa = PBXBuildFile; fileRef = 572CEFC61E2CED4B008C7C83 /* SWXMLHash.swift */; };
|
||||
57614AFD1F83D15600875933 /* Group.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E5E1381E3B393900D1CB28 /* Group.swift */; };
|
||||
57614AFE1F83D15600875933 /* TextRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E5E1441E3B393900D1CB28 /* TextRenderer.swift */; };
|
||||
57614AFF1F83D15600875933 /* CGFloat+Double.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E5E14D1E3B393900D1CB28 /* CGFloat+Double.swift */; };
|
||||
57614B021F83D15600875933 /* RoundRect.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E5E1341E3B393900D1CB28 /* RoundRect.swift */; };
|
||||
57614B031F83D15600875933 /* UIImage2Image.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57900FF81EA0DEBF00809FFB /* UIImage2Image.swift */; };
|
||||
57614B041F83D15600875933 /* SVGParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E5E1471E3B393900D1CB28 /* SVGParser.swift */; };
|
||||
57614B051F83D15600875933 /* SWXMLHash.swift in Sources */ = {isa = PBXBuildFile; fileRef = 572CEFC61E2CED4B008C7C83 /* SWXMLHash.swift */; };
|
||||
57614B071F83D15600875933 /* RenderUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E5E1421E3B393900D1CB28 /* RenderUtils.swift */; };
|
||||
57614B081F83D15600875933 /* FuncBounds.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E5E0F11E3B393900D1CB28 /* FuncBounds.swift */; };
|
||||
57614B0A1F83D15600875933 /* DoubleInterpolation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E5E0EC1E3B393900D1CB28 /* DoubleInterpolation.swift */; };
|
||||
@ -234,7 +231,6 @@
|
||||
57614B671F83D15600875933 /* ContentsInterpolation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57A27BCE1E44C4EC0057BD3A /* ContentsInterpolation.swift */; };
|
||||
57614B681F83D15600875933 /* GroupRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E5E13E1E3B393900D1CB28 /* GroupRenderer.swift */; };
|
||||
57614B6B1F83D15600875933 /* NSTimer+Closure.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E5E14E1E3B393900D1CB28 /* NSTimer+Closure.swift */; };
|
||||
57614B6C1F83D15600875933 /* SWXMLHash+TypeConversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 572CEFC51E2CED4B008C7C83 /* SWXMLHash+TypeConversion.swift */; };
|
||||
57614B6D1F83D15600875933 /* AnimationSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E5E0FF1E3B393900D1CB28 /* AnimationSequence.swift */; };
|
||||
57614B6E1F83D15600875933 /* MorphingGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E5E0FB1E3B393900D1CB28 /* MorphingGenerator.swift */; };
|
||||
57614B6F1F83D15600875933 /* SVGConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E5E1461E3B393900D1CB28 /* SVGConstants.swift */; };
|
||||
@ -681,6 +677,12 @@
|
||||
A7B47E44230EA402009DD7E5 /* Graphics_iOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = A718CD451F45C28700966E06 /* Graphics_iOS.swift */; };
|
||||
A7B47E45230EA404009DD7E5 /* Common_iOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = A718CD431F45C28200966E06 /* Common_iOS.swift */; };
|
||||
A7E675561EC4213500BD9ECB /* NodeBoundsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7E675551EC4213500BD9ECB /* NodeBoundsTests.swift */; };
|
||||
A7F46DE0270B0EE8008DA1DF /* XMLHash.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7F46DDD270B0EE8008DA1DF /* XMLHash.swift */; };
|
||||
A7F46DE1270B0EE8008DA1DF /* XMLHash.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7F46DDD270B0EE8008DA1DF /* XMLHash.swift */; };
|
||||
A7F46DE2270B0EE8008DA1DF /* shim.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7F46DDE270B0EE8008DA1DF /* shim.swift */; };
|
||||
A7F46DE3270B0EE8008DA1DF /* shim.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7F46DDE270B0EE8008DA1DF /* shim.swift */; };
|
||||
A7F46DE4270B0EE8008DA1DF /* XMLIndexer+XMLIndexerDeserializable.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7F46DDF270B0EE8008DA1DF /* XMLIndexer+XMLIndexerDeserializable.swift */; };
|
||||
A7F46DE5270B0EE8008DA1DF /* XMLIndexer+XMLIndexerDeserializable.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7F46DDF270B0EE8008DA1DF /* XMLIndexer+XMLIndexerDeserializable.swift */; };
|
||||
C410148E1F834D290022EE44 /* style.svg in Resources */ = {isa = PBXBuildFile; fileRef = C410148D1F834D280022EE44 /* style.svg */; };
|
||||
C4153A8F1F8793DE001BA5EE /* small-logo.png in Resources */ = {isa = PBXBuildFile; fileRef = C4153A8E1F8793DD001BA5EE /* small-logo.png */; };
|
||||
C46E83551F94B20E00208037 /* transform.svg in Resources */ = {isa = PBXBuildFile; fileRef = C46E83541F94B20E00208037 /* transform.svg */; };
|
||||
@ -859,8 +861,6 @@
|
||||
5713C4F41E5AE2C300BBA4D9 /* CombineAnimationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CombineAnimationTests.swift; sourceTree = "<group>"; };
|
||||
5713C4F61E5C34C700BBA4D9 /* SequenceAnimationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SequenceAnimationTests.swift; sourceTree = "<group>"; };
|
||||
5713C4F81E5C3FEE00BBA4D9 /* DelayedAnimationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DelayedAnimationTests.swift; sourceTree = "<group>"; };
|
||||
572CEFC51E2CED4B008C7C83 /* SWXMLHash+TypeConversion.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SWXMLHash+TypeConversion.swift"; sourceTree = "<group>"; };
|
||||
572CEFC61E2CED4B008C7C83 /* SWXMLHash.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SWXMLHash.swift; sourceTree = "<group>"; };
|
||||
57614B791F83D15600875933 /* MacawOSX.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MacawOSX.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
57614BD91F8739EE00875933 /* MacawView+PDF.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MacawView+PDF.swift"; sourceTree = "<group>"; };
|
||||
57900FF81EA0DEBF00809FFB /* UIImage2Image.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIImage2Image.swift; sourceTree = "<group>"; };
|
||||
@ -1260,6 +1260,9 @@
|
||||
A74C832B229FB7690085A832 /* color-prop-04-t-manual-osx.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "color-prop-04-t-manual-osx.svg"; sourceTree = "<group>"; };
|
||||
A74C832D229FBA4C0085A832 /* color-prop-04-t-manual-osx.reference */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "color-prop-04-t-manual-osx.reference"; sourceTree = "<group>"; };
|
||||
A7E675551EC4213500BD9ECB /* NodeBoundsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NodeBoundsTests.swift; path = Bounds/NodeBoundsTests.swift; sourceTree = "<group>"; };
|
||||
A7F46DDD270B0EE8008DA1DF /* XMLHash.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XMLHash.swift; sourceTree = "<group>"; };
|
||||
A7F46DDE270B0EE8008DA1DF /* shim.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = shim.swift; sourceTree = "<group>"; };
|
||||
A7F46DDF270B0EE8008DA1DF /* XMLIndexer+XMLIndexerDeserializable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "XMLIndexer+XMLIndexerDeserializable.swift"; sourceTree = "<group>"; };
|
||||
C410148D1F834D280022EE44 /* style.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = style.svg; sourceTree = "<group>"; };
|
||||
C4153A8E1F8793DD001BA5EE /* small-logo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "small-logo.png"; sourceTree = "<group>"; };
|
||||
C43B064C1F9738EF00787A35 /* clip.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = clip.svg; sourceTree = "<group>"; };
|
||||
@ -1448,8 +1451,9 @@
|
||||
572CEFC41E2CED4B008C7C83 /* SWXMLHash */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
572CEFC51E2CED4B008C7C83 /* SWXMLHash+TypeConversion.swift */,
|
||||
572CEFC61E2CED4B008C7C83 /* SWXMLHash.swift */,
|
||||
A7F46DDE270B0EE8008DA1DF /* shim.swift */,
|
||||
A7F46DDD270B0EE8008DA1DF /* XMLHash.swift */,
|
||||
A7F46DDF270B0EE8008DA1DF /* XMLIndexer+XMLIndexerDeserializable.swift */,
|
||||
);
|
||||
path = SWXMLHash;
|
||||
sourceTree = "<group>";
|
||||
@ -2697,7 +2701,6 @@
|
||||
5B6E194020AC58F900454E7E /* Stroke.swift in Sources */,
|
||||
57614B041F83D15600875933 /* SVGParser.swift in Sources */,
|
||||
A7B47E42230EA3FC009DD7E5 /* MDisplayLink_iOS.swift in Sources */,
|
||||
57614B051F83D15600875933 /* SWXMLHash.swift in Sources */,
|
||||
57614B071F83D15600875933 /* RenderUtils.swift in Sources */,
|
||||
57614B081F83D15600875933 /* FuncBounds.swift in Sources */,
|
||||
57614B0A1F83D15600875933 /* DoubleInterpolation.swift in Sources */,
|
||||
@ -2738,6 +2741,7 @@
|
||||
5B6E193020AC58F900454E7E /* LinearGradient.swift in Sources */,
|
||||
57614B261F83D15600875933 /* ShapeAnimation.swift in Sources */,
|
||||
57614B271F83D15600875933 /* TransformInterpolation.swift in Sources */,
|
||||
A7F46DE1270B0EE8008DA1DF /* XMLHash.swift in Sources */,
|
||||
57614B281F83D15600875933 /* ShapeAnimationGenerator.swift in Sources */,
|
||||
57614B291F83D15600875933 /* AnimationUtils.swift in Sources */,
|
||||
57614B2A1F83D15600875933 /* Polygon.swift in Sources */,
|
||||
@ -2776,6 +2780,7 @@
|
||||
30FF496D215CF27E00FF653C /* MCAShapeLayerLineCap_macOS.swift in Sources */,
|
||||
57614B491F83D15600875933 /* MView_macOS.swift in Sources */,
|
||||
A7B47E3F230EA3F5009DD7E5 /* MCAShapeLayerLineCap_iOS.swift in Sources */,
|
||||
A7F46DE3270B0EE8008DA1DF /* shim.swift in Sources */,
|
||||
5B6E192E20AC58F900454E7E /* Font.swift in Sources */,
|
||||
5BFEF5D120B80A83008DAC11 /* ColorMatrixEffect.swift in Sources */,
|
||||
57614B4A1F83D15600875933 /* Easing.swift in Sources */,
|
||||
@ -2810,6 +2815,7 @@
|
||||
5B9B970D2486506C00CAF2CE /* PathAnimationGenerator.swift in Sources */,
|
||||
57614B631F83D15600875933 /* Insets.swift in Sources */,
|
||||
3081E77E20DB58B100640F96 /* DescriptionExtensions.swift in Sources */,
|
||||
A7F46DE5270B0EE8008DA1DF /* XMLIndexer+XMLIndexerDeserializable.swift in Sources */,
|
||||
57614B641F83D15600875933 /* Rect.swift in Sources */,
|
||||
30FF4971215CF4CE00FF653C /* MCAMediaTimingFunctionName_macOS.swift in Sources */,
|
||||
57614B651F83D15600875933 /* PathBuilder.swift in Sources */,
|
||||
@ -2820,7 +2826,6 @@
|
||||
5B6E192A20AC58F900454E7E /* Align.swift in Sources */,
|
||||
57614B6B1F83D15600875933 /* NSTimer+Closure.swift in Sources */,
|
||||
5B6E193620AC58F900454E7E /* Stop.swift in Sources */,
|
||||
57614B6C1F83D15600875933 /* SWXMLHash+TypeConversion.swift in Sources */,
|
||||
57614B6D1F83D15600875933 /* AnimationSequence.swift in Sources */,
|
||||
5B1A8C7720A15F7300E5FFAE /* SVGNodeLayout.swift in Sources */,
|
||||
57614B6E1F83D15600875933 /* MorphingGenerator.swift in Sources */,
|
||||
@ -2842,7 +2847,6 @@
|
||||
57900FF91EA0DEBF00809FFB /* UIImage2Image.swift in Sources */,
|
||||
57E5E1AB1E3B393900D1CB28 /* SVGParser.swift in Sources */,
|
||||
5B6E193F20AC58F900454E7E /* Stroke.swift in Sources */,
|
||||
572CEFC81E2CED4B008C7C83 /* SWXMLHash.swift in Sources */,
|
||||
57E5E1A71E3B393900D1CB28 /* RenderUtils.swift in Sources */,
|
||||
57E5E1601E3B393900D1CB28 /* FuncBounds.swift in Sources */,
|
||||
A718CD481F45C28700966E06 /* MView_iOS.swift in Sources */,
|
||||
@ -2884,6 +2888,7 @@
|
||||
57A27BD31E44C5570057BD3A /* ShapeAnimationGenerator.swift in Sources */,
|
||||
57E5E1571E3B393900D1CB28 /* AnimationUtils.swift in Sources */,
|
||||
30FF496F215CF3B000FF653C /* MCAMediaTimingFunctionName_iOS.swift in Sources */,
|
||||
A7F46DE0270B0EE8008DA1DF /* XMLHash.swift in Sources */,
|
||||
57E5E1981E3B393900D1CB28 /* Polygon.swift in Sources */,
|
||||
57E5E1701E3B393900D1CB28 /* TransformAnimation.swift in Sources */,
|
||||
57E5E16C1E3B393900D1CB28 /* CombineAnimation.swift in Sources */,
|
||||
@ -2922,6 +2927,7 @@
|
||||
5BFEF5CE20B80A83008DAC11 /* BlendEffect.swift in Sources */,
|
||||
A718CD501F45C28F00966E06 /* MView_macOS.swift in Sources */,
|
||||
57E5E1581E3B393900D1CB28 /* Easing.swift in Sources */,
|
||||
A7F46DE2270B0EE8008DA1DF /* shim.swift in Sources */,
|
||||
5BFEF5D020B80A83008DAC11 /* ColorMatrixEffect.swift in Sources */,
|
||||
5B6E192D20AC58F900454E7E /* Font.swift in Sources */,
|
||||
57E5E1971E3B393900D1CB28 /* Point.swift in Sources */,
|
||||
@ -2956,6 +2962,7 @@
|
||||
3081E77D20DB58B100640F96 /* DescriptionExtensions.swift in Sources */,
|
||||
57E5E19A1E3B393900D1CB28 /* Rect.swift in Sources */,
|
||||
57E5E1941E3B393900D1CB28 /* PathBuilder.swift in Sources */,
|
||||
A7F46DE4270B0EE8008DA1DF /* XMLIndexer+XMLIndexerDeserializable.swift in Sources */,
|
||||
57E5E1761E3B393900D1CB28 /* PinchEvent.swift in Sources */,
|
||||
57A27BCF1E44C4EC0057BD3A /* ContentsInterpolation.swift in Sources */,
|
||||
57E5E1A31E3B393900D1CB28 /* GroupRenderer.swift in Sources */,
|
||||
@ -2964,7 +2971,6 @@
|
||||
57E5E1B11E3B393900D1CB28 /* NSTimer+Closure.swift in Sources */,
|
||||
30FF4962215CE97300FF653C /* MCAMediaTimingFillMode_iOS.swift in Sources */,
|
||||
5B6E193520AC58F900454E7E /* Stop.swift in Sources */,
|
||||
572CEFC71E2CED4B008C7C83 /* SWXMLHash+TypeConversion.swift in Sources */,
|
||||
30FF496B215CF0ED00FF653C /* MCAShapeLayerLineCap_iOS.swift in Sources */,
|
||||
5BECDC7B222FE6DE009C8E6A /* PathAnimation.swift in Sources */,
|
||||
57E5E16B1E3B393900D1CB28 /* AnimationSequence.swift in Sources */,
|
||||
|
@ -69,7 +69,7 @@ class CSSParser {
|
||||
return .byTag(text)
|
||||
}
|
||||
|
||||
func getStyles(element: SWXMLHash.XMLElement) -> [String: String] {
|
||||
func getStyles(element: XMLHash.XMLElement) -> [String: String] {
|
||||
var styleAttributes = [String: String]()
|
||||
|
||||
if let styles = stylesByTag[element.name] {
|
||||
|
@ -133,12 +133,12 @@ open class SVGParser {
|
||||
}
|
||||
|
||||
fileprivate func parse() throws -> Group {
|
||||
let config = SWXMLHash.config { config in
|
||||
let config = XMLHash.config { config in
|
||||
config.shouldProcessNamespaces = true
|
||||
}
|
||||
let parsedXml = config.parse(xmlString)
|
||||
|
||||
var svgElement: SWXMLHash.XMLElement?
|
||||
var svgElement: XMLHash.XMLElement?
|
||||
for child in parsedXml.children {
|
||||
if let element = child.element {
|
||||
if element.name == "svg" {
|
||||
@ -203,7 +203,7 @@ open class SVGParser {
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func parseViewBox(_ element: SWXMLHash.XMLElement) throws -> SVGNodeLayout? {
|
||||
fileprivate func parseViewBox(_ element: XMLHash.XMLElement) throws -> SVGNodeLayout? {
|
||||
let widthAttributeNil = element.allAttributes["width"] == nil
|
||||
let heightAttributeNil = element.allAttributes["height"] == nil
|
||||
let viewBoxAttributeNil = element.allAttributes["viewBox"] == nil
|
||||
@ -508,7 +508,7 @@ open class SVGParser {
|
||||
return Group(contents: groupNodes, place: getPosition(element), tag: getTag(element))
|
||||
}
|
||||
|
||||
fileprivate func getPosition(_ element: SWXMLHash.XMLElement) -> Transform {
|
||||
fileprivate func getPosition(_ element: XMLHash.XMLElement) -> Transform {
|
||||
guard let transformAttribute = element.allAttributes["transform"]?.text else {
|
||||
return Transform.identity
|
||||
}
|
||||
@ -666,7 +666,7 @@ open class SVGParser {
|
||||
}
|
||||
|
||||
fileprivate func getStyleAttributes(_ groupAttributes: [String: String],
|
||||
element: SWXMLHash.XMLElement) -> [String: String] {
|
||||
element: XMLHash.XMLElement) -> [String: String] {
|
||||
var styleAttributes: [String: String] = groupAttributes
|
||||
|
||||
for (att, val) in styles.getStyles(element: element) {
|
||||
@ -876,7 +876,7 @@ open class SVGParser {
|
||||
return dashes
|
||||
}
|
||||
|
||||
fileprivate func getMatrix(_ element: SWXMLHash.XMLElement, attribute: String) -> [Double] {
|
||||
fileprivate func getMatrix(_ element: XMLHash.XMLElement, attribute: String) -> [Double] {
|
||||
var result = [Double]()
|
||||
if let values = element.allAttributes[attribute]?.text {
|
||||
let separatedValues = values.components(separatedBy: CharacterSet(charactersIn: " ,"))
|
||||
@ -896,7 +896,7 @@ open class SVGParser {
|
||||
return 0
|
||||
}
|
||||
|
||||
fileprivate func getTag(_ element: SWXMLHash.XMLElement) -> [String] {
|
||||
fileprivate func getTag(_ element: XMLHash.XMLElement) -> [String] {
|
||||
let id = element.allAttributes["id"]?.text
|
||||
return id.map { [$0] } ?? []
|
||||
}
|
||||
@ -1081,7 +1081,7 @@ open class SVGParser {
|
||||
return Align.min
|
||||
}
|
||||
|
||||
fileprivate func parseSimpleText(_ text: SWXMLHash.XMLElement,
|
||||
fileprivate func parseSimpleText(_ text: XMLHash.XMLElement,
|
||||
textAnchor: String?,
|
||||
fill: Fill?,
|
||||
stroke: Stroke?,
|
||||
@ -1156,7 +1156,7 @@ open class SVGParser {
|
||||
baseline: .alphabetic,
|
||||
place: place,
|
||||
opacity: opacity)
|
||||
} else if let tspanElement = element as? SWXMLHash.XMLElement,
|
||||
} else if let tspanElement = element as? XMLHash.XMLElement,
|
||||
tspanElement.name == "tspan" {
|
||||
// parse as <tspan> element
|
||||
// ultimately skip it if it cannot be parsed
|
||||
@ -1187,7 +1187,7 @@ open class SVGParser {
|
||||
return collection
|
||||
}
|
||||
|
||||
fileprivate func parseTspan(_ element: SWXMLHash.XMLElement,
|
||||
fileprivate func parseTspan(_ element: XMLHash.XMLElement,
|
||||
withWhitespace: Bool = false,
|
||||
textAnchor: String?,
|
||||
fill: Fill?,
|
||||
@ -1242,7 +1242,7 @@ open class SVGParser {
|
||||
weight: getFontWeight(attributes) ?? fontWeight ?? "normal")
|
||||
}
|
||||
|
||||
fileprivate func getTspanPosition(_ element: SWXMLHash.XMLElement,
|
||||
fileprivate func getTspanPosition(_ element: XMLHash.XMLElement,
|
||||
bounds: Rect,
|
||||
previousCollectedTspan: Node?,
|
||||
withWhitespace: inout Bool) -> Transform {
|
||||
@ -1653,14 +1653,14 @@ open class SVGParser {
|
||||
return .none
|
||||
}
|
||||
|
||||
fileprivate func getDoubleValue(_ element: SWXMLHash.XMLElement, attribute: String) -> Double? {
|
||||
fileprivate func getDoubleValue(_ element: XMLHash.XMLElement, attribute: String) -> Double? {
|
||||
guard let attributeValue = element.allAttributes[attribute]?.text else {
|
||||
return .none
|
||||
}
|
||||
return doubleFromString(attributeValue)
|
||||
}
|
||||
|
||||
fileprivate func getDimensionValue(_ element: SWXMLHash.XMLElement, attribute: String) -> SVGLength? {
|
||||
fileprivate func getDimensionValue(_ element: XMLHash.XMLElement, attribute: String) -> SVGLength? {
|
||||
guard let attributeValue = element.allAttributes[attribute]?.text else {
|
||||
return .none
|
||||
}
|
||||
@ -1701,7 +1701,7 @@ open class SVGParser {
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func getDoubleValueFromPercentage(_ element: SWXMLHash.XMLElement, attribute: String) -> Double? {
|
||||
fileprivate func getDoubleValueFromPercentage(_ element: XMLHash.XMLElement, attribute: String) -> Double? {
|
||||
guard let attributeValue = element.allAttributes[attribute]?.text else {
|
||||
return .none
|
||||
}
|
||||
@ -1716,7 +1716,7 @@ open class SVGParser {
|
||||
return .none
|
||||
}
|
||||
|
||||
fileprivate func getIntValue(_ element: SWXMLHash.XMLElement, attribute: String) -> Int? {
|
||||
fileprivate func getIntValue(_ element: XMLHash.XMLElement, attribute: String) -> Int? {
|
||||
if let attributeValue = element.allAttributes[attribute]?.text {
|
||||
if let doubleValue = Double(attributeValue) {
|
||||
return Int(doubleValue)
|
||||
|
Loading…
Reference in New Issue
Block a user