错误:使用golang encoding/xml解组GML时出错。

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

Error unmarshalling GML with golang encoding/xml

问题

我正在尝试解析一些XML,实际上是地理标记语言(GML)。

我在http://play.golang.org/p/qS6GjCOtHF 上有一个示例。

有两个问题,第一个问题是:

读取xml main.FeatureCollection字段"LowerCorner"时出错,标签为"boundedBy>Envelope>lowerCorner"与标签"boundedBy>Envelope"冲突。

我不知道如何修复这个问题。我将其注释掉后,成功解析了GML,但是在FeatureCollection中没有Features

有什么线索吗?

GML的一个示例是:

<?xml version="1.0" encoding="UTF-8"?>
<gml:FeatureCollection xmlns:gml="http://www.opengis.net/gml"
	xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:fme="http://www.safe.com/gml/fme" xsi:schemaLocation="http://www.safe.com/gml/fme tblMainGML.xsd">
	<gml:boundedBy>
		<gml:Envelope srsName="EPSG:3112" srsDimension="2">
			<gml:lowerCorner>45.2921142578125 -80.2166748046875</gml:lowerCorner>
			<gml:upperCorner>169.000122070313 -9.14251708984375</gml:upperCorner>
		</gml:Envelope>
	</gml:boundedBy>
	<gml:featureMember>
		<fme:GML gml:id="id5255fa48-42b3-43d1-9e0d-b2ba8b57a936">
			<fme:OBJECTID>1</fme:OBJECTID>
			<fme:RECORD_ID>QLD48234</fme:RECORD_ID>
			<fme:NAME>HATCHMAN POINT</fme:NAME>
			<fme:FEAT_CODE>PT</fme:FEAT_CODE>
			<fme:CGDN>N</fme:CGDN>
			<fme:AUTHORITY_ID>QLD</fme:AUTHORITY_ID>
			<fme:CONCISE_GAZ>N</fme:CONCISE_GAZ>
			<fme:LATITUDE>-12.58361</fme:LATITUDE>
			<fme:lat_degrees>-12</fme:lat_degrees>
			<fme:lat_minutes>35</fme:lat_minutes>
			<fme:lat_seconds>0</fme:lat_seconds>
			<fme:LONGITUDE>141.62583</fme:LONGITUDE>
			<fme:long_degrees>141</fme:long_degrees>
			<fme:long_minutes>37</fme:long_minutes>
			<fme:long_seconds>32</fme:long_seconds>
			<fme:STATE_ID>QLD</fme:STATE_ID>
			<fme:STATUS>U</fme:STATUS>
			<fme:VARIANT_NAME />
			<fme:MAP_100K>7272</fme:MAP_100K>
			<fme:Place_ID>45880</fme:Place_ID>
			<gml:pointProperty>
				<gml:Point srsName="EPSG:3112" srsDimension="2">
					<gml:pos>141.625915527344 -12.5836181640625</gml:pos>
				</gml:Point>
			</gml:pointProperty>
		</fme:GML>
	</gml:featureMember>
</gml:FeatureCollection>
</xml>

我的结构体如下:

type FeatureCollection struct {
	Xsi            string   `xml:"xsi,attr"`
	Fme            string   `xml:"fme,attr"`
	Gml            string   `xml:"gml,attr"`
	Xlink          string   `xml:"xlink,attr"`
	LowerCorner    string   `xml:"boundedBy>Envelope>lowerCorner"`
	UpperCorner    string   `xml:"boundedBy>Envelope>upperCorner"`
	Envelope       Envelope `xml:"boundedBy>Envelope"`
	SchemaLocation string   `xml:"schemaLocation,attr"`
	Features       []Feature
}

type Feature struct {
	PlaceID  string `xml:"featureMember>GML>Place_ID"`
	StateID  string `xml:"featureMember>GML>STATE_ID"`
	Postcode string `xml:"featureMember>GML>POSTCODE"`
	CGDN     string `xml:"featureMember>GML>CGDN"`
	Map100K  string `xml:"featureMember>GML>MAP_100K"`
	// 其他字段...
}
英文:

I am trying to unmarshal some XML, actually Geography Markup Language (GML).

I have an example at http://play.golang.org/p/qS6GjCOtHF

Two problems, the first:

> error reading xml main.FeatureCollection field "LowerCorner" with tag "boundedBy>Envelope>lowerCorner" conflicts with field "Envelope" with tag "boundedBy>Envelope"

I have no idea how to fix that. I commented those out and get the GML to unmarshal without errors but then there are no Features in the FeatureCollection.

Any clues?

An example of the GML is:

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;gml:FeatureCollection xmlns:gml=&quot;http://www.opengis.net/gml&quot;
	xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
	xmlns:fme=&quot;http://www.safe.com/gml/fme&quot; xsi:schemaLocation=&quot;http://www.safe.com/gml/fme tblMainGML.xsd&quot;&gt;
	&lt;gml:boundedBy&gt;
		&lt;gml:Envelope srsName=&quot;EPSG:3112&quot; srsDimension=&quot;2&quot;&gt;
			&lt;gml:lowerCorner&gt;45.2921142578125 -80.2166748046875&lt;/gml:lowerCorner&gt;
			&lt;gml:upperCorner&gt;169.000122070313 -9.14251708984375&lt;/gml:upperCorner&gt;
		&lt;/gml:Envelope&gt;
	&lt;/gml:boundedBy&gt;
	&lt;gml:featureMember&gt;
		&lt;fme:GML gml:id=&quot;id5255fa48-42b3-43d1-9e0d-b2ba8b57a936&quot;&gt;
			&lt;fme:OBJECTID&gt;1&lt;/fme:OBJECTID&gt;
			&lt;fme:RECORD_ID&gt;QLD48234&lt;/fme:RECORD_ID&gt;
			&lt;fme:NAME&gt;HATCHMAN POINT&lt;/fme:NAME&gt;
			&lt;fme:FEAT_CODE&gt;PT&lt;/fme:FEAT_CODE&gt;
			&lt;fme:CGDN&gt;N&lt;/fme:CGDN&gt;
			&lt;fme:AUTHORITY_ID&gt;QLD&lt;/fme:AUTHORITY_ID&gt;
			&lt;fme:CONCISE_GAZ&gt;N&lt;/fme:CONCISE_GAZ&gt;
			&lt;fme:LATITUDE&gt;-12.58361&lt;/fme:LATITUDE&gt;
			&lt;fme:lat_degrees&gt;-12&lt;/fme:lat_degrees&gt;
			&lt;fme:lat_minutes&gt;35&lt;/fme:lat_minutes&gt;
			&lt;fme:lat_seconds&gt;0&lt;/fme:lat_seconds&gt;
			&lt;fme:LONGITUDE&gt;141.62583&lt;/fme:LONGITUDE&gt;
			&lt;fme:long_degrees&gt;141&lt;/fme:long_degrees&gt;
			&lt;fme:long_minutes&gt;37&lt;/fme:long_minutes&gt;
			&lt;fme:long_seconds&gt;32&lt;/fme:long_seconds&gt;
			&lt;fme:STATE_ID&gt;QLD&lt;/fme:STATE_ID&gt;
			&lt;fme:STATUS&gt;U&lt;/fme:STATUS&gt;
			&lt;fme:VARIANT_NAME /&gt;
			&lt;fme:MAP_100K&gt;7272&lt;/fme:MAP_100K&gt;
			&lt;fme:Place_ID&gt;45880&lt;/fme:Place_ID&gt;
			&lt;gml:pointProperty&gt;
				&lt;gml:Point srsName=&quot;EPSG:3112&quot; srsDimension=&quot;2&quot;&gt;
					&lt;gml:pos&gt;141.625915527344 -12.5836181640625&lt;/gml:pos&gt;
				&lt;/gml:Point&gt;
			&lt;/gml:pointProperty&gt;
		&lt;/fme:GML&gt;
	&lt;/gml:featureMember&gt;
&lt;/gml:FeatureCollection&gt;
&lt;/xml&gt;

My structs

type FeatureCollection struct {
	Xsi            string   `xml:&quot;xsi,attr&quot;`
	Fme            string   `xml:&quot;fme,attr&quot;`
	Gml            string   `xml:&quot;gml,attr&quot;`
	Xlink          string   `xml:&quot;xlink,attr&quot;`
	LowerCorner    string   `xml:&quot;boundedBy&gt;Envelope&gt;lowerCorner&quot;`
	UpperCorner    string   `xml:&quot;boundedBy&gt;Envelope&gt;upperCorner&quot;`
	Envelope       Envelope `xml:&quot;boundedBy&gt;Envelope&quot;`
	SchemaLocation string   `xml:&quot;schemaLocation,attr&quot;`
	Features       []Feature
}

type Feature struct {
	PlaceID     string `xml:&quot;featureMember&gt;GML&gt;Place_ID&quot;`
	StateID     string `xml:&quot;featureMember&gt;GML&gt;STATE_ID&quot;`
	Postcode    string `xml:&quot;featureMember&gt;GML&gt;POSTCODE&quot;`
	CGDN        string `xml:&quot;featureMember&gt;GML&gt;CGDN&quot;`
	Map100K     string `xml:&quot;featureMember&gt;GML&gt;MAP_100K&quot;`
ETC...
}

答案1

得分: 1

XML标签只能映射到(最多)一个结构字段。encoding/xml包必须为每个XML标签决定将其解码到哪个结构字段中。你的用于建模XML的结构体很奇怪,这使得这个决定变得模棱两可。

例如,让我们看看这个例子:

type FeatureCollection struct {
    ...
    LowerCorner    string   `xml:"boundedBy>Envelope>lowerCorner"`
    UpperCorner    string   `xml:"boundedBy>Envelope>upperCorner"`
    Envelope       Envelope `xml:"boundedBy>Envelope"`
    ...
}

encoding/xml包无法确定XML标签<Envelope>应该解码到哪里,比如解码到LowerCorner?解码到UpperCorner?解码到Envelope?是的,我知道LowerCorner只是<Envelope>的子元素,但由于整个<Envelope>元素被映射到FeatureCollection.Envelope,这是不允许的。

你应该将LowerCornerUpperCorner字段移动到你的Envelope结构体类型中,因为它们属于那里,并且你想要解组整个Envelope XML标签(或者如果不需要,可以完全删除FeatureCollection.Envelope)。所以按照这个模式将字段放到它们应该属于的地方。

这是更新后的模型,提取了你想要的所有信息:

type FeatureCollection struct {
	Xsi            string   `xml:"xsi,attr"`
	Fme            string   `xml:"fme,attr"`
	Gml            string   `xml:"gml,attr"`
	Xlink          string   `xml:"xlink,attr"`
	Envelope       Envelope `xml:"boundedBy>Envelope"`
	SchemaLocation string   `xml:"schemaLocation,attr"`
	FeaturesGML    []GML    `xml:"featureMember>GML"`
}
type Envelope struct {
	SrsName      string `xml:"srsName,attr"`
	SrsDimension string `xml:"srsDimension,attr"`
	LowerCorner  string `xml:"lowerCorner"`
	UpperCorner  string `xml:"upperCorner"`
}
type GML struct {
	ID          string `xml:"id,attr"`
	PlaceID     string `xml:"Place_ID"`
	StateID     string `xml:"STATE_ID"`
	Postcode    string `xml:"POSTCODE"`
	CGDN        string `xml:"CGDN"`
	Map100K     string `xml:"MAP_100K"`
	Point       Point  `xml:"pointProperty>Point"`
	VariantName string `xml:"VARIANT_NAME"`
	RecordID    string `xml:"RECORD_ID"`
	LatSeconds  string `xml:"lat_seconds"`
	Status      string `xml:"STATUS"`
	LongSeconds string `xml:"long_seconds"`
	ConciseGAZ  string `xml:"CONCISE_GAZ"`
	Lattitude   string `xml:"LATITUDE"`
	AuthorityID string `xml:"AUTHORITY_ID"`
	Longitude   string `xml:"LONGITUDE"`
	LongMinutes string `xml:"long_minutes"`
	LatDegrees  string `xml:"lat_degrees"`
	NAME        string `xml:"NAME"`
	LatMinutes  string `xml:"lat_minutes"`
	ObjectID    string `xml:"OBJECTID"`
	FeatCode    string `xml:"FEAT_CODE"`
	LongDegrees string `xml:"long_degrees"`
}
type Point struct {
	SrsName      string `xml:"srsName,attr"`
	SrsDimension string `xml:"srsDimension,attr"`
	Pos          string `xml:"pos"`
}

这是你的代码在Go Playground上修改后的版本,可以正常运行。

为了验证你的结构体是否包含了从XML解组的所有信息:

fmt.Printf("%+v", v)

输出:

&{Xsi:http://www.w3.org/2001/XMLSchema-instance Fme:http://www.safe.com/gml/fme Gml:http://www.opengis.net/gml Xlink:http://www.w3.org/1999/xlink Envelope:{SrsName:EPSG:3112 SrsDimension:2 LowerCorner:45.2921142578125 -80.2166748046875 UpperCorner:169.000122070313 -9.14251708984375} SchemaLocation:http://www.safe.com/gml/fme tblMainGML.xsd FeaturesGML:[{ID:id5255fa48-42b3-43d1-9e0d-b2ba8b57a936 PlaceID:45880 StateID:QLD Postcode: CGDN:N Map100K:7272 Point:{SrsName:EPSG:3112 SrsDimension:2 Pos:141.625915527344 -12.5836181640625} VariantName: RecordID:QLD48234 LatSeconds:0 Status:U LongSeconds:32 ConciseGAZ:N Lattitude:-12.58361 AuthorityID:QLD Longitude:141.62583 LongMinutes:37 LatDegrees:-12 NAME:HATCHMAN POINT LatMinutes:35 ObjectID:1 FeatCode:PT LongDegrees:141}]}

英文:

An XML tag can only be mapped to (at most) one struct field. The encoding/xml package has to decide for each XML tag into which struct field it will be decoded. Your structs that model the XML are weird, and make this decision ambiguous.

For example let's take this example:

type FeatureCollection struct {
    ...
    LowerCorner    string   `xml:&quot;boundedBy&gt;Envelope&gt;lowerCorner&quot;`
    UpperCorner    string   `xml:&quot;boundedBy&gt;Envelope&gt;upperCorner&quot;`
    Envelope       Envelope `xml:&quot;boundedBy&gt;Envelope&quot;`
    ...
}

The encoding/xml package can't decide where the XML tag &lt;Envelope&gt; should be decoded into, e.g. into LowerCorner? into UpperCorner? into Envelope? Yes, I know LowerCorner is only a sub-element of &lt;Envelope&gt; but since the whole &lt;Envelope&gt; element is mapped to FeatureCollection.Envelope, this is not allowed.

You should move LowerCorner and UpperCorner fields into your Envelope struct type because that's where they belong to and you want to unmarshal the whole Envelope xml tag (or if not, FeatureCollection.Envelope could be removed entirely). So follow this pattern to put fields to where they belong.

Here is your updated model which extracts all the info you wanted:

type FeatureCollection struct {
	Xsi            string   `xml:&quot;xsi,attr&quot;`
	Fme            string   `xml:&quot;fme,attr&quot;`
	Gml            string   `xml:&quot;gml,attr&quot;`
	Xlink          string   `xml:&quot;xlink,attr&quot;`
	Envelope       Envelope `xml:&quot;boundedBy&gt;Envelope&quot;`
	SchemaLocation string   `xml:&quot;schemaLocation,attr&quot;`
	FeaturesGML    []GML    `xml:&quot;featureMember&gt;GML&quot;`
}
type Envelope struct {
	SrsName      string `xml:&quot;srsName,attr&quot;`
	SrsDimension string `xml:&quot;srsDimension,attr&quot;`
	LowerCorner  string `xml:&quot;lowerCorner&quot;`
	UpperCorner  string `xml:&quot;upperCorner&quot;`
}
type GML struct {
	ID          string `xml:&quot;id,attr&quot;`
	PlaceID     string `xml:&quot;Place_ID&quot;`
	StateID     string `xml:&quot;STATE_ID&quot;`
	Postcode    string `xml:&quot;POSTCODE&quot;`
	CGDN        string `xml:&quot;CGDN&quot;`
	Map100K     string `xml:&quot;MAP_100K&quot;`
	Point       Point  `xml:&quot;pointProperty&gt;Point&quot;`
	VariantName string `xml:&quot;VARIANT_NAME&quot;`
	RecordID    string `xml:&quot;RECORD_ID&quot;`
	LatSeconds  string `xml:&quot;lat_seconds&quot;`
	Status      string `xml:&quot;STATUS&quot;`
	LongSeconds string `xml:&quot;long_seconds&quot;`
	ConciseGAZ  string `xml:&quot;CONCISE_GAZ&quot;`
	Lattitude   string `xml:&quot;LATITUDE&quot;`
	AuthorityID string `xml:&quot;AUTHORITY_ID&quot;`
	Longitude   string `xml:&quot;LONGITUDE&quot;`
	LongMinutes string `xml:&quot;long_minutes&quot;`
	LatDegrees  string `xml:&quot;lat_degrees&quot;`
	NAME        string `xml:&quot;NAME&quot;`
	LatMinutes  string `xml:&quot;lat_minutes&quot;`
	ObjectID    string `xml:&quot;OBJECTID&quot;`
	FeatCode    string `xml:&quot;FEAT_CODE&quot;`
	LongDegrees string `xml:&quot;long_degrees&quot;`
}
type Point struct {
	SrsName      string `xml:&quot;srsName,attr&quot;`
	SrsDimension string `xml:&quot;srsDimension,attr&quot;`
	Pos          string `xml:&quot;pos&quot;`
}

Here is the modified version of your code on the Go Playground which runs without errors.

To verify that your struct holds all the unmarshalled info from the XML:

fmt.Printf(&quot;%+v&quot;, v)

Output:

> &{Xsi:http://www.w3.org/2001/XMLSchema-instance Fme:http://www.safe.com/gml/fme Gml:http://www.opengis.net/gml Xlink:http://www.w3.org/1999/xlink Envelope:{SrsName:EPSG:3112 SrsDimension:2 LowerCorner:45.2921142578125 -80.2166748046875 UpperCorner:169.000122070313 -9.14251708984375} SchemaLocation:http://www.safe.com/gml/fme tblMainGML.xsd FeaturesGML:[{ID:id5255fa48-42b3-43d1-9e0d-b2ba8b57a936 PlaceID:45880 StateID:QLD Postcode: CGDN:N Map100K:7272 Point:{SrsName:EPSG:3112 SrsDimension:2 Pos:141.625915527344 -12.5836181640625} VariantName: RecordID:QLD48234 LatSeconds:0 Status:U LongSeconds:32 ConciseGAZ:N Lattitude:-12.58361 AuthorityID:QLD Longitude:141.62583 LongMinutes:37 LatDegrees:-12 NAME:HATCHMAN POINT LatMinutes:35 ObjectID:1 FeatCode:PT LongDegrees:141}]}

huangapple
  • 本文由 发表于 2016年4月11日 14:50:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/36541694.html
匿名

发表评论

匿名网友

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

确定