1
0
Fork 0
mirror of https://github.com/Luzifer/staticmap.git synced 2024-10-19 08:04:22 +00:00
staticmap/vendor/github.com/tkrajina/gpxgo/gpx/xml.go

179 lines
3.6 KiB
Go
Raw Normal View History

// Copyright 2013, 2014 Peter Vasil, Tomo Krajina. All
// rights reserved. Use of this source code is governed
// by a BSD-style license that can be found in the
// LICENSE file.
package gpx
import (
"bytes"
"encoding/xml"
"errors"
"io/ioutil"
"os"
"strings"
"time"
)
// An array cannot be constant :( The first one if the default layout:
var TIMELAYOUTS = []string{
"2006-01-02T15:04:05Z",
"2006-01-02T15:04:05",
"2006-01-02 15:04:05Z",
"2006-01-02 15:04:05",
}
func init() {
/*
fmt.Println("----------------------------------------------------------------------------------------------------")
fmt.Println("This API is experimental, it *will* change")
fmt.Println("----------------------------------------------------------------------------------------------------")
*/
}
type ToXmlParams struct {
Version string
Indent bool
}
/*
* Params are optional, you can set null to use GPXs Version and no indentation.
*/
func ToXml(g *GPX, params ToXmlParams) ([]byte, error) {
version := g.Version
if len(params.Version) > 0 {
version = params.Version
}
indentation := params.Indent
var gpxDoc interface{}
if version == "1.0" {
gpxDoc = convertToGpx10Models(g)
} else if version == "1.1" {
gpxDoc = convertToGpx11Models(g)
} else {
g.Version = "1.1"
gpxDoc = convertToGpx11Models(g)
}
var buffer bytes.Buffer
buffer.WriteString(xml.Header)
if indentation {
bytes, err := xml.MarshalIndent(gpxDoc, "", " ")
if err != nil {
return nil, err
}
buffer.Write(bytes)
} else {
bytes, err := xml.Marshal(gpxDoc)
if err != nil {
return nil, err
}
buffer.Write(bytes)
}
return buffer.Bytes(), nil
}
func guessGPXVersion(bytes []byte) (string, error) {
bytesCount := 1000
if len(bytes) < 1000 {
bytesCount = len(bytes)
}
startOfDocument := string(bytes[:bytesCount])
parts := strings.Split(startOfDocument, "<gpx")
if len(parts) <= 1 {
return "", errors.New("Invalid GPX file, cannot find version")
}
parts = strings.Split(parts[1], "version=")
if len(parts) <= 1 {
return "", errors.New("Invalid GPX file, cannot find version")
}
if len(parts[1]) < 10 {
return "", errors.New("Invalid GPX file, cannot find version")
}
result := parts[1][1:4]
return result, nil
}
func parseGPXTime(timestr string) (*time.Time, error) {
if strings.Contains(timestr, ".") {
// Probably seconds with milliseconds
timestr = strings.Split(timestr, ".")[0]
}
timestr = strings.Trim(timestr, " \t\n\r")
for _, timeLayout := range TIMELAYOUTS {
t, err := time.Parse(timeLayout, timestr)
if err == nil {
return &t, nil
}
}
return nil, errors.New("Cannot parse " + timestr)
}
func formatGPXTime(time *time.Time) string {
if time == nil {
return ""
}
if time.Year() <= 1 {
// Invalid date:
return ""
}
return time.Format(TIMELAYOUTS[0])
}
func ParseFile(fileName string) (*GPX, error) {
f, err := os.Open(fileName)
if err != nil {
return nil, err
}
defer f.Close()
bytes, err := ioutil.ReadAll(f)
if err != nil {
return nil, err
}
return ParseBytes(bytes)
}
func ParseBytes(bytes []byte) (*GPX, error) {
version, err := guessGPXVersion(bytes)
if err != nil {
// Unknown version, try with 1.1
version = "1.1"
}
if version == "1.0" {
g := &gpx10Gpx{}
err := xml.Unmarshal(bytes, &g)
if err != nil {
return nil, err
}
return convertFromGpx10Models(g), nil
} else if version == "1.1" {
g := &gpx11Gpx{}
err := xml.Unmarshal(bytes, &g)
if err != nil {
return nil, err
}
return convertFromGpx11Models(g), nil
} else {
return nil, errors.New("Invalid version:" + version)
}
}
func ParseString(str string) (*GPX, error) {
return ParseBytes([]byte(str))
}