Merge branch 'release/1.8'
This commit is contained in:
commit
729113b428
@ -1,5 +1,7 @@
|
||||
# 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.
|
||||
@ -8,6 +10,12 @@ Official GPX format is on [topografix](https://www.topografix.com/GPX/1/1/) site
|
||||
|
||||
## Changelog
|
||||
|
||||
### 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
|
||||
|
2
pom.xml
2
pom.xml
@ -6,7 +6,7 @@
|
||||
|
||||
<artifactId>GpxAndroidSdk</artifactId>
|
||||
<groupId>me.bvn13.sdk.android.gpx</groupId>
|
||||
<version>1.7</version>
|
||||
<version>1.8</version>
|
||||
|
||||
<packaging>jar</packaging>
|
||||
|
||||
|
@ -92,10 +92,13 @@ package me.bvn13.sdk.android.gpx
|
||||
*
|
||||
* [parameters] Map of key-value pairs
|
||||
*/
|
||||
class ExtensionType(val nodeName: String, val value: String? = null, val parameters: Map<String, String>? = null) {
|
||||
class ExtensionType(val nodeName: String,
|
||||
val value: String? = null,
|
||||
val parameters: Map<String, String>? = null,
|
||||
val nested: List<ExtensionType>? = null) {
|
||||
init {
|
||||
require(value != null || parameters != null) {
|
||||
"value or parameters must be specified"
|
||||
require(value != null || parameters != null || nested != null) {
|
||||
"value or parameters or nesting elements must be specified for ${nodeName}"
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,6 +111,7 @@ class ExtensionType(val nodeName: String, val value: String? = null, val paramet
|
||||
if (nodeName != other.nodeName) return false
|
||||
if (value != other.value) return false
|
||||
if (parameters != other.parameters) return false
|
||||
if (nested != other.nested) return false
|
||||
|
||||
return true
|
||||
}
|
||||
@ -116,8 +120,7 @@ class ExtensionType(val nodeName: String, val value: String? = null, val paramet
|
||||
var result = nodeName.hashCode()
|
||||
result = 31 * result + (value?.hashCode() ?: 0)
|
||||
result = 31 * result + (parameters?.hashCode() ?: 0)
|
||||
result = 31 * result + (nested?.hashCode() ?: 0)
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import java.time.format.DateTimeFormatterBuilder
|
||||
class GpxConstant {
|
||||
companion object {
|
||||
const val HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
|
||||
const val HEADER_EXTENDED = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"
|
||||
const val VERSION = "1.1"
|
||||
val DTF =
|
||||
DateTimeFormatterBuilder().append(ISO_LOCAL_DATE_TIME) // use the existing formatter for date time
|
||||
|
@ -3,6 +3,7 @@ package me.bvn13.sdk.android.gpx
|
||||
import me.bvn13.sdk.android.gpx.GpxConstant.Companion.DTF
|
||||
import java.io.InputStream
|
||||
import java.time.OffsetDateTime
|
||||
import java.util.stream.Collectors
|
||||
|
||||
fun GpxType.Companion.read(dis: InputStream) = GpxReader().read(dis)
|
||||
|
||||
@ -28,7 +29,13 @@ class GpxReader {
|
||||
|
||||
private fun readSignature(dis: InputStream, buffer: Container): GpxType {
|
||||
val container = readUntil(dis, buffer, '\n')
|
||||
if ("${GpxConstant.HEADER}\n" != container.buffer.asString()) {
|
||||
val signaturePrepared = container.buffer.asString()
|
||||
.trim()
|
||||
.replace("'", "\"")
|
||||
.replace(" ?", "?")
|
||||
if (GpxConstant.HEADER != signaturePrepared
|
||||
&& GpxConstant.HEADER_EXTENDED != signaturePrepared
|
||||
) {
|
||||
throw IllegalArgumentException("Wrong xml signature!")
|
||||
}
|
||||
return readBeginning(dis, Container.empty(container.position))
|
||||
@ -59,10 +66,12 @@ class GpxReader {
|
||||
return findObject(container.objects, "gpx").let {
|
||||
return GpxType(
|
||||
metadata = assembleMetadataType(it.nested),
|
||||
creator = findAttributeOrNull(it.attributes, "creator") ?: throw IllegalArgumentException("Gpx.Creator not found"),
|
||||
wpt = findObjectsOrNull(it.nested ,"wpt")?.map { assembleWptType(it) },
|
||||
creator = findAttributeOrNull(it.attributes, "creator")
|
||||
?: throw IllegalArgumentException("Gpx.Creator not found"),
|
||||
wpt = findObjectsOrNull(it.nested, "wpt")?.map { assembleWptType(it) },
|
||||
rte = findObjectsOrNull(it.nested, "rte")?.map { assembleRteType(it) },
|
||||
trk = findObjectsOrNull(it.nested, "trk")?.map { assembleTrkType(it) }
|
||||
trk = findObjectsOrNull(it.nested, "trk")?.map { assembleTrkType(it) },
|
||||
extensions = findObjectOrNull(it.nested, "extensions")?.let { assembleExtensionType(it) }
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -71,10 +80,13 @@ class GpxReader {
|
||||
findObject(objects, "metadata")
|
||||
.let {
|
||||
return MetadataType(
|
||||
name = findObjectOrNull(it.nested, "name")?.value ?: throw IllegalArgumentException("Gpx.Metadata.Name not found"),
|
||||
description = findObjectOrNull(it.nested, "desc")?.value ?: throw IllegalArgumentException("Gpx.Metadata.Description not found"),
|
||||
authorName = findObject(it.nested, "author").let { author ->
|
||||
findObject(author.nested, "name").value ?: throw IllegalArgumentException("Gpx.Metadata.Author.Name not found")
|
||||
name = findObjectOrNull(it.nested, "name")?.value
|
||||
?: throw IllegalArgumentException("Gpx.Metadata.Name not found"),
|
||||
description = findObjectOrNull(it.nested, "desc")?.value
|
||||
?: "",
|
||||
authorName = findObjectOrNull(it.nested, "author").let { author ->
|
||||
findObjectOrNull(author?.nested, "name")?.value
|
||||
?: ""
|
||||
}
|
||||
)
|
||||
}
|
||||
@ -123,7 +135,10 @@ class GpxReader {
|
||||
cmt = findObjectOrNull(obj.nested, "cmt")?.value,
|
||||
desc = findObjectOrNull(obj.nested, "desc")?.value,
|
||||
src = findObjectOrNull(obj.nested, "src")?.value,
|
||||
link = findObjectsOrNull(obj.nested, "link")?.let { list -> if (list.isNotEmpty()) list.map { assembleLinkType(it) } else null },
|
||||
link = findObjectsOrNull(
|
||||
obj.nested,
|
||||
"link"
|
||||
)?.let { list -> if (list.isNotEmpty()) list.map { assembleLinkType(it) } else null },
|
||||
number = findObjectOrNull(obj.nested, "number")?.value?.toInt(),
|
||||
type = findObjectOrNull(obj.nested, "type")?.value,
|
||||
extensions = findObjectOrNull(obj.nested, "extensions")?.let { assembleExtensionType(it) },
|
||||
@ -140,12 +155,17 @@ class GpxReader {
|
||||
private fun assembleFixType(value: String): FixType =
|
||||
FixType.valueOf(value.uppercase())
|
||||
|
||||
private fun assembleExtensionType(obj: XmlObject): ExtensionType =
|
||||
ExtensionType(
|
||||
private fun assembleExtensionType(obj: XmlObject): ExtensionType {
|
||||
val nested: List<ExtensionType>? = obj.nested?.stream()
|
||||
?.map { assembleExtensionType(it) }
|
||||
?.collect(Collectors.toList())
|
||||
return ExtensionType(
|
||||
nodeName = obj.type,
|
||||
value = if (obj.value == "") null else obj.value,
|
||||
parameters = if (obj.attributes.isEmpty()) null else obj.attributes.toSortedMap()
|
||||
)
|
||||
parameters = if (obj.attributes.isEmpty()) null else obj.attributes.toSortedMap(),
|
||||
nested = nested
|
||||
)
|
||||
}
|
||||
|
||||
private fun assembleTrksegType(obj: XmlObject): TrksegType =
|
||||
TrksegType(
|
||||
@ -186,14 +206,16 @@ class GpxReader {
|
||||
container = readAttributes(dis, container)
|
||||
xmlObject.attributes = container.attributes
|
||||
}
|
||||
container = readSkipping(dis, container, SKIPPING_SET)
|
||||
if (container.byte!!.toInt() == '<'.code) {
|
||||
container = readNestedObjects(dis, container)
|
||||
xmlObject.nested = container.objects
|
||||
container = readFinishingTag(dis, container, tagName)
|
||||
}
|
||||
if (container.buffer.asString() != "</$tagName>") {
|
||||
container = readValue(dis, container, tagName)
|
||||
if (!container.isShortClosing) {
|
||||
container = readSkipping(dis, container, SKIPPING_SET)
|
||||
if (container.byte!!.toInt() == '<'.code) {
|
||||
container = readNestedObjects(dis, container)
|
||||
xmlObject.nested = container.objects
|
||||
container = readFinishingTag(dis, container, tagName)
|
||||
}
|
||||
if (container.buffer.asString() != "</$tagName>") {
|
||||
container = readValue(dis, container, tagName)
|
||||
}
|
||||
}
|
||||
xmlObject.value = container.buffer.asString().replace("</$tagName>", "")
|
||||
container.objects = listOf(xmlObject)
|
||||
@ -221,8 +243,12 @@ class GpxReader {
|
||||
return container
|
||||
}
|
||||
|
||||
private fun readFinishingTag(dis: InputStream, buffer: Container, tagName: String): Container =
|
||||
readExactly(dis, buffer, "</${tagName}>")
|
||||
private fun readFinishingTag(dis: InputStream, buffer: Container, tagName: String): Container {
|
||||
if (buffer.isShortClosing) {
|
||||
return buffer
|
||||
}
|
||||
return readExactly(dis, buffer, "</${tagName}>")
|
||||
}
|
||||
|
||||
private fun readValue(dis: InputStream, buffer: Container, tagName: String): Container =
|
||||
readUntil(dis, buffer, "</$tagName>")
|
||||
@ -236,8 +262,10 @@ class GpxReader {
|
||||
do {
|
||||
attributeContainer = readAttribute(dis, attributeContainer)
|
||||
attributes.putAll(attributeContainer.attributes)
|
||||
} while (attributeContainer.attributes.isNotEmpty() && attributeContainer.byte!!.toInt() != '>'.code)
|
||||
val result = Container.emptyWithAttributes(attributeContainer.position, attributes)
|
||||
} while (attributeContainer.attributes.isNotEmpty()
|
||||
&& attributeContainer.byte!!.toInt() != '>'.code
|
||||
)
|
||||
val result = Container.emptyWithAttributes(attributeContainer.position, attributes, attributeContainer.isShortClosing)
|
||||
return result
|
||||
}
|
||||
|
||||
@ -250,8 +278,17 @@ class GpxReader {
|
||||
val valueAsString = valueContainer.buffer.asString()
|
||||
val value = valueAsString.substring(0, valueAsString.length - 1)
|
||||
val result = Container.empty(valueContainer.position)
|
||||
val closingContainer = readSkipping(dis, result, SKIPPING_SET)
|
||||
val nextBlockContainer = Container.of(closingContainer.byte!!, closingContainer.position)
|
||||
var closingContainer = readSkipping(dis, result, SKIPPING_SET)
|
||||
var isShortClosing = false
|
||||
if (closingContainer.byte!!.toInt() == '/'.code) {
|
||||
val endingContainer = readByte(dis, closingContainer)
|
||||
if (endingContainer.byte!!.toInt() != '>'.code) {
|
||||
throw IllegalArgumentException("There must be valid closing tag at ${endingContainer.position}")
|
||||
}
|
||||
closingContainer = endingContainer
|
||||
isShortClosing = true
|
||||
}
|
||||
val nextBlockContainer = Container.of(closingContainer.byte!!, closingContainer.position, isShortClosing)
|
||||
nextBlockContainer.attributes = mapOf(name to value)
|
||||
return nextBlockContainer
|
||||
}
|
||||
@ -321,28 +358,42 @@ class GpxReader {
|
||||
private fun readByte(dis: InputStream, container: Container): Container {
|
||||
val ba = ByteArray(1);
|
||||
if (-1 == dis.read(ba, 0, 1)) {
|
||||
throw InterruptedException("EOF")
|
||||
throw InterruptedException("EOF at ${container.position}\nUnparsed data: " + String(container.buffer))
|
||||
} else if (ba.size != 1) {
|
||||
throw InterruptedException("Reading of 1 byte returns ${ba.size} bytes")
|
||||
throw InterruptedException("Reading of 1 byte returns ${ba.size} bytes at ${container.position}")
|
||||
}
|
||||
return Container(container.position + 1, ba[0], container.buffer.plus(ba))
|
||||
}
|
||||
|
||||
class Container(val position: Long = 0, val byte: Byte?, val buffer: ByteArray) {
|
||||
class Container(
|
||||
val position: Long = 0,
|
||||
val byte: Byte?,
|
||||
val buffer: ByteArray,
|
||||
val isShortClosing: Boolean = false
|
||||
) {
|
||||
var objects: List<XmlObject>? = null
|
||||
var attributes: Map<String, String> = HashMap()
|
||||
var value: String? = null
|
||||
|
||||
companion object {
|
||||
fun empty(): Container = empty(0)
|
||||
fun empty(position: Long) = Container(position, null, ByteArray(0))
|
||||
fun emptyWithAttributes(position: Long, attributes: Map<String, String>): Container {
|
||||
val container = Container.empty(position)
|
||||
fun empty(position: Long, isShortClosing: Boolean = false) = Container(position, null, ByteArray(0), isShortClosing)
|
||||
fun emptyWithAttributes(position: Long, attributes: Map<String, String>, isShortClosing: Boolean = false): Container {
|
||||
val container = Container.empty(position, isShortClosing)
|
||||
container.attributes = attributes
|
||||
return container
|
||||
}
|
||||
|
||||
fun of(b: Byte, position: Long) = Container(position, b, ByteArray(1) { _ -> b })
|
||||
fun of(b: Byte, position: Long, isShortClosing: Boolean = false) =
|
||||
Container(position, b, ByteArray(1) { _ -> b }, isShortClosing)
|
||||
|
||||
fun isShortClosing(c: Container, buffer: ByteArray): Container {
|
||||
val container = Container(c.position, c.byte, buffer, isShortClosing = true)
|
||||
container.objects = c.objects
|
||||
container.attributes = c.attributes
|
||||
container.value = c.value
|
||||
return container
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String = this.buffer.asString()
|
||||
|
@ -100,6 +100,7 @@ fun GpxType.toXmlString(clock: Clock?): String = """
|
||||
${this.wpt?.toXmlString() ?: ""}
|
||||
${this.rte?.toXmlString() ?: ""}
|
||||
${this.trk?.toXmlString() ?: ""}
|
||||
${this.extensions?.toXmlString() ?: ""}
|
||||
</gpx>
|
||||
""".trim().removeEmptyStrings()
|
||||
|
||||
@ -140,7 +141,7 @@ fun WptType.toXmlString(nodeName: String) = """
|
||||
${toXmlString(pdop, "pdop")}
|
||||
${toXmlString(ageofgpsdata, "ageofgpsdata")}
|
||||
${toXmlString(dgpsid, "dgpsid")}
|
||||
${extensions?.toXmlString() ?: ""}
|
||||
${extensions?.toXmlString(true) ?: ""}
|
||||
</${nodeName}>
|
||||
""".trim().removeEmptyStrings()
|
||||
|
||||
@ -153,7 +154,7 @@ fun RteType.toXmlString() = """
|
||||
${this.link?.toXmlString() ?: ""}
|
||||
${toXmlString(this.number, "number")}
|
||||
${toXmlString(this.type, "type")}
|
||||
${this.extensions?.toXmlString() ?: ""}
|
||||
${this.extensions?.toXmlString(true) ?: ""}
|
||||
${this.rtept?.toXmlString("rtept") ?: ""}
|
||||
</rte>
|
||||
""".trim().removeEmptyStrings()
|
||||
@ -183,13 +184,21 @@ fun FixType.toXmlString() = """
|
||||
<fix>${this.value}</fix>
|
||||
""".trim().removeEmptyStrings()
|
||||
|
||||
fun ExtensionType.toXmlString() = """
|
||||
fun ExtensionType.toXmlString() =
|
||||
if ((this.nested?.size ?: 0) > 0) {
|
||||
"""
|
||||
<${this.nodeName}${toXmlString(this.parameters)}>${this.nested?.toXmlString() ?: ""}</${this.nodeName}>
|
||||
""".trim().removeEmptyStrings()
|
||||
} else {
|
||||
"""
|
||||
<${this.nodeName}${toXmlString(this.parameters)}>${this.value ?: ""}</${this.nodeName}>
|
||||
""".trim().removeEmptyStrings()
|
||||
}
|
||||
|
||||
fun TrksegType.toXmlString() = """
|
||||
<trkseg>
|
||||
${this.trkpt?.toXmlString("trkpt") ?: ""}
|
||||
${this.extensions?.toXmlString() ?: ""}
|
||||
</trkseg>
|
||||
""".trim().removeEmptyStrings()
|
||||
|
||||
@ -197,9 +206,17 @@ fun List<WptType>.toXmlString(nodeName: String?) = this.joinToString(prefix = "\
|
||||
it.toXmlString(nodeName)
|
||||
}
|
||||
|
||||
fun List<ExtensionType>.toXmlString() = this.joinToString(
|
||||
prefix = "<extensions>\n", postfix = "\n</extensions>", separator = "\n", transform = ExtensionType::toXmlString
|
||||
)
|
||||
fun List<ExtensionType>.toXmlString(inGroup: Boolean = false): String {
|
||||
if (inGroup) {
|
||||
return this.joinToString(
|
||||
prefix = "<extensions>\n", postfix = "\n</extensions>", separator = "\n", transform = ExtensionType::toXmlString
|
||||
)
|
||||
} else {
|
||||
return this.joinToString(
|
||||
prefix = "\n", postfix = "\n", separator = "\n", transform = ExtensionType::toXmlString
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmName("toXmlStringWptType")
|
||||
fun List<WptType>.toXmlString() = this.joinToString(prefix = "", postfix = "", separator = "") {
|
||||
|
@ -1,5 +1,6 @@
|
||||
package me.bvn13.sdk.android.gpx
|
||||
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import java.time.*
|
||||
@ -409,4 +410,16 @@ class GpxReaderTest {
|
||||
val gpx = GpxType.read(gpxString.byteInputStream())
|
||||
assertEquals(gpxType, gpx)
|
||||
}
|
||||
|
||||
@DisplayName("Read test.gpx (generated in OsmAnd Android application")
|
||||
@Test
|
||||
fun readTestGpx() {
|
||||
val gpxType = GpxType.read(javaClass.classLoader.getResource("test.gpx").openStream())
|
||||
Assertions.assertEquals(1011, gpxType.trk?.get(0)?.trkseg?.get(0)?.trkpt?.size ?: 0)
|
||||
Assertions.assertEquals(1, gpxType.trk?.get(0)?.trkseg?.get(0)?.trkpt?.get(0)?.extensions?.size ?: 0)
|
||||
Assertions.assertEquals(2, gpxType.trk?.get(0)?.trkseg?.get(0)?.extensions?.nested?.size ?: 0)
|
||||
Assertions.assertEquals(223, gpxType.trk?.get(0)?.trkseg?.get(0)?.extensions?.nested?.get(0)?.nested?.size ?: 0)
|
||||
Assertions.assertEquals(159, gpxType.trk?.get(0)?.trkseg?.get(0)?.extensions?.nested?.get(1)?.nested?.size ?: 0)
|
||||
Assertions.assertEquals(1, gpxType.extensions?.nested?.size ?: 0)
|
||||
}
|
||||
}
|
243
src/test/kotlin/me/bvn13/sdk/android/gpx/ReadWriteTest.kt
Normal file
243
src/test/kotlin/me/bvn13/sdk/android/gpx/ReadWriteTest.kt
Normal file
@ -0,0 +1,243 @@
|
||||
package me.bvn13.sdk.android.gpx
|
||||
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.time.*
|
||||
|
||||
class ReadWriteTest {
|
||||
|
||||
@DisplayName("Read-Write test")
|
||||
@Test
|
||||
fun testReadWrite() {
|
||||
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 gpx = gpxType.toXmlString(clock)
|
||||
val deserializedGpxType = GpxType.read(ByteArrayInputStream(gpx.toByteArray()))
|
||||
|
||||
Assertions.assertEquals(gpxType, deserializedGpxType)
|
||||
}
|
||||
|
||||
}
|
6459
src/test/resources/test.gpx
Normal file
6459
src/test/resources/test.gpx
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user