Golang Custom Unmarshal XML - PullRequest
       1

Golang Custom Unmarshal XML

0 голосов
/ 26 октября 2018

Я пытался написать собственный 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 игровой площадке для общего комментария.или совет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...