diff --git a/Sources/GPXKit/GPXFileParser.swift b/Sources/GPXKit/GPXFileParser.swift
index c0d5d19..aaa027d 100644
--- a/Sources/GPXKit/GPXFileParser.swift
+++ b/Sources/GPXKit/GPXFileParser.swift
@@ -17,6 +17,7 @@ public enum GPXParserError: Error, Equatable {
internal enum GPXTags: String {
case gpx
case metadata
+ case waypoint = "wpt"
case time
case track = "trk"
case name
@@ -27,6 +28,7 @@ internal enum GPXTags: String {
case power
case description = "desc"
case keywords
+ case comment = "cmt"
}
internal enum GPXAttributes: String {
@@ -72,6 +74,7 @@ final public class GPXFileParser {
}
return GPXTrack(
date: node.childFor(.metadata)?.childFor(.time)?.date,
+ waypoints: parseWaypoints(node.childrenOfType(.waypoint)),
title: title,
description: trackNode.childFor(.description)?.content,
trackPoints: parseSegment(trackNode.childFor(.trackSegment)),
@@ -80,6 +83,11 @@ final public class GPXFileParser {
)
}
+ private func parseWaypoints(_ nodes: [XMLNode]) -> [Waypoint]? {
+ guard !nodes.isEmpty else { return nil }
+ return nodes.compactMap { Waypoint.init($0) ?? nil }
+ }
+
private func parseKeywords(node: XMLNode) -> [String] {
node.childFor(.metadata)?
.childFor(.keywords)?
@@ -150,6 +158,24 @@ final public class GPXFileParser {
}
}
+internal extension Waypoint {
+ init?(_ waypointNode: XMLNode) {
+ guard let lat = waypointNode.latitude,
+ let lon = waypointNode.longitude
+ else {
+ return nil
+ }
+ self.coordinate = Coordinate(
+ latitude: lat,
+ longitude: lon
+ )
+ self.date = waypointNode.childFor(.time)?.date
+ self.name = waypointNode.childFor(.name)?.content
+ self.comment = waypointNode.childFor(.comment)?.content
+ self.description = waypointNode.childFor(.description)?.content
+ }
+}
+
internal extension TrackPoint {
init?(trackNode: XMLNode) {
guard let lat = trackNode.latitude,
diff --git a/Sources/GPXKit/GPXTrack.swift b/Sources/GPXKit/GPXTrack.swift
index a002058..6a776f4 100644
--- a/Sources/GPXKit/GPXTrack.swift
+++ b/Sources/GPXKit/GPXTrack.swift
@@ -4,6 +4,8 @@ import Foundation
public struct GPXTrack: Hashable {
/// Optional date stamp of the gpx track
public var date: Date?
+ /// Waypoint defined for the gpx
+ public var waypoints: [Waypoint]?
/// Title of the gpx track
public var title: String
/// Description of the gpx track
@@ -20,12 +22,14 @@ public struct GPXTrack: Hashable {
/// Initializes a GPXTrack. You don't need to construct this value by yourself, as it is done by GXPKits track parsing logic.
/// - Parameters:
/// - date: The date stamp of the track. Defaults to nil.
+ /// - waypoints: Array of `Waypoints`. Defaults to nil.
/// - title: String describing the track.
/// - trackPoints: Array of `TrackPoint`s describing the route.
- /// - keywords: Array of `String`s with keyords. Default is an empty array (no keywords).
+ /// - keywords: Array of `String`s with keywords. Default is an empty array (no keywords).
/// - gradeSegmentLength: The length in meters for the grade segments. Defaults to 50 meters.
- public init(date: Date? = nil, title: String, description: String? = nil, trackPoints: [TrackPoint], keywords: [String] = [], gradeSegmentLength: Double = 50.0) {
+ public init(date: Date? = nil, waypoints: [Waypoint]? = nil, title: String, description: String? = nil, trackPoints: [TrackPoint], keywords: [String] = [], gradeSegmentLength: Double = 50.0) {
self.date = date
+ self.waypoints = waypoints
self.title = title
self.description = description
self.trackPoints = trackPoints
diff --git a/Sources/GPXKit/Waypoint.swift b/Sources/GPXKit/Waypoint.swift
new file mode 100644
index 0000000..47aa1d5
--- /dev/null
+++ b/Sources/GPXKit/Waypoint.swift
@@ -0,0 +1,32 @@
+import Foundation
+
+/// Value type describing a single Waypoint defined within a `GPXTrack`. A `Waypoint` has a location consisting of latitude, longitude and some metadata,
+/// e.g. name and description.
+public struct Waypoint: Hashable {
+ /// The coordinate (latitude, longitude and elevation in meters)
+ public var coordinate: Coordinate
+ /// Optional date for a given point.
+ public var date: Date?
+ /// Optional name of the waypoint
+ public var name: String?
+ /// Optional comment for the waypoint
+ public var comment: String?
+ /// Optional description of the waypoint
+ public var description: String?
+
+ /// Initializer
+ /// You don't need to construct this value by yourself, as it is done by GXPKits track parsing logic.
+ /// - Parameters:
+ /// - coordinate: Location of the waypoint, required
+ /// - date: Optional date
+ /// - name: Name of the waypoint
+ /// - comment: A short comment
+ /// - description: A longer description
+ public init(coordinate: Coordinate, date: Date? = nil, name: String? = nil, comment: String? = nil, description: String? = nil) {
+ self.coordinate = coordinate
+ self.date = date
+ self.name = name
+ self.comment = comment
+ self.description = description
+ }
+}
diff --git a/Tests/GPXKitTests/GPXParserTests.swift b/Tests/GPXKitTests/GPXParserTests.swift
index 90d0605..1706d97 100644
--- a/Tests/GPXKitTests/GPXParserTests.swift
+++ b/Tests/GPXKitTests/GPXParserTests.swift
@@ -284,4 +284,35 @@ class GPXParserTests: XCTestCase {
let sut = try XCTUnwrap(self.result)
XCTAssertEqual(["one", "two", "three", "four"], sut.keywords)
}
+
+ func testParsingAFileWithoutWaypointDefinitionsHasEmptyWaypoints() throws {
+ parseXML(testXMLData)
+ let sut = try XCTUnwrap(self.result)
+
+ XCTAssertNil(sut.waypoints)
+ }
+
+ func testParsingWaypointAttributes() throws {
+ parseXML(testXMLDataContainingWaypoint)
+ let sut = try XCTUnwrap(self.result)
+
+ let waypointStart = Waypoint(
+ coordinate: Coordinate(latitude: 51.2760600, longitude: 12.3769500),
+ date: expectedDate(for: "2020-03-18T12:39:47Z"),
+ name: "Start",
+ comment: "start comment",
+ description: "This is the start"
+ )
+
+ let waypointFinish = Waypoint(
+ coordinate: Coordinate(latitude: 51.2760420, longitude: 12.3769760),
+ date: expectedDate(for: "2020-03-18T12:39:48Z"),
+ name: "Finish",
+ comment: "finish comment",
+ description: "This is the finish"
+ )
+
+ XCTAssertEqual([waypointStart, waypointFinish], sut.waypoints)
+
+ }
}
diff --git a/Tests/GPXKitTests/TestFixtures.swift b/Tests/GPXKitTests/TestFixtures.swift
index cc3b84c..fc10275 100644
--- a/Tests/GPXKitTests/TestFixtures.swift
+++ b/Tests/GPXKitTests/TestFixtures.swift
@@ -120,6 +120,59 @@ let testTrackWithoutTime = GPXTrack(date: nil,
date: nil)
])
+let testXMLDataContainingWaypoint = """
+
+
+
+
+
+
+
+ Start
+ start comment
+ This is the start
+
+
+
+ Finish
+ finish comment
+ This is the finish
+
+
+ Haus- und Seenrunde Ausdauer
+ Track description
+ 1
+
+
+ 114.2
+
+
+ 42
+
+ 21
+ 97
+ 40
+
+
+
+
+ 114.0
+
+
+ 272
+
+ 20
+ 97
+ 40
+
+
+
+
+
+
+ """
+
+
let sampleGPX = """