# Android (Kotlin) SDK for manipulating GPX files ![](https://img.shields.io/maven-central/v/me.bvn13.sdk.android.gpx/GpxAndroidSdk) ## About This is another one SDK for reading and writing (manipulating) GPX files. Official GPX format is on [topografix](https://www.topografix.com/GPX/1/1/) site. ## Why this one? 1. This library supports GPX v1.1 format 2. This library reads and writes files in one pass 3. This library works without any external dependency ## Changelog ### 2023-03-26 1) Fixed signature reading 2) Since 1.10.4 extensions can have NULL as values ### 2023-02-13 1) Fixed missed extensions 2) ✅ Tested on reading with self written content 3) ✅ Tested on reading [OsmAnd](https://osmand.net) GPX files ### 2022-12-18 1) Implemented GPX format reader ### 2022-09-25 1) Project started 2) Implemented GPX format in Kotlin 3) Implemented representing GPX object into String for future saving ## Examples ### Writer example ```kotlin val gpxType = GpxType( MetadataType("test name", description = "test description", authorName = "bvn13"), wpt = listOf( WptType( lat = 14.64736838389662, lon = 7.93212890625, ele = 10.toDouble(), time = OffsetDateTime.now(clock), magvar = 3.toDouble(), geoidheight = 45.toDouble(), name = "test point 1", cmt = "comment 1", desc = "description of point 1", link = listOf( LinkType( href = "http://link-to.site.href", text = "text", type = "hyperlink" ), LinkType( href = "http://link2-to.site.href", text = "text2", type = "hyperlink2" ) ), src = "source 1", sym = "sym 1", type = "type 1", fix = FixType.DGPS, sat = 1, hdop = 55.toDouble(), vdop = 66.toDouble(), pdop = 77.toDouble(), ageofgpsdata = 44, dgpsid = 88, extensions = listOf( ExtensionType( "extension1", parameters = mapOf(Pair("first", "second"), Pair("third", "fours")) ), ExtensionType( "extension2", parameters = mapOf(Pair("aa", "bb"), Pair("cc", "dd")) ) ) ) ), rte = listOf( RteType( name = "rte name", cmt = "cmt", desc = "desc", src = "src", link = listOf( LinkType( href = "https://new.link.rte", text = "new text rte", type = "hyperlink" ) ), number = 1234, type = "route", extensions = listOf( ExtensionType( "ext-1", value = "value1" ) ), rtept = listOf( WptType( lat = 14.64736838389662, lon = 7.93212890625, ele = 10.toDouble(), time = OffsetDateTime.now(clock), magvar = 3.toDouble(), geoidheight = 45.toDouble(), name = "test point 1", cmt = "comment 1", desc = "description of point 1", link = listOf( LinkType( href = "http://link-to.site.href", text = "text", type = "hyperlink" ), LinkType( href = "http://link2-to.site.href", text = "text2", type = "hyperlink2" ) ), src = "source 1", sym = "sym 1", type = "type 1", fix = FixType.DGPS, sat = 1, hdop = 55.toDouble(), vdop = 66.toDouble(), pdop = 77.toDouble(), ageofgpsdata = 44, dgpsid = 88, extensions = listOf( ExtensionType( "extension1", parameters = mapOf(Pair("first", "second"), Pair("third", "fours")) ), ExtensionType( "extension2", parameters = mapOf(Pair("aa", "bb"), Pair("cc", "dd")) ) ) ) ) ) ), trk = listOf( TrkType( name = "track 1", cmt = "comment track 1", desc = "desc track 1", src = "src track 1", number = 1234, type = "type 1", trkseg = listOf( TrksegType( listOf( WptType( lat = 14.64736838389662, lon = 7.93212890625, ele = 10.toDouble(), time = OffsetDateTime.now(clock), magvar = 3.toDouble(), geoidheight = 45.toDouble(), name = "test point 1", cmt = "comment 1", desc = "description of point 1", link = listOf( LinkType( href = "http://link-to.site.href", text = "text", type = "hyperlink" ), LinkType( href = "http://link2-to.site.href", text = "text2", type = "hyperlink2" ) ), src = "source 1", sym = "sym 1", type = "type 1", fix = FixType.DGPS, sat = 1, hdop = 55.toDouble(), vdop = 66.toDouble(), pdop = 77.toDouble(), ageofgpsdata = 44, dgpsid = 88, extensions = listOf( ExtensionType( "extension1", parameters = mapOf(Pair("first", "second"), Pair("third", "fours")) ), ExtensionType( "extension2", parameters = mapOf(Pair("aa", "bb"), Pair("cc", "dd")) ) ) ) ) ) ) ) ) ) ``` this example will be presented in GPX as following ```xml test name test description bvn13 10.0 3.0 45.0 test point 1 comment 1 description of point 1 source 1 text hyperlink text2 hyperlink2 sym 1 type 1 dgps 1 55.0 66.0 77.0 44 88 rte name cmt desc src new text rte hyperlink 1234 route value1 10.0 3.0 45.0 test point 1 comment 1 description of point 1 source 1 text hyperlink text2 hyperlink2 sym 1 type 1 dgps 1 55.0 66.0 77.0 44 88 track 1 comment track 1 desc track 1 src track 1 null 1234 type 1 null 10.0 3.0 45.0 test point 1 comment 1 description of point 1 source 1 text hyperlink text2 hyperlink2 sym 1 type 1 dgps 1 55.0 66.0 77.0 44 88 ``` ### Reader example ```kotlin val clock = Clock.fixed( LocalDateTime.of(2022, 9, 24, 15, 4, 0, 0).toInstant(ZoneOffset.ofHours(3)), ZoneId.of("Europe/Moscow") ) val gpxType = GpxType( MetadataType("test name", description = "test description", authorName = "bvn13"), wpt = listOf( WptType( lat = 14.64736838389662, lon = 7.93212890625, ele = 10.toDouble(), time = OffsetDateTime.now(clock), magvar = 3.toDouble(), geoidheight = 45.toDouble(), name = "test point 1", cmt = "comment 1", desc = "description of point 1", link = listOf( LinkType( href = "http://link-to.site.href", text = "text", type = "hyperlink" ), LinkType( href = "http://link2-to.site.href", text = "text2", type = "hyperlink2" ) ), src = "source 1", sym = "sym 1", type = "type 1", fix = FixType.DGPS, sat = 1, hdop = 55.toDouble(), vdop = 66.toDouble(), pdop = 77.toDouble(), ageofgpsdata = 44, dgpsid = 88, extensions = listOf( ExtensionType( "extension1", parameters = mapOf(Pair("first", "second"), Pair("third", "fours")) ), ExtensionType( "extension2", parameters = mapOf(Pair("aa", "bb"), Pair("cc", "dd")) ) ) ) ), rte = listOf( RteType( name = "rte name", cmt = "cmt", desc = "desc", src = "src", link = listOf( LinkType( href = "https://new.link.rte", text = "new text rte", type = "hyperlink" ) ), number = 1234, type = "route", extensions = listOf( ExtensionType( "ext-1", value = "value1" ) ), rtept = listOf( WptType( lat = 14.64736838389662, lon = 7.93212890625, ele = 10.toDouble(), time = OffsetDateTime.now(clock), magvar = 3.toDouble(), geoidheight = 45.toDouble(), name = "test point 1", cmt = "comment 1", desc = "description of point 1", link = listOf( LinkType( href = "http://link-to.site.href", text = "text", type = "hyperlink" ), LinkType( href = "http://link2-to.site.href", text = "text2", type = "hyperlink2" ) ), src = "source 1", sym = "sym 1", type = "type 1", fix = FixType.DGPS, sat = 1, hdop = 55.toDouble(), vdop = 66.toDouble(), pdop = 77.toDouble(), ageofgpsdata = 44, dgpsid = 88, extensions = listOf( ExtensionType( "extension1", parameters = mapOf(Pair("first", "second"), Pair("third", "fours")) ), ExtensionType( "extension2", parameters = mapOf(Pair("aa", "bb"), Pair("cc", "dd")) ) ) ) ) ) ), trk = listOf( TrkType( name = "track 1", cmt = "comment track 1", desc = "desc track 1", src = "src track 1", number = 1234, type = "type 1", trkseg = listOf( TrksegType( listOf( WptType( lat = 14.64736838389662, lon = 7.93212890625, ele = 10.toDouble(), time = OffsetDateTime.now(clock), magvar = 3.toDouble(), geoidheight = 45.toDouble(), name = "test point 1", cmt = "comment 1", desc = "description of point 1", link = listOf( LinkType( href = "http://link-to.site.href", text = "text", type = "hyperlink" ), LinkType( href = "http://link2-to.site.href", text = "text2", type = "hyperlink2" ) ), src = "source 1", sym = "sym 1", type = "type 1", fix = FixType.DGPS, sat = 1, hdop = 55.toDouble(), vdop = 66.toDouble(), pdop = 77.toDouble(), ageofgpsdata = 44, dgpsid = 88, extensions = listOf( ExtensionType( "extension1", parameters = mapOf(Pair("first", "second"), Pair("third", "fours")) ), ExtensionType( "extension2", parameters = mapOf(Pair("aa", "bb"), Pair("cc", "dd")) ) ) ), WptType( lat = 14.64736838389662, lon = 7.93212890625, ele = 10.toDouble(), time = OffsetDateTime.now(clock), magvar = 3.toDouble(), geoidheight = 45.toDouble(), name = "test point 1", cmt = "comment 1", desc = "description of point 1", link = listOf( LinkType( href = "http://link-to.site.href", text = "text", type = "hyperlink" ), LinkType( href = "http://link2-to.site.href", text = "text2", type = "hyperlink2" ) ), src = "source 1", sym = "sym 1", type = "type 1", fix = FixType.DGPS, sat = 1, hdop = 55.toDouble(), vdop = 66.toDouble(), pdop = 77.toDouble(), ageofgpsdata = 44, dgpsid = 88, extensions = listOf( ExtensionType( "extension1", parameters = mapOf(Pair("first", "second"), Pair("third", "fours")) ), ExtensionType( "extension2", parameters = mapOf(Pair("aa", "bb"), Pair("cc", "dd")) ) ) ) ) ) ) ) ) ) val gpxString = """ test name test description bvn13 10.0 3.0 45.0 test point 1 comment 1 description of point 1 source 1 text hyperlink text2 hyperlink2 sym 1 type 1 dgps 1 55.0 66.0 77.0 44 88 rte name cmt desc src new text rte hyperlink 1234 route value1 10.0 3.0 45.0 test point 1 comment 1 description of point 1 source 1 text hyperlink text2 hyperlink2 sym 1 type 1 dgps 1 55.0 66.0 77.0 44 88 track 1 comment track 1 desc track 1 src track 1 1234 type 1 10.0 3.0 45.0 test point 1 comment 1 description of point 1 source 1 text hyperlink text2 hyperlink2 sym 1 type 1 dgps 1 55.0 66.0 77.0 44 88 10.0 3.0 45.0 test point 1 comment 1 description of point 1 source 1 text hyperlink text2 hyperlink2 sym 1 type 1 dgps 1 55.0 66.0 77.0 44 88 """.trim() .lineSequence() .map { it.trim() } .joinToString("\n") val gpx = GpxType.read(gpxString.byteInputStream()) assertEquals(gpxType, gpx) ```