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

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

How to getting an empty array when parsing XML?

问题

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

以下是XML的示例:

<?xml version="1.0" encoding="utf-8"?>
<tracks clid="020">
  <track uuid="551" category="s" route="8" vehicle_type="trolleybus" >
    <point
      latitude="53.61491"
      longitude="55.90922"
      avg_speed="24"
      direction="270"
      time="13122022:072116"
    />
  </track>
  <track uuid="552" category="s" route="6" vehicle_type="trolleybus">
    <point
      latitude="53.68321"
      longitude="57.90922"
      avg_speed="42"
      direction="181"
      time="13122022:072216"
    />
  </track>
</tracks>

我编写了以下代码:

package main

import (
	"encoding/json"
	"encoding/xml"
	"fmt"
)

type Tracks struct {
	XMLName xml.Name `xml:"tracks" json:"-"`
	Clid    string   `xml:"clid,attr" json:"clid"`
	Tracks  []Track  `xml:"track" json:"track_list"`
}

type Track struct {
	XMLName     xml.Name `xml:"tracks"`
	Uuid        string   `xml:"uuid,attr" json:"uuid"`
	Category    string   `xml:"category,attr" json:"category"`
	Route       string   `xml:"route,attr" json:"route"`
	VehicleType string   `xml:"vehicle_type,attr" json:"vehicle_type"`
	Point       Point    `xml:"point" json:"point"`
}

type Point struct {
	Latitude  string `xml:"latitude,attr" json:"latitude"`
	Longitude string `xml:"longitude,attr" json:"longitude"`
	AvgSpeed  string `xml:"avg_speed,attr" json:"avg_speed"`
	Direction string `xml:"direction,attr" json:"direction"`
	Time      string `xml:"time,attr" json:"time"`
}

func main() {
	rawXmlData := `
		<?xml version="1.0" encoding="utf-8"?>
		<tracks clid="020">
			<track uuid="551" category="s" route="8" vehicle_type="trolleybus">
				<point latitude="53.61491" longitude="55.90922" avg_speed="24" direction="270" time="13122022:072116"/>
			</track>
			<track uuid="552" category="s" route="6" vehicle_type="trolleybus">
				<point latitude="53.68321" longitude="57.90922" avg_speed="42" direction="181" time="13122022:072216"/>
			</track>
		</tracks>
	`

	var tracks Tracks

	err := xml.Unmarshal([]byte(rawXmlData), &tracks)
	if err != nil {
		log.Fatal(err)
	}

	jsonData, err := json.Marshal(tracks)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf(string(jsonData))
}

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

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:

&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;tracks clid=&quot;020&quot;&gt;
  &lt;track uuid=&quot;551&quot; category=&quot;s&quot; route=&quot;8&quot; vehicle_type=&quot;trolleybus&quot; &gt;
    &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;
  &lt;/track&gt;
  &lt;track uuid=&quot;552&quot; category=&quot;s&quot; route=&quot;6&quot; vehicle_type=&quot;trolleybus&quot;&gt;
    &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;
  &lt;/track&gt;
&lt;/tracks&gt;

I wrote the following code:

package main

import (
	&quot;encoding/json&quot;
	&quot;encoding/xml&quot;
	&quot;fmt&quot;
)

type Tracks struct {
	XMLName xml.Name `xml:&quot;tracks&quot; json:&quot;-&quot;`
	Clid    string   `xml:&quot;clid,attr&quot; json:&quot;clid&quot;`
	Tracks  []Track  `xml:&quot;track&quot; json:&quot;track_list&quot;`
}

type Track struct {
	XMLName     xml.Name `xml:&quot;tracks&quot;`
	Uuid        string   `xml:&quot;uuid,attr&quot; json:&quot;uuid&quot;`
	Category    string   `xml:&quot;category,attr&quot; json:&quot;category&quot;`
	Route       string   `xml:&quot;route,attr&quot; json:&quot;route&quot;`
	VehicleType string   `xml:&quot;vehicle_type,attr&quot; json:&quot;vehicle_type&quot;`
	Point       Point    `xml:&quot;point&quot; json:&quot;point&quot;`
}

type Point struct {
	Latitude  string `xml:&quot;latitude,attr&quot; json:&quot;latitude&quot;`
	Longitude string `xml:&quot;longitude,attr&quot; json:&quot;longitude&quot;`
	AvgSpeed  string `xml:&quot;avg_speed,attr&quot; json:&quot;avg_speed&quot;`
	Direction string `xml:&quot;direction,attr&quot; json:&quot;direction&quot;`
	Time      string `xml:&quot;time,attr&quot; json:&quot;time&quot;`
}

func main() {
	rawXmlData := `
		&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
		&lt;tracks clid=&quot;020&quot;&gt;
			&lt;track uuid=&quot;551&quot; category=&quot;s&quot; route=&quot;8&quot; vehicle_type=&quot;trolleybus&quot;&gt;
				&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;
			&lt;/track&gt;
			&lt;track uuid=&quot;552&quot; category=&quot;s&quot; route=&quot;6&quot; vehicle_type=&quot;trolleybus&quot;&gt;
				&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;
			&lt;/track&gt;
		&lt;/tracks&gt;
	`

	var tracks Tracks

	err := xml.Unmarshal([]byte(rawXmlData), &amp;tracks)
	if err != nil {
		log.Fatal(err)
	}

	jsonData, err := json.Marshal(tracks)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf(string(jsonData))
}

Go.dev

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

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返回的错误。代码可能如下所示:

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

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

panic: expected element type <tracks> but have <track>

goroutine 1 [running]:
main.main()
        /home/lars/tmp/go/main.go:48 +0x12f

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

type Track struct {
    XMLName     xml.Name `xml:"tracks"`
    Uuid        string   `xml:"uuid,attr" json:"uuid"`
    Category    string   `xml:"category,attr" json:"category"`
    Route       string   `xml:"route,attr" json:"route"`
    VehicleType string   `xml:"vehicle_type,attr" json:"vehicle_type"`
    Point       Point    `xml:"point" json:"point"`
}

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

type Track struct {
    XMLName     xml.Name `xml:"track"`
    Uuid        string   `xml:"uuid,attr" json:"uuid"`
    Category    string   `xml:"category,attr" json:"category"`
    Route       string   `xml:"route,attr" json:"route"`
    VehicleType string   `xml:"vehicle_type,attr" json:"vehicle_type"`
    Point       Point    `xml:"point" json:"point"`
}

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

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

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


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

{
  "clid": "020",
  "track_list": [
    {
      "XMLName": {
        "Space": "",
        "Local": "track"
      },
      "uuid": "551",
      "category": "s",
      "route": "8",
      "vehicle_type": "trolleybus",
      "point": {
        "latitude": "53.61491",
        "longitude": "55.90922",
        "avg_speed": "24",
        "direction": "270",
        "time": "13122022:072116"
      }
    },
    {
      "XMLName": {
        "Space": "",
        "Local": "track"
      },
      "uuid": "552",
      "category": "s",
      "route": "6",
      "vehicle_type": "trolleybus",
      "point": {
        "latitude": "53.68321",
        "longitude": "57.90922",
        "avg_speed": "42",
        "direction": "181",
        "time": "13122022:072216"
      }
    }
  ]
}

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

type Track struct {
    Uuid        string `xml:"uuid,attr" json:"uuid"`
    Category    string `xml:"category,attr" json:"category"`
    Route       string `xml:"route,attr" json:"route"`
    VehicleType string `xml:"vehicle_type,attr" json:"vehicle_type"`
    Point       Point  `xml:"point" json:"point"`
}

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

{
  "clid": "020",
  "track_list": [
    {
      "uuid": "551",
      "category": "s",
      "route": "8",
      "vehicle_type": "trolleybus",
      "point": {
        "latitude": "53.61491",
        "longitude": "55.90922",
        "avg_speed": "24",
        "direction": "270",
        "time": "13122022:072116"
      }
    },
    {
      "uuid": "552",
      "category": "s",
      "route": "6",
      "vehicle_type": "trolleybus",
      "point": {
        "latitude": "53.68321",
        "longitude": "57.90922",
        "avg_speed": "42",
        "direction": "181",
        "time": "13122022:072216"
      }
    }
  ]
}
英文:

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:

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

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:

panic: expected element type &lt;tracks&gt; but have &lt;track&gt;
goroutine 1 [running]:
main.main()
/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:

type Track struct {
XMLName     xml.Name `xml:&quot;tracks&quot;`
Uuid        string   `xml:&quot;uuid,attr&quot; json:&quot;uuid&quot;`
Category    string   `xml:&quot;category,attr&quot; json:&quot;category&quot;`
Route       string   `xml:&quot;route,attr&quot; json:&quot;route&quot;`
VehicleType string   `xml:&quot;vehicle_type,attr&quot; json:&quot;vehicle_type&quot;`
Point       Point    `xml:&quot;point&quot; json:&quot;point&quot;`
}

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

type Track struct {
XMLName     xml.Name `xml:&quot;track&quot;`
Uuid        string   `xml:&quot;uuid,attr&quot; json:&quot;uuid&quot;`
Category    string   `xml:&quot;category,attr&quot; json:&quot;category&quot;`
Route       string   `xml:&quot;route,attr&quot; json:&quot;route&quot;`
VehicleType string   `xml:&quot;vehicle_type,attr&quot; json:&quot;vehicle_type&quot;`
Point       Point    `xml:&quot;point&quot; json:&quot;point&quot;`
}

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:

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

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):

{
&quot;clid&quot;: &quot;020&quot;,
&quot;track_list&quot;: [
{
&quot;XMLName&quot;: {
&quot;Space&quot;: &quot;&quot;,
&quot;Local&quot;: &quot;track&quot;
},
&quot;uuid&quot;: &quot;551&quot;,
&quot;category&quot;: &quot;s&quot;,
&quot;route&quot;: &quot;8&quot;,
&quot;vehicle_type&quot;: &quot;trolleybus&quot;,
&quot;point&quot;: {
&quot;latitude&quot;: &quot;53.61491&quot;,
&quot;longitude&quot;: &quot;55.90922&quot;,
&quot;avg_speed&quot;: &quot;24&quot;,
&quot;direction&quot;: &quot;270&quot;,
&quot;time&quot;: &quot;13122022:072116&quot;
}
},
{
&quot;XMLName&quot;: {
&quot;Space&quot;: &quot;&quot;,
&quot;Local&quot;: &quot;track&quot;
},
&quot;uuid&quot;: &quot;552&quot;,
&quot;category&quot;: &quot;s&quot;,
&quot;route&quot;: &quot;6&quot;,
&quot;vehicle_type&quot;: &quot;trolleybus&quot;,
&quot;point&quot;: {
&quot;latitude&quot;: &quot;53.68321&quot;,
&quot;longitude&quot;: &quot;57.90922&quot;,
&quot;avg_speed&quot;: &quot;42&quot;,
&quot;direction&quot;: &quot;181&quot;,
&quot;time&quot;: &quot;13122022:072216&quot;
}
}
]
}

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

type Track struct {
Uuid        string `xml:&quot;uuid,attr&quot; json:&quot;uuid&quot;`
Category    string `xml:&quot;category,attr&quot; json:&quot;category&quot;`
Route       string `xml:&quot;route,attr&quot; json:&quot;route&quot;`
VehicleType string `xml:&quot;vehicle_type,attr&quot; json:&quot;vehicle_type&quot;`
Point       Point  `xml:&quot;point&quot; json:&quot;point&quot;`
}

Then we get as output (formatted with jq):

{
&quot;clid&quot;: &quot;020&quot;,
&quot;track_list&quot;: [
{
&quot;uuid&quot;: &quot;551&quot;,
&quot;category&quot;: &quot;s&quot;,
&quot;route&quot;: &quot;8&quot;,
&quot;vehicle_type&quot;: &quot;trolleybus&quot;,
&quot;point&quot;: {
&quot;latitude&quot;: &quot;53.61491&quot;,
&quot;longitude&quot;: &quot;55.90922&quot;,
&quot;avg_speed&quot;: &quot;24&quot;,
&quot;direction&quot;: &quot;270&quot;,
&quot;time&quot;: &quot;13122022:072116&quot;
}
},
{
&quot;uuid&quot;: &quot;552&quot;,
&quot;category&quot;: &quot;s&quot;,
&quot;route&quot;: &quot;6&quot;,
&quot;vehicle_type&quot;: &quot;trolleybus&quot;,
&quot;point&quot;: {
&quot;latitude&quot;: &quot;53.68321&quot;,
&quot;longitude&quot;: &quot;57.90922&quot;,
&quot;avg_speed&quot;: &quot;42&quot;,
&quot;direction&quot;: &quot;181&quot;,
&quot;time&quot;: &quot;13122022:072216&quot;
}
}
]
}

答案2

得分: 1

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

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

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

链接

英文:
type Track struct {
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:

确定