将 XML 元素名称解组为不同的 属性
Unmarshal XML element name to different property
我目前正在为 NameSilo API 编写一个库。我卡在 getPriceList api 上,returns XML 是这样的:
<namesilo>
<request>
<operation>getPrices</operation>
<ip>55.555.55.55</ip>
</request>
<reply>
<code>300</code>
<detail>success</detail>
<com>
<registration>8.99</registration>
<transfer>8.39</transfer>
<renew>8.99</renew>
</com>
<net>
<registration>9.29</registration>
<transfer>8.99</transfer>
<renew>9.29</renew>
</net>
</reply>
</namesilo>
如您所见,每个 TLD 都有一个元素。我想将元素名称(例如:com、net)解组为 属性,它不被称为 XMLName
(我希望它被称为 TLD)。
看完https://golang.org/src/encoding/xml/marshal.go的第34-39行后,看来这是不可能的。
我已经尝试了下面的代码,但是它不起作用。
type APIResponse struct {
Request struct {
Operation string `xml:"operation"`
IP string `xml:"ip"`
} `xml:"request"`
}
type GetPricesResponse struct {
APIResponse
Reply []struct {
Domains []struct {
TLD xml.name
Registration string `xml:"registration"`
Transfer string `xml:"transfer"`
Renew string `xml:"renew"`
} `xml:",any"`
} `xml:"reply"`
}
我有什么办法可以做到这一点,或者 xml 元素名称不能使用 XMLName
以外的 属性 名称。
更新:我仔细查看了代码,发现 this,这让我觉得我不能轻易做到这一点。
您不需要解组为您的最终类型。您可以解组为一组单独的类型来反映此数据结构,然后将其转换为您喜欢的表示形式以在其他地方使用(例如,为了快速查找,您可能希望有一个 map[string]PriceRecord 将域名映射到价格记录).我会这样想,而不是一定要尝试在一个步骤中进行翻译,这将你完全与他们选择生产的任何 xml 联系在一起——如果它发生变化,你的数据结构也必须改变。
没有比 XMLName xml.Name
更简单的选择了。
可以用满足 unmarshaller interface. The added complexity is probably not worthwhile. Playground example:
的类型做你想做的事
package main
import (
"encoding/xml"
"fmt"
"log"
)
func main() {
var data Data
if err := xml.Unmarshal(payload, &data); err != nil {
log.Fatal(err)
}
for k, v := range data.Reply.Domains {
fmt.Printf("%d: %#v\n", k, v)
}
}
type Domain struct {
TLD string
Registration string `xml:"registration"`
Transfer string `xml:"transfer"`
Renew string `xml:"renew"`
}
func (domain *Domain) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
v := struct {
XMLName xml.Name
Registration string `xml:"registration"`
Transfer string `xml:"transfer"`
Renew string `xml:"renew"`
}{}
d.DecodeElement(&v, &start)
domain.TLD = v.XMLName.Local
domain.Registration = v.Registration
domain.Transfer = v.Transfer
domain.Renew = v.Renew
return nil
}
type Data struct {
Request struct {
Operation string `xml:"operation"`
Ip string `xml:"ip"`
} `xml:"request"`
Reply struct {
Code string `xml:"code"`
Detail string `xml:"detail"`
Domains []Domain `xml:",any"`
} `xml:"reply"`
}
var payload = []byte(`<namesilo>
<request>
<operation>getPrices</operation>
<ip>55.555.55.55</ip>
</request>
<reply>
<code>300</code>
<detail>success</detail>
<com>
<registration>8.99</registration>
<transfer>8.39</transfer>
<renew>8.99</renew>
</com>
<net>
<registration>9.29</registration>
<transfer>8.99</transfer>
<renew>9.29</renew>
</net>
</reply>
</namesilo>`)
我目前正在为 NameSilo API 编写一个库。我卡在 getPriceList api 上,returns XML 是这样的:
<namesilo>
<request>
<operation>getPrices</operation>
<ip>55.555.55.55</ip>
</request>
<reply>
<code>300</code>
<detail>success</detail>
<com>
<registration>8.99</registration>
<transfer>8.39</transfer>
<renew>8.99</renew>
</com>
<net>
<registration>9.29</registration>
<transfer>8.99</transfer>
<renew>9.29</renew>
</net>
</reply>
</namesilo>
如您所见,每个 TLD 都有一个元素。我想将元素名称(例如:com、net)解组为 属性,它不被称为 XMLName
(我希望它被称为 TLD)。
看完https://golang.org/src/encoding/xml/marshal.go的第34-39行后,看来这是不可能的。
我已经尝试了下面的代码,但是它不起作用。
type APIResponse struct {
Request struct {
Operation string `xml:"operation"`
IP string `xml:"ip"`
} `xml:"request"`
}
type GetPricesResponse struct {
APIResponse
Reply []struct {
Domains []struct {
TLD xml.name
Registration string `xml:"registration"`
Transfer string `xml:"transfer"`
Renew string `xml:"renew"`
} `xml:",any"`
} `xml:"reply"`
}
我有什么办法可以做到这一点,或者 xml 元素名称不能使用 XMLName
以外的 属性 名称。
更新:我仔细查看了代码,发现 this,这让我觉得我不能轻易做到这一点。
您不需要解组为您的最终类型。您可以解组为一组单独的类型来反映此数据结构,然后将其转换为您喜欢的表示形式以在其他地方使用(例如,为了快速查找,您可能希望有一个 map[string]PriceRecord 将域名映射到价格记录).我会这样想,而不是一定要尝试在一个步骤中进行翻译,这将你完全与他们选择生产的任何 xml 联系在一起——如果它发生变化,你的数据结构也必须改变。
没有比 XMLName xml.Name
更简单的选择了。
可以用满足 unmarshaller interface. The added complexity is probably not worthwhile. Playground example:
的类型做你想做的事package main
import (
"encoding/xml"
"fmt"
"log"
)
func main() {
var data Data
if err := xml.Unmarshal(payload, &data); err != nil {
log.Fatal(err)
}
for k, v := range data.Reply.Domains {
fmt.Printf("%d: %#v\n", k, v)
}
}
type Domain struct {
TLD string
Registration string `xml:"registration"`
Transfer string `xml:"transfer"`
Renew string `xml:"renew"`
}
func (domain *Domain) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
v := struct {
XMLName xml.Name
Registration string `xml:"registration"`
Transfer string `xml:"transfer"`
Renew string `xml:"renew"`
}{}
d.DecodeElement(&v, &start)
domain.TLD = v.XMLName.Local
domain.Registration = v.Registration
domain.Transfer = v.Transfer
domain.Renew = v.Renew
return nil
}
type Data struct {
Request struct {
Operation string `xml:"operation"`
Ip string `xml:"ip"`
} `xml:"request"`
Reply struct {
Code string `xml:"code"`
Detail string `xml:"detail"`
Domains []Domain `xml:",any"`
} `xml:"reply"`
}
var payload = []byte(`<namesilo>
<request>
<operation>getPrices</operation>
<ip>55.555.55.55</ip>
</request>
<reply>
<code>300</code>
<detail>success</detail>
<com>
<registration>8.99</registration>
<transfer>8.39</transfer>
<renew>8.99</renew>
</com>
<net>
<registration>9.29</registration>
<transfer>8.99</transfer>
<renew>9.29</renew>
</net>
</reply>
</namesilo>`)