Skip to content

Commit

Permalink
Adding full metadata parsing support
Browse files Browse the repository at this point in the history
Includes author, copyright, email parsings through GPXParser.

Fix #18
  • Loading branch information
vincentneo committed Feb 12, 2019
1 parent ba3d9e1 commit 337156a
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 8 deletions.
5 changes: 5 additions & 0 deletions Classes/GPXAuthor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ open class GPXAuthor: GPXPerson {
super.init()
}

override init(dictionary: [String : String]) {
super.init()
self.name = dictionary["name"]
}

// MARK: Tag

override func tagName() -> String {
Expand Down
41 changes: 41 additions & 0 deletions Classes/GPXCopyright.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ open class GPXCopyright: GPXElement {
self.author = author
}

init(dictionary: [String : String]) {
super.init()
self.year = CopyrightYearParser.parse(dictionary["year"])
self.license = dictionary["license"]
self.author = dictionary["author"]
}

// MARK: Tag

override func tagName() -> String {
Expand All @@ -48,3 +55,37 @@ open class GPXCopyright: GPXElement {
self.addProperty(forValue: license, gpx: gpx, tagName: "license", indentationLevel: indentationLevel)
}
}

// MARK:- Year Parser
// code from http://jordansmith.io/performant-date-parsing/
// edited for use in CoreGPX

fileprivate class CopyrightYearParser {

private static var calendarCache = [Int : Calendar]()
private static var components = DateComponents()

private static let year = UnsafeMutablePointer<Int>.allocate(capacity: 1)

static func parse(_ yearString: String?) -> Date? {
guard let NonNilString = yearString else {
return nil
}

_ = withVaList([year], { pointer in
vsscanf(NonNilString, "%d", pointer)

})

components.year = year.pointee

if let calendar = calendarCache[0] {
return calendar.date(from: components)
}

var calendar = Calendar(identifier: .gregorian)
calendar.timeZone = TimeZone(secondsFromGMT: 0)!
calendarCache[0] = calendar
return calendar.date(from: components)
}
}
5 changes: 5 additions & 0 deletions Classes/GPXEmail.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ open class GPXEmail: GPXElement {
self.domain = domain
}

init(dictionary: [String : String]) {
self.emailID = dictionary["id"]
self.domain = dictionary["domain"]
}

// MARK:- Tag
override func tagName() -> String {
return "email"
Expand Down
92 changes: 87 additions & 5 deletions Classes/GPXParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,16 @@ open class GPXParser: NSObject, XMLParserDelegate {
var trackpointDict = [String : String]()
var routeDict = [String : String]()
var routepointDict = [String : String]()
var metadataDict = [String : String]()
var extensionsDict = [String : String]()

var linkDict = [String : String]()
var extensionsDict = [String : String]()

// metadata types
var metadataDict = [String : String]()
var boundsDict = [String : String]()
var authorDict = [String : String]()
var emailDict = [String : String]()
var copyrightDict = [String : String]()


var metadata: GPXMetadata?
Expand All @@ -92,8 +97,16 @@ open class GPXParser: NSObject, XMLParserDelegate {

var isLink = false
var elementHasLink = false

// for metadata
var isBounds = false
var elementHasBounds = false
var isAuthor = false
var elementHasAuthor = false
var isEmail = false
var elementHasEmail = false
var isCopyright = false
var elementHasCopyright = false

public func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {

Expand Down Expand Up @@ -125,12 +138,21 @@ open class GPXParser: NSObject, XMLParserDelegate {
case "link":
isLink = true
linkDict["href"] = attributeDict["href"]

// for metadata
case "bounds":
isBounds = true
boundsDict["minlon"] = attributeDict["minlon"]
boundsDict["maxlon"] = attributeDict["maxlon"]
boundsDict["minlat"] = attributeDict["minlat"]
boundsDict["maxlat"] = attributeDict["maxlat"]
case "author":
isAuthor = true
case "email":
isEmail = true
case "copyright":
isCopyright = true
copyrightDict["author"] = attributeDict["author"]
default:
break
}
Expand Down Expand Up @@ -179,12 +201,26 @@ open class GPXParser: NSObject, XMLParserDelegate {
}
}
if isMetadata {
if isLink {
if isLink && !isAuthor {
linkDict[element] = foundString
}
if isBounds {
// do nothing
}
if isAuthor {
if isLink {
linkDict[element] = foundString
}
else {
if isEmail {
emailDict[element] = foundString
}
authorDict[element] = foundString
}
}
if isCopyright {
copyrightDict[element] = foundString
}
else {
metadataDict[element] = foundString
}
Expand All @@ -201,7 +237,7 @@ open class GPXParser: NSObject, XMLParserDelegate {
switch elementName {
case "metadata":
self.metadata = GPXMetadata(dictionary: metadataDict)
if elementHasLink {
if elementHasLink && !elementHasAuthor {
self.metadata?.link = GPXLink(dictionary: linkDict)

// clear values
Expand All @@ -211,10 +247,39 @@ open class GPXParser: NSObject, XMLParserDelegate {
if elementHasBounds {
self.metadata?.bounds = GPXBounds(dictionary: boundsDict)

//clear values
// clear values
boundsDict.removeAll()
elementHasBounds = false
}
if elementHasAuthor {
let author = GPXAuthor(dictionary: authorDict)
if elementHasLink {
author.link = GPXLink(dictionary: linkDict)

// clear values
linkDict.removeAll()
elementHasLink = false
}
if elementHasEmail {
author.email = GPXEmail(dictionary: emailDict)

// clear values
emailDict.removeAll()
elementHasEmail = false
}
self.metadata?.author = author

// clear values
authorDict.removeAll()
elementHasAuthor = false
}
if elementHasCopyright {
self.metadata?.copyright = GPXCopyright(dictionary: copyrightDict)

// clear values
copyrightDict.removeAll()
elementHasCopyright = false
}

// clear values
isMetadata = false
Expand Down Expand Up @@ -315,6 +380,23 @@ open class GPXParser: NSObject, XMLParserDelegate {
// clear values
isBounds = false

case "author":
elementHasAuthor = true

// clear values
isAuthor = false

case "email":
elementHasEmail = true

// clear values
isEmail = false

case "copyright":
elementHasCopyright = true

// clear values
isCopyright = false
default:
break
}
Expand Down
7 changes: 6 additions & 1 deletion Classes/GPXPerson.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import Foundation

open class GPXPerson: GPXElement {

var name: String
var name: String?
var email: GPXEmail?
var link: GPXLink?

Expand All @@ -22,6 +22,11 @@ open class GPXPerson: GPXElement {
super.init()
}

init(dictionary: [String : String]) {
name = dictionary["name"]
super.init()
}

// MARK:- Public Methods


Expand Down
4 changes: 2 additions & 2 deletions Classes/GPXWaypoint.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,14 @@ open class GPXWaypoint: GPXElement {

// MARK:- Public Methods

private func number(from string: String?) -> Double? {
func number(from string: String?) -> Double? {
guard let NonNilString = string else {
return nil
}
return Double(NonNilString)
}

private func integer(from string: String?) -> Int? {
func integer(from string: String?) -> Int? {
guard let NonNilString = string else {
return nil
}
Expand Down

0 comments on commit 337156a

Please sign in to comment.