Я пытался написать собственный Unmarshal для работы с некоторым XML-кодом.
Я знаю, что вы можете написать собственный Unmarshal метод для работы с отдельным полем в структуре, однако я пыталсянапишите один на всю структуру:
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, указав поле структуры для каждого элемента.,Есть ли способ, использующий мой подход, который я могу переопределить для определенных элементов, но просто автоматически заполнить остальные, используя теги в структуре в соответствии со стандартным демаршалом, не генерируя отдельные типы для полей структуры?
Я опубликовалполный код на go игровой площадке :
Надеюсь, в этом есть какой-то смысл.
Я обновил свой подход и вопрос, чтобы использовать собственные типы и пользовательские демаршаллинг для них.
Основная структура была обновлена следующим образом:
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"`
}
Она включает в себя структуру «Все», которая, по-видимому, была единственным способом получить демаршаллинг'status' из элемента 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
}
Я также пытаюсь выяснить, как установить CurrencyCode с помощью типа наименьших цен, не уверен, возможно ли это?
Полный обновленный код находится на go игровой площадке для общего комментария.или совет.