使用戈朗更新 KML 文件中的节点

我正在使用一个KML文件,我用它来在谷歌地球内绘制线串。我正在从 USB 适配器接收 GPS 数据,并将坐标馈送到 Go 频道。我正在尝试读取通道并更新KML文件中的节点以添加到线弦中(从而绘制我的移动)。


以下是 KML 结构:


<?xml version="1.0" encoding="UTF-8"?>

<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2" xmlns:kml="http://www.opengis.net/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom">

<Folder>

    <name>Foo</name>

    <open>1</open>

    <Document>

        <name>Bar</name>

        <Placemark>

            <Style>

                <LineStyle>

                    <color>ff00ff00</color>

                    <width>5</width>

                </LineStyle>

                <PolyStyle>

                    <color>ff4080ff</color>

                    <fill>1</fill>

                    <outline>1</outline>

                </PolyStyle>

            </Style>

            <LineString>

                <tessellate>1</tessellate>

                <coordinates>

                    1.23411166666667,10.12345678901234,0 

                    1.23421166666667,10.12345678901234,0 

                    1.23431166666667,10.12345678901234,0 

                    1.23431166666667,10.32345678901234,0 

                </coordinates>

            </LineString>

        </Placemark>

    </Document>

</Folder>

</kml>

我希望追加到坐标节点。


我在想两种方法之一。首先解析文件并使用正则表达式查找并插入数据。其次,解析 XML 并查找更新节点中的值。后者似乎是更明智的选择,但是我在Google上搜索的所有内容都向我展示了如何将新节点添加到XML树中,而不是附加到现有条目中。</coordinates>


到目前为止,我所尝试的感觉就像一团糟,每次从频道读取时都低效地打开文件,最终不起作用。


type LineString struct {

    coordinates string `xml:"coordinates"`

}    


func plotLocation(c chan data.GpsPos) {

    /*

        continuously read from the channel

        use the location data to plot a breadcrumb trail

    */


    defer wg.Done()


    for currentCoords := range c {


        file, err := os.Open("/Users/me/foo.kml")

        if err != nil {

            log.Fatal(err)

        }


我是否做了一些明显错误的事情,是否有更好的方法将这些数据写入文件(每秒钟左右发生一次)?

萧十郎
浏览 103回答 1
1回答

慕沐林林

文件是否在应用程序之外发生更改?如果没有,那么您可以在循环之前解析一次文件,维护坐标列表,并在每次更改时将其写出,以便外部应用程序可以看到中间结果。如果您计划执行更多转换,或者想要在开始时从头开始生成整个文件,这也将非常有用。首先,您需要一个具有适当标记的结构(请参见 xml.Unmarshal)。我通常从在线生成器开始进行此类操作:// type definition adapted from https://www.onlinetool.io/xmltogo/type KML struct {&nbsp; &nbsp; XMLName xml.Name `xml:"kml"`&nbsp; &nbsp; Text&nbsp; &nbsp; string&nbsp; &nbsp;`xml:",chardata"`&nbsp; &nbsp; XMLNS&nbsp; &nbsp;string&nbsp; &nbsp;`xml:"xmlns,attr"`&nbsp; &nbsp; GX&nbsp; &nbsp; &nbsp; string&nbsp; &nbsp;`xml:"gx,attr"`&nbsp; &nbsp; KML&nbsp; &nbsp; &nbsp;string&nbsp; &nbsp;`xml:"kml,attr"`&nbsp; &nbsp; Atom&nbsp; &nbsp; string&nbsp; &nbsp;`xml:"atom,attr"`&nbsp; &nbsp; Folder&nbsp; struct {&nbsp; &nbsp; &nbsp; &nbsp; Text&nbsp; &nbsp; &nbsp;string `xml:",chardata"`&nbsp; &nbsp; &nbsp; &nbsp; Name&nbsp; &nbsp; &nbsp;string `xml:"name"`&nbsp; &nbsp; &nbsp; &nbsp; Open&nbsp; &nbsp; &nbsp;string `xml:"open"`&nbsp; &nbsp; &nbsp; &nbsp; Document struct {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Text&nbsp; &nbsp; &nbsp; string `xml:",chardata"`&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Name&nbsp; &nbsp; &nbsp; string `xml:"name"`&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Placemark struct {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Text&nbsp; string `xml:",chardata"`&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Style struct {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Text&nbsp; &nbsp; &nbsp; string `xml:",chardata"`&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LineStyle struct {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Text&nbsp; string `xml:",chardata"`&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Color string `xml:"color"`&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Width string `xml:"width"`&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } `xml:"LineStyle"`&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PolyStyle struct {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Text&nbsp; &nbsp; string `xml:",chardata"`&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Color&nbsp; &nbsp;string `xml:"color"`&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Fill&nbsp; &nbsp; string `xml:"fill"`&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Outline string `xml:"outline"`&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } `xml:"PolyStyle"`&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } `xml:"Style"`&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LineString struct {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Text&nbsp; &nbsp; &nbsp; &nbsp; string `xml:",chardata"`&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Tessellate&nbsp; string `xml:"tessellate"`&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Coordinates string `xml:"coordinates"`&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } `xml:"LineString"`&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } `xml:"Placemark"`&nbsp; &nbsp; &nbsp; &nbsp; } `xml:"Document"`&nbsp; &nbsp; } `xml:"Folder"`}&nbsp;我会为此做一些帮助:func readKML(filename string) (*KML, error) {&nbsp; f, err := os.Open(filename)&nbsp; if err != nil {&nbsp; &nbsp; return nil, fmt.Errorf("opening KML file: %w", err) // contains filename&nbsp; }&nbsp; defer f.Close() // reading, ignoring error is acceptable&nbsp; var kml KML&nbsp; if err := xml.NewDecoder(f).Decode(&kml); err != nil {&nbsp; &nbsp; return nil, fmt.Errorf("decoding XML from %q as KML: %w", filename, err)&nbsp; }&nbsp; return &kml, nil}func writeKML(filename string, kml *KML) error {&nbsp; f, err := os.Create(filename)&nbsp; if err != nil {&nbsp; &nbsp; return fmt.Errorf("creating KML file: %w", err) // contains filename&nbsp; }&nbsp; defer f.Close() // double close is OK for *os.File&nbsp; enc := xml.NewEncoder(f)&nbsp; enc.Indent("", "&nbsp; &nbsp; ")&nbsp; if err := enc.Encode(kml); err != nil {&nbsp; &nbsp; return nil, fmt.Errorf("encoding KML to %q: %w", filename, err)&nbsp; }&nbsp; return nil}然后你的循环可以看起来像这样:kml, err := readKML(filename)if err != nil {&nbsp; return err // contains context}coordinates := strings.Fields(kml.Folder.Document.Placemark.LineString.Coordinates)for coord := range incoming {&nbsp; line := fmt.Sprintf("%f,%f,%d\n", coord.Lat, coord.Long, 0)&nbsp; coordinates = append(coordinates, coord)&nbsp;&nbsp;&nbsp; kml.Folder.Document.Placemark.LineString.Coordinates = strings.Join(coordinates, "\n")&nbsp; if err := writeKML(filename, kml); err != nil {&nbsp; &nbsp; log.Printf("Warning: failed to update %q: %s", filename, err)&nbsp; }}在查看您拥有的代码时,我怀疑问题在于您正在延迟文件关闭,这将在函数返回时执行,而不是在循环继续时执行。您也可以使此方法正常工作,为此,我建议将逻辑分解为函数,以便可以独立测试每个部分,这也可能意味着您的延迟现在已在函数中正确限定。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go