我一直在尝试编写一个自定义的Unmarshal来处理一些XML代码。
我知道您可以编写一个自定义解组方法来处理结构中的单个字段,但是我试图在整个结构上编写一个方法:
type LowestPricedPricedOffers struct {
ASIN string `xml:"GetLowestPricedOffersForASINResult>Identifier>ASIN"`
TimeOfOfferChange string `xml:"GetLowestPricedOffersForASINResult>Identifier>TimeOfOfferChange"`
TotalOfferCount int `xml:"GetLowestPricedOffersForASINResult>Summary>TotalOfferCount"`
ListPrice float32 `xml:"GetLowestPricedOffersForASINResult>Summary>ListPrice>Amount"`
LowestNew float32 //lowest new landed price
LowestUsed float32 //lowest used landed price
OfferCount map[string]map[string]int
CurrencyCode string //currency code taken from LowestPrices
NumberOfOffers []struct {
OfferCount string `xml:",innerxml"` //Will not work with int
Condition string `xml:"condition,attr"`
FulfillmentChannel string `xml:"fulfillmentChannel,attr"`
} `xml:"GetLowestPricedOffersForASINResult>Summary>NumberOfOffers>OfferCount"`
LowestPrices []struct {
Condition string `xml:"condition,attr"`
FulfillmentChannel string `xml:"fulfillmentChannel,attr"`
LandedPrice float32Unmarsh `xml:"LandedPrice>Amount"`
ListingPrice float32 `xml:"ListingPrice>Amount"`
Shipping float32 `xml:"Shipping>Amount"`
CurrencyCode string `xml:"LandedPrice>CurrencyCode"`
} `xml:"GetLowestPricedOffersForASINResult>Summary>LowestPrices>LowestPrice"`
}
func (n *LowestPricedPricedOffers) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
for {
t, err := d.Token()
if err == io.EOF {
break
}
switch tt := t.(type) {
case xml.StartElement:
var value int
if tt.Name.Local == "OfferCount" {
d.DecodeElement(&value, &start)
var condition string
var fullfillmentChannel string
for _, x := range tt.Attr {
//fmt.Println(x.Name.Local, x.Value)
if x.Name.Local == "condition" {
condition = x.Value
fmt.Println(condition)
} else {
fullfillmentChannel = x.Value
}
}
if n.OfferCount == nil {
n.OfferCount = make(map[string]map[string]int)
n.OfferCount[condition] = make(map[string]int)
n.OfferCount[condition][fullfillmentChannel] = value
} else {
if n.OfferCount[condition] == nil {
n.OfferCount[condition] = make(map[string]int)
}
n.OfferCount[condition][fullfillmentChannel] = value
}
} else if tt.Name.Local == "ASIN" {
d.DecodeElement(&n.ASIN, &start)
}
// More else if's to deal with rest of XML
}
}
return nil
}
这似乎起作用,因为我可以控制如何填充结构,例如,生成“ OfferCount”的映射。使用我的通用方法,然后我需要使用例如
来手动填充其余结构} else if tt.Name.Local == "ASIN" {
d.DecodeElement(&n.ASIN, &start)
}
我将不得不处理XML中的所有元素,必须为每个元素指定struct字段。有没有一种方法可以覆盖某些元素,但仅按照标准解组利用结构中的标记自动填充其余元素,而无需为结构字段生成单独的类型?
我已将完整代码张贴在go playground上:
我希望这有道理。
我已经更新了方法和问题,以在其上使用自定义类型和自定义解组。
主要结构已更新如下:
type LowestPricedPricedOffers struct {
Error AmazonError `xml:"Error"`
All struct {
/*The only way I found to retrieve 'status' from the GetLowestPricedOffersForASINResult element was to wrap in the struct 'All'.
This is the only reason the All struct exists. Ideally would like to remove*/
Status string `xml:"status,attr"`
ASIN string `xml:"Identifier>ASIN"`
ItemCondition string `xml:"Identifier>ItemCondition"`
TimeOfOfferChange string `xml:"Identifier>TimeOfOfferChange"`
TotalOfferCount int `xml:"Summary>TotalOfferCount"`
ListPrice float32 `xml:"Summary>ListPrice>Amount"`
OfferCount offerCount `xml:"Summary>NumberOfOffers"`
//Want to take Currency code from LowestPrices below but cannot think of a way to achieve this against the lowestPrices type
//CurrencyCode string `xml:"CurrencyCode"`
BuyBoxPrices buyBoxPrices `xml:"Summary>BuyBoxPrices"`
LowestPrices lowestPrices `xml:"Summary>LowestPrices"`
BuyBoxEligibleOffers buyBoxEligibleOffers `xml:"Summary>BuyBoxEligibleOffers"`
Offers []struct {
SubCondition string `xml:"SubCondition"`
SellerPositiveFeedbackRating float32 `xml:"SellerFeedbackRating>SellerPositiveFeedbackRating"`
FeedbackCount int `xml:"SellerFeedbackRating>FeedbackCount"`
ShippingTime struct {
MinimumHours int `xml:"minimumHours,attr"`
MaximumHours int `xml:"maximumHours,attr"`
AvailabilityType string `xml:"availabilityType,attr"`
}
ListingPrice float32 `xml:"ListingPrice>Amount"`
Shipping float32 `xml:"Shipping>Amount"`
ShipsFrom string `xml:"ShipsFrom>Country"`
IsFulfilledByAmazon bool `xml:"IsFulfilledByAmazon"`
IsBuyBoxWinner bool `xml:"IsBuyBoxWinner"`
IsFeaturedMerchant bool `xml:"IsFeaturedMerchant"` //true if the seller of the item is eligible to win the Buy Box.
} `xml:"Offers>Offer"`
} `xml:"GetLowestPricedOffersForASINResult"`
}
它包括“全部”结构,这似乎是从GetLowestPricedOffersForASINResult元素中解组“状态”的唯一方法。理想情况下,我想摆脱这种包装器结构,但是我不确定这是可能的。
一些自定义类型是地图,以便于轻松检索数据:
type offerCount map[string]map[string]int
func (m *offerCount) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
var content map[string]map[string]int
for {
t, err := d.Token()
if err == io.EOF {
break
}
switch tt := t.(type) {
case xml.StartElement:
var value int
if tt.Name.Local == "OfferCount" {
d.DecodeElement(&value, &start)
var condition string
var fullfillmentChannel string
for _, x := range tt.Attr {
if x.Name.Local == "condition" {
condition = x.Value
} else {
fullfillmentChannel = x.Value
}
}
if content == nil {
content = make(map[string]map[string]int)
content[condition] = make(map[string]int)
content[condition][fullfillmentChannel] = value
} else {
if content[condition] == nil {
content[condition] = make(map[string]int)
}
content[condition][fullfillmentChannel] = value
}
}
}
*m = offerCount(content)
}
return nil
}
我还在尝试找出如何通过lowestPrices类型设置CurrencyCode,不确定是否可行?
完整的更新代码位于go playground上,以征询一般性意见或建议。