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