英文:
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:
<?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>
My structs
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"`
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
,这是不允许的。
你应该将LowerCorner
和UpperCorner
字段移动到你的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:"boundedBy>Envelope>lowerCorner"`
UpperCorner string `xml:"boundedBy>Envelope>upperCorner"`
Envelope Envelope `xml:"boundedBy>Envelope"`
...
}
The encoding/xml
package can't decide where the XML tag <Envelope>
should be decoded into, e.g. into LowerCorner
? into UpperCorner
? into Envelope
? Yes, I know LowerCorner
is only a sub-element of <Envelope>
but since the whole <Envelope>
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:"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"`
}
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("%+v", 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}]}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论