首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >xml解析航线文件kmz-goland

xml解析航线文件kmz-goland

原创
作者头像
王宝
发布2025-02-05 11:29:45
发布2025-02-05 11:29:45
66900
代码可运行
举报
文章被收录于专栏:核心思路逻辑核心思路逻辑
运行总次数:0
代码可运行

术语:

航线文件:后缀以kmz结尾的文件,本质是一个压缩包,可通过压缩包解压得到

WPML 是WayPointMarkupLanguage 的缩写,即航线文件格式标准。WPML 航线文件格式标准基于 KML(Keyhole Markup Language)的定义进行扩展。WPML 航线文件遵循 KMZ 归档要求,所有航线文件以 “.kmz” 后缀结尾。WPML 航线文件格式标准作为航线数字资产的载体

解压后如下图文件:

背景

通过go语言实现对kmz文件中wpml航线规划的解析,获取相应航线轨迹、航点动作等信息

流程图

说明:

主要功能是从指定路径下载KMZ文件,解压并解析其中的KML内容。具体步骤如下:

1. 下载KMZ文件到本地。

2. 解压KMZ文件,查找并读取特定的KML文件内容。

3. 清洗XML字符串,替换特定前缀。

4. 解析清洗后的XML字符串为WPML结构。

逻辑代码

以下代码为解析kmz包中的waylines.wpml是飞机直接执行的文件

核心逻辑代码文件:kmzprase_test.go

代码语言:javascript
代码运行次数:0
运行
复制
package kmzPrase

import (
    "archive/zip"
    "bytes"
    "encoding/xml"
    "errors"
    "fmt"
    "io"
    "io/ioutil"
    "log"
    "net/http"
    "net/url"
    "os"
    "path/filepath"
    "strings"
    "testing"
)

func TestUnzipKMZ(t *testing.T) {

    rawURL := "./20250102.kmz"
    filePath, err := downLoadFile(rawURL)

    body, err := unzipKMZ(filePath)
    if err != nil {
       fmt.Println("unzipKMZ err:", err)
       return
    }

    cleanedXmlStr := string(body)
    fmt.Println(cleanedXmlStr)

    cleanedXmlStr = strings.Replace(cleanedXmlStr, "xmlns:", "xmlns-", 1)
    cleanedXmlStr = strings.ReplaceAll(cleanedXmlStr, "wpml:", "wpml-")

    var kml WPML
    if err := xml.Unmarshal([]byte(cleanedXmlStr), &kml); err != nil {
       fmt.Println("解析失败:", err)
       return
    }

}
func downLoadFile(rawURL string) (string, error) {

    localPath, err := os.Getwd()

    if err != nil {
       return localPath, err
    }

    parsedURL, err := url.Parse(rawURL)

    // 获取文件名
    filename := filepath.Base(parsedURL.Path)

    if err != nil {
       return localPath, errors.New(fmt.Sprintf("Parse raw url err: %s\n", err))
    }

    // Send HTTP GET request
    resp, err := http.Get(rawURL)
    if err != nil {
       return localPath, errors.New(fmt.Sprintf("Error while making GET request: %s\n", err))
    }
    defer resp.Body.Close() // Ensure the body is closed when we're done with it

    // Check if the request was successful (status code 200)
    if resp.StatusCode != http.StatusOK {
       return localPath, errors.New(fmt.Sprintf("Failed to download file: %s\n", err))
    }

    // Read the response body
    body, err := io.ReadAll(resp.Body)
    if err != nil {

       return localPath, errors.New(fmt.Sprintf("Error reading response body: %s\n", err))
    }

    localPath += "/" + filename
    // write it to a file:
    err = os.WriteFile(filename, body, 0644) // Go 1.16+ syntax
    if err != nil {
       return localPath, errors.New(fmt.Sprintf("Error writing to file: %s\n", err))
    } else {
       return localPath, nil
    }
}
func unzipKMZ(path string) ([]byte, error) {
    result := []byte{}

    r, err := zip.OpenReader(path)
    if err != nil {
       return result, err
    }
    defer r.Close()

    for _, f := range r.File {
       if f.Name == "wpmz/waylines.wpml" { // 假设KML文件名为doc.kml
          rc, err := f.Open()
          if err != nil {
             return result, err
          }
          defer rc.Close()
          buf := new(bytes.Buffer)
          _, err = io.Copy(buf, rc)
          if err != nil {
             return result, err
          }

          kmlContent, err := ioutil.ReadAll(buf)
          if err != nil {
             log.Fatal(err)
          }
          return kmlContent, nil // 返回KML内容的字符串表示
          //return buf.String(), nil // 返回KML内容的字符串表示
       }
    }
    return result, fmt.Errorf("KML file not found in KMZ")
}

主结构体文件:waylines_wpml.go

代码语言:javascript
代码运行次数:0
运行
复制
package kmzPrase

import (
    "encoding/xml"
)

type WPMLHeader struct {
    XMLName xml.Name `xml:"kml"`
}

type WPML struct {
    XMLName   xml.Name     `xml:"kml"`
    XMLNS     string       `xml:"xmlns,attr"`
    XMLNSWPML string       `xml:"xmlns-wpml,attr"`
    Document  DocumentWPML `xml:"Document"`
}

type DocumentWPML struct {
    MissionConfig MissionConfigWPML `xml:"wpml-missionConfig"`
    Folder        FolderWPML        `xml:"Folder"`
}

type MissionConfigWPML struct {
    FlyToWaylineMode        string      `xml:"wpml-flyToWaylineMode"`
    FinishAction            string      `xml:"wpml-finishAction"`
    ExitOnRCLost            string      `xml:"wpml-exitOnRCLost"`
    ExecuteRCLostAction     string      `xml:"wpml-executeRCLostAction"`
    TakeOffSecurityHeight   float64     `xml:"wpml-takeOffSecurityHeight"`
    GlobalTransitionalSpeed float64     `xml:"wpml-globalTransitionalSpeed"`
    DroneInfo               DroneInfo   `xml:"wpml-droneInfo"`
    PayloadInfo             PayloadInfo `xml:"wpml-payloadInfo"`
}

type FolderWPML struct {
    TemplateID        int             `xml:"wpml-templateId"`
    ExecuteHeightMode string          `xml:"wpml-executeHeightMode"`
    WaylineID         int             `xml:"wpml-waylineId"`
    AutoFlightSpeed   int             `xml:"wpml-autoFlightSpeed"`
    Placemarks        []PlacemarkWPML `xml:"Placemark"`
}

type PlacemarkWPML struct {
    IsRisky              int `xml:"wpml-isRisky,omitempty"`
    Point                Point
    Index                int                  `xml:"wpml-index"`
    ExecuteHeight        int                  `xml:"wpml-executeHeight"`
    WaypointSpeed        int16                `xml:"wpml-waypointSpeed"`
    WaypointHeadingParam WaypointHeadingParam `xml:"wpml-waypointHeadingParam"`
    WaypointTurnParam    WaypointTurnParam    `xml:"wpml-waypointTurnParam"`
    UseStraightLine      int                  `xml:"wpml-useStraightLine,omitempty"`
    ActionGroup          *ActionGroup         `xml:"wpml-actionGroup"`
}

公共结构体文件:common.go

代码语言:javascript
代码运行次数:0
运行
复制
package kmzPrase

type DroneInfo struct {
    DroneEnumValue    int `xml:"wpml-droneEnumValue"`
    DroneSubEnumValue int `xml:"wpml-droneSubEnumValue"`
}

type PayloadInfo struct {
    PayloadEnumValue int `xml:"wpml-payloadEnumValue"`
    //PayloadSubEnumValue  int `xml:"wpml-payloadSubEnumValue"`
    PayloadPositionIndex int `xml:"wpml-payloadPositionIndex"`
}

type Point struct {
    Coordinates string `xml:"coordinates"`
}

type WaypointHeadingParam struct { //UseGlobalHeadingParam为0时必有
    WaypointHeadingMode     string  `xml:"wpml-waypointHeadingMode"`
    WaypointHeadingAngle    float64 `xml:"wpml-waypointHeadingAngle"`
    WaypointPoiPoint        string  `xml:"wpml-waypointPoiPoint"` //仅当wpml-waypointHeadingMode为towardPOI时必需
    WaypointHeadingPathMode string  `xml:"wpml-waypointHeadingPathMode"`
}

type WaypointTurnParam struct {
    WaypointTurnMode        string  `xml:"wpml-waypointTurnMode"`
    WaypointTurnDampingDist float64 `xml:"wpml-waypointTurnDampingDist,omitempty"`
}

type PayloadParam struct {
    PayloadPositionIndex int    `xml:"wpml-payloadPositionIndex"`
    FocusMode            string `xml:"wpml-focusMode,omitempty"`
    MeteringMode         string `xml:"wpml-meteringMode,omitempty"`
    ReturnMode           string `xml:"wpml-returnMode,omitempty"`
    SamplingRate         int    `xml:"wpml-samplingRate,omitempty"`
    ScanningMode         string `xml:"wpml-scanningMode,omitempty"`
    ImageFormat          string `xml:"wpml-imageFormat"`
}

// ActionGroup contains actions to be executed at a waypoint.
type ActionGroup struct {
    ActionGroupId         int           `xml:"wpml-actionGroupId"`
    ActionGroupStartIndex int           `xml:"wpml-actionGroupStartIndex"`
    ActionGroupEndIndex   int           `xml:"wpml-actionGroupEndIndex"`
    ActionGroupMode       string        `xml:"wpml-actionGroupMode"`
    ActionTrigger         ActionTrigger `xml:"wpml-actionTrigger"`
    Actions               []Action      `xml:"wpml-action"`
}

// ActionTrigger contains trigger information for the action group.
type ActionTrigger struct {
    ActionTriggerType string `xml:"wpml-actionTriggerType"`
}

// Action represents a single action to be executed.
type Action struct {
    ActionId                int         `xml:"wpml-actionId"`
    ActionActuatorFunc      string      `xml:"wpml-actionActuatorFunc"`
    ActionActuatorFuncParam interface{} `xml:"wpml-actionActuatorFuncParam"`
}

// ActionActuatorFuncParam contains parameters for the action actuator function.
type TakePhotoActionActuatorFuncParam struct {
    PayloadPositionIndex      string `xml:"wpml-payloadPositionIndex"`
    FileSuffix                string `xml:"wpml-fileSuffix"`
    PayloadLensIndex          int    `xml:"wpml-payloadLensIndex"`
    UseGlobalPayloadLensIndex int    `xml:"wpml-useGlobalPayloadLensIndex"`
}

type StartRecordActionActuatorFuncParam struct {
    PayloadPositionIndex      string `xml:"wpml-payloadPositionIndex"`
    FileSuffix                string `xml:"wpml-fileSuffix"`
    PayloadLensIndex          int    `xml:"wpml-payloadLensIndex"`
    UseGlobalPayloadLensIndex int    `xml:"wpml-useGlobalPayloadLensIndex"`
}

type StopRecordActionActuatorFuncParam struct {
    PayloadPositionIndex string `xml:"wpml-payloadPositionIndex"`
    FileSuffix           string `xml:"wpml-payloadLensIndex"`
}

type FocusActionActuatorFuncParam struct {
    PayloadPositionIndex string `xml:"wpml-payloadPositionIndex"`
    IsPointFocus         string `xml:"wpml-isPointFocus"`
    FocusX               string `xml:"wpml-focusX"`
    FocusY               string `xml:"wpml-focusY"`
    FocusRegionWidth     string `xml:"wpml-focusRegionWidth"`
    FocusRegionHeight    string `xml:"wpml-focusRegionHeight"`
    IsInfiniteFocus      string `xml:"wpml-isInfiniteFocus"`
}

type ZoomActionActuatorFuncParam struct {
    PayloadPositionIndex string `xml:"wpml-payloadPositionIndex"`
    FocalLength          string `xml:"wpml-focalLength"`
}

type CustomDirNameActionActuatorFuncParam struct {
    PayloadPositionIndex string `xml:"wpml-payloadPositionIndex"`
    DirectoryName        string `xml:"wpml-directoryName"`
}

type GimbalRotateActionActuatorFuncParam struct {
    PayloadPositionIndex    int     `xml:"wpml-payloadPositionIndex"`
    GimbalHeadingYawBase    string  `xml:"wpml-gimbalHeadingYawBase"`
    GimbalRotateMode        string  `xml:"wpml-gimbalRotateMode"`
    GimbalPitchRotateEnable bool    `xml:"wpml-gimbalPitchRotateEnable"`
    GimbalPitchRotateAngle  float64 `xml:"wpml-gimbalPitchRotateAngle"`
    GimbalRollRotateEnable  bool    `xml:"wpml-gimbalRollRotateEnable"`
    GimbalRollRotateAngle   float64 `xml:"wpml-gimbalRollRotateAngle"`
    GimbalYawRotateEnable   bool    `xml:"wpml-gimbalYawRotateEnable"`
    GimbalYawRotateAngle    float64 `xml:"wpml-gimbalYawRotateAngle"`
    GimbalRotateTimeEnable  bool    `xml:"wpml-gimbalRotateTimeEnable"`
    GimbalRotateTime        float64 `xml:"wpml-gimbalRotateTime"`
}

type GimbalEvenlyRotateActionActuatorFuncParam struct {
    GimbalPitchRotateAngle float64 `xml:"wpml-gimbalPitchRotateAngle"`
    PayloadPositionIndex   int     `xml:"wpml-payloadPositionIndex"`
}

type RotateYawRotateActionActuatorFuncParam struct {
    AircraftHeading  float64 `xml:"wpml-aircraftHeading"`
    AircraftPathMode int     `xml:"wpml-aircraftPathMode"`
}

type AccurateShootActionActuatorFuncParam struct {
    AircraftHeading  float64 `xml:"wpml-aircraftHeading"`
    AircraftPathMode int     `xml:"wpml-aircraftPathMode"`
}

type HoverActionActuatorFuncParam struct {
    HoverTime float64 `xml:"wpml-hoverTime"`
}

type OrientedShootActionActuatorFuncParam struct {
    GimbalPitchRotateAngle    float64 `xml:"wpml-gimbalPitchRotateAngle"`
    GimbalYawRotateAngle      float64 `xml:"wpml-gimbalYawRotateAngle"`
    FocusX                    int     `xml:"wpml-focusX"`
    FocusY                    int     `xml:"wpml-focusY"`
    FocusRegionWidth          int     `xml:"wpml-focusRegionWidth"`
    FocusRegionHeight         int     `xml:"wpml-focusRegionHeight"`
    FocalLength               float64 `xml:"wpml-focalLength"`
    AircraftHeading           float64 `xml:"wpml-aircraftHeading"`
    AccurateFrameValid        bool    `xml:"wpml-accurateFrameValid"`
    PayloadPositionIndex      int     `xml:"wpml-payloadPositionIndex"`
    PayloadLensIndex          string  `xml:"wpml-payloadLensIndex"`
    UseGlobalPayloadLensIndex bool    `xml:"wpml-useGlobalPayloadLensIndex"`
    TargetAngle               float64 `xml:"wpml-targetAngle"`
    ActionUUID                string  `xml:"wpml-actionUUID"`
    ImageWidth                int     `xml:"wpml-imageWidth"`
    ImageHeight               int     `xml:"wpml-imageHeight"`
    AFPos                     int     `xml:"wpml-AFPos"`
    GimbalPort                int     `xml:"wpml-gimbalPort"`
    OrientedCameraType        int     `xml:"wpml-orientedCameraType"`
    OrientedFilePath          string  `xml:"wpml-orientedFilePath"`
    OrientedFileMD5           string  `xml:"wpml-orientedFileMD5"`
    OrientedFileSize          int     `xml:"wpml-orientedFileSize"`
    OrientedFileSuffix        string  `xml:"wpml-orientedFileSuffix"`
    OrientedCameraApertue     int     `xml:"wpml-orientedCameraApertue"`
    OrientedCameraLuminance   int     `xml:"wpml-orientedCameraLuminance"`
    OrientedCameraShutterTime float64 `xml:"wpml-orientedCameraShutterTime"`
    OrientedCameraISO         int     `xml:"wpml-orientedCameraISO"`
    OrientedPhotoMode         string  `xml:"wpml-orientedPhotoMode"`
}

type PanoShotActionActuatorFuncParam struct {
    PayloadPositionIndex      int    `xml:"wpml-payloadPositionIndex"`
    PayloadLensIndex          string `xml:"wpml-payloadLensIndex"`
    UseGlobalPayloadLensIndex bool   `xml:"wpml-useGlobalPayloadLensIndex"`
    PanoShotSubMode           string `xml:"wpml-panoShotSubMode"`
}

type RecordPointCloudActionActuatorFuncParam struct {
    PayloadPositionIndex    string `xml:"wpml-payloadPositionIndex"`
    RecordPointCloudOperate string `xml:"wpml-recordPointCloudOperate"`
}

注意事项:

wpml或kml后缀的文件内容是xml格式,但标签结构是以【:】进行分割,导致无法通过xml表解析数据,故而需要将字符串中【wpml:】替换为【wpml-】可进行解析,如下图所示:

xml格式中标签通过[:]分割
xml格式中标签通过[:]分割

参考文献:

航线文件格式标准

https://developer.dji.com/doc/cloud-api-tutorial/cn/api-reference/dji-wpml/overview.html

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 术语:
  • 背景
  • 流程图
  • 逻辑代码
    • 核心逻辑代码文件:kmzprase_test.go
    • 主结构体文件:waylines_wpml.go
    • 公共结构体文件:common.go
  • 注意事项:
  • 参考文献:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档