GpxAndroidSdk/src/main/kotlin/me/bvn13/sdk/android/gpx/GpxWriter.kt

212 lines
6.2 KiB
Kotlin

package me.bvn13.sdk.android.gpx
import me.bvn13.sdk.android.gpx.GpxWriter.Companion.DTF
import me.bvn13.sdk.android.gpx.GpxWriter.Companion.HEADER
import me.bvn13.sdk.android.gpx.GpxWriter.Companion.SCHEMA_LOCATION
import me.bvn13.sdk.android.gpx.GpxWriter.Companion.XMLNS
import me.bvn13.sdk.android.gpx.GpxWriter.Companion.XMLNS_XSI
import java.time.Clock
import java.time.OffsetDateTime
import java.time.format.DateTimeFormatter.ISO_LOCAL_DATE_TIME
import java.time.format.DateTimeFormatterBuilder
fun GpxType.toXmlString(): String = this.toXmlString(null)
fun GpxType.toXmlString(clock: Clock?): String = """
$HEADER
<gpx
xmlns="$XMLNS"
version="${this.version}"
creator="${this.creator}"
xmlns:xsi="$XMLNS_XSI"
xsi:schemaLocation="$SCHEMA_LOCATION">
<time>${now(clock)}</time>
${this.metadata.toXmlString()}
${this.wpt?.toXmlString()}
${this.rte?.toXmlString()}
${this.trk?.toXmlString()}
</gpx>
""".trim()
fun MetadataType.toXmlString(): String = """
<metadata>
<name>${this.name}</name>
<desc>${this.description}</desc>
<author>
<name>${this.authorName}</name>
</author>
</metadata>
""".trim()
private fun now(clock: Clock?) = OffsetDateTime.now(clock ?: Clock.systemDefaultZone()).format(DTF)
fun WptType.toXmlString(nodeName: String? = null) =
if (nodeName != null) {
this.toXmlString(nodeName)
} else {
this.toXmlString("wpt")
}
@JvmName("toXmlStringNamed")
fun WptType.toXmlString(nodeName: String) = """
<${nodeName} lat="${this.lat}" lon="${this.lon}">
${toXmlString(ele, "ele")}
${toXmlString(time, "time")}
${toXmlString(magvar, "magvar")}
${toXmlString(geoidheight, "geoidheight")}
${toXmlString(name, "name")}
${toXmlString(cmt, "cmt")}
${toXmlString(desc, "desc")}
${toXmlString(src, "src")}
${link?.toXmlString()}
${toXmlString(sym, "sym")}
${toXmlString(type, "type")}
${fix?.toXmlString()}
${toXmlString(sat, "sat")}
${toXmlString(hdop, "hdop")}
${toXmlString(vdop, "vdop")}
${toXmlString(pdop, "pdop")}
${toXmlString(ageofgpsdata, "ageofgpsdata")}
${toXmlString(dgpsid, "dgpsid")}
${extensions?.toXmlString()}
</${nodeName}>
""".trim()
fun RteType.toXmlString() = """
<rte>
${toXmlString(this.name, "name")}
${toXmlString(this.cmt, "cmt")}
${toXmlString(this.desc, "desc")}
${toXmlString(this.src, "src")}
${this.link?.toXmlString()}
${toXmlString(this.number, "number")}
${toXmlString(this.type, "type")}
${this.extensions?.toXmlString()}
${this.rtept?.toXmlString()}
</rte>
""".trim()
fun TrkType.toXmlString() = """
<trk>
${toXmlString(this.name, "name")}
${toXmlString(this.cmt, "cmt")}
${toXmlString(this.desc, "desc")}
${toXmlString(this.src, "src")}
${this.link?.toXmlString()}
${toXmlString(this.number, "number")}
${toXmlString(this.type, "type")}
${this.extensions?.toXmlString()}
${this.trkseg?.toXmlString()}
</trk>
""".trim()
fun List<WptType>.toXmlString(nodeName: String?) =
this.joinToString(prefix = "", postfix = "", separator = "") {
it.toXmlString(nodeName)
}
@JvmName("toXmlStringWptType")
fun List<WptType>.toXmlString() =
this.joinToString(prefix = "", postfix = "", separator = "") {
it.toXmlString()
}
@JvmName("toXmlStringLinkType")
fun List<LinkType>.toXmlString() =
this.joinToString(prefix = "", postfix = "", separator = "\n", transform = LinkType::toXmlString)
@JvmName("toXmlStringRteType")
fun List<RteType>.toXmlString() =
this.joinToString(prefix = "", postfix = "", separator = "", transform = RteType::toXmlString)
@JvmName("toXmlStringTrkType")
fun List<TrkType>.toXmlString() =
this.joinToString(prefix = "", postfix = "", separator = "", transform = TrkType::toXmlString)
@JvmName("toXmlStringTrksegType")
fun List<TrksegType>.toXmlString() =
this.joinToString(prefix = "", postfix = "", separator = "", transform = TrksegType::toXmlString)
fun List<ExtensionType>.toXmlString() =
this.joinToString(
prefix = "<extensions>\n",
postfix = "\n</extensions>",
separator = "\n",
transform = ExtensionType::toXmlString
)
fun LinkType.toXmlString() = """
<link href="${this.href}">
<text>${this.text}</text>
<type>${this.type}</type>
</link>
""".trim()
fun FixType.toXmlString() = """
<fix>${this.value}</fix>
""".trim()
fun ExtensionType.toXmlString() = """
<${this.nodeName}${toXmlString(this.parameters)}>${this.value ?: ""}</${this.nodeName}>
""".trim()
fun TrksegType.toXmlString() = """
<trkseg>
${this.trkpt?.toXmlString("trkpt")}
</trkseg>
""".trim()
fun toXmlString(value: String?, nodeName: String) =
if (value != null) {
"""
<${nodeName}>${value}</${nodeName}>
""".trim()
} else {
""
}
fun toXmlString(value: Int?, nodeName: String) =
if (value != null) {
"""
<${nodeName}>${value}</${nodeName}>
""".trim()
} else {
""
}
fun toXmlString(value: Double?, nodeName: String) =
if (value != null) {
"""
<${nodeName}>${value}</${nodeName}>
""".trim()
} else {
""
}
fun toXmlString(value: OffsetDateTime?, nodeName: String) =
if (value != null) {
"""
<${nodeName}>${value.format(DTF)}</${nodeName}>
""".trim()
} else {
""
}
fun toXmlString(value: Map<String, String>?) =
value?.entries?.joinToString(separator = "") {
" ${it.key}=\"${it.value}\""
} ?: ""
class GpxWriter {
companion object {
const val HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
const val XMLNS = "http://www.topografix.com/GPX/1/1"
const val XMLNS_XSI = "http://www.w3.org/2001/XMLSchema-instance"
const val SCHEMA_LOCATION = "http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd"
internal val DTF = DateTimeFormatterBuilder()
.append(ISO_LOCAL_DATE_TIME) // use the existing formatter for date time
.appendOffset("+HH:MM", "+00:00") // set 'noOffsetText' to desired '+00:00'
.toFormatter()
}
}