如何在解析 XML 时获取一个空数组?

huangapple go评论102阅读模式
英文:

How to getting an empty array when parsing XML?

问题

我被委托编写一个Go实用程序,它接受一个XML文件,解析它,并以JSON格式返回。

以下是XML的示例:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <tracks clid="020">
  3. <track uuid="551" category="s" route="8" vehicle_type="trolleybus" >
  4. <point
  5. latitude="53.61491"
  6. longitude="55.90922"
  7. avg_speed="24"
  8. direction="270"
  9. time="13122022:072116"
  10. />
  11. </track>
  12. <track uuid="552" category="s" route="6" vehicle_type="trolleybus">
  13. <point
  14. latitude="53.68321"
  15. longitude="57.90922"
  16. avg_speed="42"
  17. direction="181"
  18. time="13122022:072216"
  19. />
  20. </track>
  21. </tracks>

我编写了以下代码:

  1. package main
  2. import (
  3. "encoding/json"
  4. "encoding/xml"
  5. "fmt"
  6. )
  7. type Tracks struct {
  8. XMLName xml.Name `xml:"tracks" json:"-"`
  9. Clid string `xml:"clid,attr" json:"clid"`
  10. Tracks []Track `xml:"track" json:"track_list"`
  11. }
  12. type Track struct {
  13. XMLName xml.Name `xml:"tracks"`
  14. Uuid string `xml:"uuid,attr" json:"uuid"`
  15. Category string `xml:"category,attr" json:"category"`
  16. Route string `xml:"route,attr" json:"route"`
  17. VehicleType string `xml:"vehicle_type,attr" json:"vehicle_type"`
  18. Point Point `xml:"point" json:"point"`
  19. }
  20. type Point struct {
  21. Latitude string `xml:"latitude,attr" json:"latitude"`
  22. Longitude string `xml:"longitude,attr" json:"longitude"`
  23. AvgSpeed string `xml:"avg_speed,attr" json:"avg_speed"`
  24. Direction string `xml:"direction,attr" json:"direction"`
  25. Time string `xml:"time,attr" json:"time"`
  26. }
  27. func main() {
  28. rawXmlData := `
  29. <?xml version="1.0" encoding="utf-8"?>
  30. <tracks clid="020">
  31. <track uuid="551" category="s" route="8" vehicle_type="trolleybus">
  32. <point latitude="53.61491" longitude="55.90922" avg_speed="24" direction="270" time="13122022:072116"/>
  33. </track>
  34. <track uuid="552" category="s" route="6" vehicle_type="trolleybus">
  35. <point latitude="53.68321" longitude="57.90922" avg_speed="42" direction="181" time="13122022:072216"/>
  36. </track>
  37. </tracks>
  38. `
  39. var tracks Tracks
  40. err := xml.Unmarshal([]byte(rawXmlData), &tracks)
  41. if err != nil {
  42. log.Fatal(err)
  43. }
  44. jsonData, err := json.Marshal(tracks)
  45. if err != nil {
  46. log.Fatal(err)
  47. }
  48. fmt.Printf(string(jsonData))
  49. }

但是,不幸的是,它不起作用。我在控制台中得到以下错误:

  1. 2009/11/10 23:00:00 expected element type <tracks> but have <track>

我做错了什么?我该如何解决这个问题?

英文:

I was tasked with writing a Go utility that takes an XML file, parses it, and returns it in JSON.

Here is an example of the XML:

  1. &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
  2. &lt;tracks clid=&quot;020&quot;&gt;
  3. &lt;track uuid=&quot;551&quot; category=&quot;s&quot; route=&quot;8&quot; vehicle_type=&quot;trolleybus&quot; &gt;
  4. &lt;point
  5. latitude=&quot;53.61491&quot;
  6. longitude=&quot;55.90922&quot;
  7. avg_speed=&quot;24&quot;
  8. direction=&quot;270&quot;
  9. time=&quot;13122022:072116&quot;
  10. /&gt;
  11. &lt;/track&gt;
  12. &lt;track uuid=&quot;552&quot; category=&quot;s&quot; route=&quot;6&quot; vehicle_type=&quot;trolleybus&quot;&gt;
  13. &lt;point
  14. latitude=&quot;53.68321&quot;
  15. longitude=&quot;57.90922&quot;
  16. avg_speed=&quot;42&quot;
  17. direction=&quot;181&quot;
  18. time=&quot;13122022:072216&quot;
  19. /&gt;
  20. &lt;/track&gt;
  21. &lt;/tracks&gt;

I wrote the following code:

  1. package main
  2. import (
  3. &quot;encoding/json&quot;
  4. &quot;encoding/xml&quot;
  5. &quot;fmt&quot;
  6. )
  7. type Tracks struct {
  8. XMLName xml.Name `xml:&quot;tracks&quot; json:&quot;-&quot;`
  9. Clid string `xml:&quot;clid,attr&quot; json:&quot;clid&quot;`
  10. Tracks []Track `xml:&quot;track&quot; json:&quot;track_list&quot;`
  11. }
  12. type Track struct {
  13. XMLName xml.Name `xml:&quot;tracks&quot;`
  14. Uuid string `xml:&quot;uuid,attr&quot; json:&quot;uuid&quot;`
  15. Category string `xml:&quot;category,attr&quot; json:&quot;category&quot;`
  16. Route string `xml:&quot;route,attr&quot; json:&quot;route&quot;`
  17. VehicleType string `xml:&quot;vehicle_type,attr&quot; json:&quot;vehicle_type&quot;`
  18. Point Point `xml:&quot;point&quot; json:&quot;point&quot;`
  19. }
  20. type Point struct {
  21. Latitude string `xml:&quot;latitude,attr&quot; json:&quot;latitude&quot;`
  22. Longitude string `xml:&quot;longitude,attr&quot; json:&quot;longitude&quot;`
  23. AvgSpeed string `xml:&quot;avg_speed,attr&quot; json:&quot;avg_speed&quot;`
  24. Direction string `xml:&quot;direction,attr&quot; json:&quot;direction&quot;`
  25. Time string `xml:&quot;time,attr&quot; json:&quot;time&quot;`
  26. }
  27. func main() {
  28. rawXmlData := `
  29. &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
  30. &lt;tracks clid=&quot;020&quot;&gt;
  31. &lt;track uuid=&quot;551&quot; category=&quot;s&quot; route=&quot;8&quot; vehicle_type=&quot;trolleybus&quot;&gt;
  32. &lt;point latitude=&quot;53.61491&quot; longitude=&quot;55.90922&quot; avg_speed=&quot;24&quot; direction=&quot;270&quot; time=&quot;13122022:072116&quot;/&gt;
  33. &lt;/track&gt;
  34. &lt;track uuid=&quot;552&quot; category=&quot;s&quot; route=&quot;6&quot; vehicle_type=&quot;trolleybus&quot;&gt;
  35. &lt;point latitude=&quot;53.68321&quot; longitude=&quot;57.90922&quot; avg_speed=&quot;42&quot; direction=&quot;181&quot; time=&quot;13122022:072216&quot;/&gt;
  36. &lt;/track&gt;
  37. &lt;/tracks&gt;
  38. `
  39. var tracks Tracks
  40. err := xml.Unmarshal([]byte(rawXmlData), &amp;tracks)
  41. if err != nil {
  42. log.Fatal(err)
  43. }
  44. jsonData, err := json.Marshal(tracks)
  45. if err != nil {
  46. log.Fatal(err)
  47. }
  48. fmt.Printf(string(jsonData))
  49. }

Go.dev

But, unfortunately, it doesn't work. I get the following in the console:

  1. 2009/11/10 23:00:00 expected element type &lt;tracks&gt; but have &lt;track&gt;

What am I doing wrong? How can I solve this problem?

答案1

得分: 2

我觉得我会将讨论转移到一个答案上,因为我认为你很接近了。正如我之前提到的,你需要检查xml.Unmarshal返回的错误。代码可能如下所示:

  1. if err := xml.Unmarshal([]byte(rawXmlData), &tracks); err != nil {
  2. panic(err)
  3. }

现在你的代码中有有效的XML数据,我们可以生成有意义的错误;通过上述错误检查,运行你的代码会产生以下输出:

  1. panic: expected element type <tracks> but have <track>
  2. goroutine 1 [running]:
  3. main.main()
  4. /home/lars/tmp/go/main.go:48 +0x12f

这是因为你的数据结构中有一个小错误;在Track结构体的定义中,你有:

  1. type Track struct {
  2. XMLName xml.Name `xml:"tracks"`
  3. Uuid string `xml:"uuid,attr" json:"uuid"`
  4. Category string `xml:"category,attr" json:"category"`
  5. Route string `xml:"route,attr" json:"route"`
  6. VehicleType string `xml:"vehicle_type,attr" json:"vehicle_type"`
  7. Point Point `xml:"point" json:"point"`
  8. }

你将XMLName属性的标签错误地标记为tracks,而应该是track

  1. type Track struct {
  2. XMLName xml.Name `xml:"track"`
  3. Uuid string `xml:"uuid,attr" json:"uuid"`
  4. Category string `xml:"category,attr" json:"category"`
  5. Route string `xml:"route,attr" json:"route"`
  6. VehicleType string `xml:"vehicle_type,attr" json:"vehicle_type"`
  7. Point Point `xml:"point" json:"point"`
  8. }

最后,这与问题没有直接关系,但你应该避免将变量命名为error,因为那是内置的错误数据类型的名称。我会修改你对json.Marshal的调用,如下所示:

  1. jsonData, err := json.Marshal(tracks)
  2. if err != nil {
  3. panic(err)
  4. }

你不需要在错误上使用panic();这只是一种方便的方式来退出代码。


在进行这些更改后,如果我们编译并运行代码,我们会得到以下输出(使用jq格式化):

  1. {
  2. "clid": "020",
  3. "track_list": [
  4. {
  5. "XMLName": {
  6. "Space": "",
  7. "Local": "track"
  8. },
  9. "uuid": "551",
  10. "category": "s",
  11. "route": "8",
  12. "vehicle_type": "trolleybus",
  13. "point": {
  14. "latitude": "53.61491",
  15. "longitude": "55.90922",
  16. "avg_speed": "24",
  17. "direction": "270",
  18. "time": "13122022:072116"
  19. }
  20. },
  21. {
  22. "XMLName": {
  23. "Space": "",
  24. "Local": "track"
  25. },
  26. "uuid": "552",
  27. "category": "s",
  28. "route": "6",
  29. "vehicle_type": "trolleybus",
  30. "point": {
  31. "latitude": "53.68321",
  32. "longitude": "57.90922",
  33. "avg_speed": "42",
  34. "direction": "181",
  35. "time": "13122022:072216"
  36. }
  37. }
  38. ]
  39. }

请注意,你甚至不需要在结构体中使用XMLName元素;如果我们完全删除它,使得结构体如下所示:

  1. type Track struct {
  2. Uuid string `xml:"uuid,attr" json:"uuid"`
  3. Category string `xml:"category,attr" json:"category"`
  4. Route string `xml:"route,attr" json:"route"`
  5. VehicleType string `xml:"vehicle_type,attr" json:"vehicle_type"`
  6. Point Point `xml:"point" json:"point"`
  7. }

那么我们会得到以下输出(使用jq格式化):

  1. {
  2. "clid": "020",
  3. "track_list": [
  4. {
  5. "uuid": "551",
  6. "category": "s",
  7. "route": "8",
  8. "vehicle_type": "trolleybus",
  9. "point": {
  10. "latitude": "53.61491",
  11. "longitude": "55.90922",
  12. "avg_speed": "24",
  13. "direction": "270",
  14. "time": "13122022:072116"
  15. }
  16. },
  17. {
  18. "uuid": "552",
  19. "category": "s",
  20. "route": "6",
  21. "vehicle_type": "trolleybus",
  22. "point": {
  23. "latitude": "53.68321",
  24. "longitude": "57.90922",
  25. "avg_speed": "42",
  26. "direction": "181",
  27. "time": "13122022:072216"
  28. }
  29. }
  30. ]
  31. }
英文:

I thought I would move the discussion to an answer, since I think you're pretty close. As I mentioned, you need to check the error returned by xml.Unmarshal. That might look like this:

  1. if err := xml.Unmarshal([]byte(rawXmlData), &amp;tracks); err != nil {
  2. panic(err)
  3. }

Now that you have valid XML data in your code, we can produce meaningful errors; with the above error check in place, running your code produces:

  1. panic: expected element type &lt;tracks&gt; but have &lt;track&gt;
  2. goroutine 1 [running]:
  3. main.main()
  4. /home/lars/tmp/go/main.go:48 +0x12f

That's happening because of a minor typo in your data structures; in the definition of your Track struct, you have:

  1. type Track struct {
  2. XMLName xml.Name `xml:&quot;tracks&quot;`
  3. Uuid string `xml:&quot;uuid,attr&quot; json:&quot;uuid&quot;`
  4. Category string `xml:&quot;category,attr&quot; json:&quot;category&quot;`
  5. Route string `xml:&quot;route,attr&quot; json:&quot;route&quot;`
  6. VehicleType string `xml:&quot;vehicle_type,attr&quot; json:&quot;vehicle_type&quot;`
  7. Point Point `xml:&quot;point&quot; json:&quot;point&quot;`
  8. }

You've mis-tagged the XMLName attribute as tracks when it should be track:

  1. type Track struct {
  2. XMLName xml.Name `xml:&quot;track&quot;`
  3. Uuid string `xml:&quot;uuid,attr&quot; json:&quot;uuid&quot;`
  4. Category string `xml:&quot;category,attr&quot; json:&quot;category&quot;`
  5. Route string `xml:&quot;route,attr&quot; json:&quot;route&quot;`
  6. VehicleType string `xml:&quot;vehicle_type,attr&quot; json:&quot;vehicle_type&quot;`
  7. Point Point `xml:&quot;point&quot; json:&quot;point&quot;`
  8. }

Lastly -- and this isn't directly related to the problem -- you should avoid naming a variable error, because that's the name of the built-in data type of errors. I would modify your call to json.Marshal like this:

  1. jsonData, err := json.Marshal(tracks)
  2. if err != nil {
  3. panic(err)
  4. }

You don't need to panic() on errors; this is just a convenient way to bail out of the code.


With these changes in place, if we compile and run the code we get as output (formatted with jq):

  1. {
  2. &quot;clid&quot;: &quot;020&quot;,
  3. &quot;track_list&quot;: [
  4. {
  5. &quot;XMLName&quot;: {
  6. &quot;Space&quot;: &quot;&quot;,
  7. &quot;Local&quot;: &quot;track&quot;
  8. },
  9. &quot;uuid&quot;: &quot;551&quot;,
  10. &quot;category&quot;: &quot;s&quot;,
  11. &quot;route&quot;: &quot;8&quot;,
  12. &quot;vehicle_type&quot;: &quot;trolleybus&quot;,
  13. &quot;point&quot;: {
  14. &quot;latitude&quot;: &quot;53.61491&quot;,
  15. &quot;longitude&quot;: &quot;55.90922&quot;,
  16. &quot;avg_speed&quot;: &quot;24&quot;,
  17. &quot;direction&quot;: &quot;270&quot;,
  18. &quot;time&quot;: &quot;13122022:072116&quot;
  19. }
  20. },
  21. {
  22. &quot;XMLName&quot;: {
  23. &quot;Space&quot;: &quot;&quot;,
  24. &quot;Local&quot;: &quot;track&quot;
  25. },
  26. &quot;uuid&quot;: &quot;552&quot;,
  27. &quot;category&quot;: &quot;s&quot;,
  28. &quot;route&quot;: &quot;6&quot;,
  29. &quot;vehicle_type&quot;: &quot;trolleybus&quot;,
  30. &quot;point&quot;: {
  31. &quot;latitude&quot;: &quot;53.68321&quot;,
  32. &quot;longitude&quot;: &quot;57.90922&quot;,
  33. &quot;avg_speed&quot;: &quot;42&quot;,
  34. &quot;direction&quot;: &quot;181&quot;,
  35. &quot;time&quot;: &quot;13122022:072216&quot;
  36. }
  37. }
  38. ]
  39. }

Note that you don't even need that XMLName element in your structure; if we remove it completely so that we have:

  1. type Track struct {
  2. Uuid string `xml:&quot;uuid,attr&quot; json:&quot;uuid&quot;`
  3. Category string `xml:&quot;category,attr&quot; json:&quot;category&quot;`
  4. Route string `xml:&quot;route,attr&quot; json:&quot;route&quot;`
  5. VehicleType string `xml:&quot;vehicle_type,attr&quot; json:&quot;vehicle_type&quot;`
  6. Point Point `xml:&quot;point&quot; json:&quot;point&quot;`
  7. }

Then we get as output (formatted with jq):

  1. {
  2. &quot;clid&quot;: &quot;020&quot;,
  3. &quot;track_list&quot;: [
  4. {
  5. &quot;uuid&quot;: &quot;551&quot;,
  6. &quot;category&quot;: &quot;s&quot;,
  7. &quot;route&quot;: &quot;8&quot;,
  8. &quot;vehicle_type&quot;: &quot;trolleybus&quot;,
  9. &quot;point&quot;: {
  10. &quot;latitude&quot;: &quot;53.61491&quot;,
  11. &quot;longitude&quot;: &quot;55.90922&quot;,
  12. &quot;avg_speed&quot;: &quot;24&quot;,
  13. &quot;direction&quot;: &quot;270&quot;,
  14. &quot;time&quot;: &quot;13122022:072116&quot;
  15. }
  16. },
  17. {
  18. &quot;uuid&quot;: &quot;552&quot;,
  19. &quot;category&quot;: &quot;s&quot;,
  20. &quot;route&quot;: &quot;6&quot;,
  21. &quot;vehicle_type&quot;: &quot;trolleybus&quot;,
  22. &quot;point&quot;: {
  23. &quot;latitude&quot;: &quot;53.68321&quot;,
  24. &quot;longitude&quot;: &quot;57.90922&quot;,
  25. &quot;avg_speed&quot;: &quot;42&quot;,
  26. &quot;direction&quot;: &quot;181&quot;,
  27. &quot;time&quot;: &quot;13122022:072216&quot;
  28. }
  29. }
  30. ]
  31. }

答案2

得分: 1

你好!以下是你要翻译的内容:

  1. type Track struct {
  2. XMLName xml.Name `xml:"tracks"`

应该是 "track" 而不是 "tracks"。

链接

英文:
  1. type Track struct {
  2. XMLName xml.Name `xml:&quot;tracks&quot;`

should be "track" not "tracks"

https://go.dev/play/p/kg-Dyep8Fv9

huangapple
  • 本文由 发表于 2022年12月13日 22:13:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/74786207.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定