title: Golang Custom Unmarshal XML
body: <p>I have been trying to write a custom Unmarshal to deal with some XML code.</p>
  
  <p>I know that you can write a custom unmarshal method to deal with an individual field within a struct, however I was trying to write one on the whole struct:</p>
  
  <pre><code>type LowestPricedPricedOffers struct {
  ASIN   string `xml:"GetLowestPricedOffersForASINResult&gt;Identifier&gt;ASIN"`
  TimeOfOfferChange string  `xml:"GetLowestPricedOffersForASINResult&gt;Identifier&gt;TimeOfOfferChange"`
  TotalOfferCount int   `xml:"GetLowestPricedOffersForASINResult&gt;Summary&gt;TotalOfferCount"`
  ListPrice         float32 `xml:"GetLowestPricedOffersForASINResult&gt;Summary&gt;ListPrice&gt;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&gt;Summary&gt;NumberOfOffers&gt;OfferCount"`
  LowestPrices []struct {
      Condition          string         `xml:"condition,attr"`
      FulfillmentChannel string         `xml:"fulfillmentChannel,attr"`
      LandedPrice        float32Unmarsh `xml:"LandedPrice&gt;Amount"`
      ListingPrice       float32        `xml:"ListingPrice&gt;Amount"`
      Shipping           float32        `xml:"Shipping&gt;Amount"`
      CurrencyCode       string         `xml:"LandedPrice&gt;CurrencyCode"`
  } `xml:"GetLowestPricedOffersForASINResult&gt;Summary&gt;LowestPrices&gt;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(&amp;value, &amp;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(&amp;n.ASIN, &amp;start)
          }
  
          // More else if's to deal with rest of XML
  
      }
  }
  return nil
  }
  </code></pre>
  
  <p>This seems to work in that I can control how my struct is populated, e.g in generating the map for 'OfferCount'.  With my generalized approach, I then need to manually populate the rest of the struct using e.g</p>
  
  <pre><code>} else if tt.Name.Local == "ASIN" {
          d.DecodeElement(&amp;n.ASIN, &amp;start)
      }
  </code></pre>
  
  <p>Which I would have to do for all the elements in the XML, having to specify the struct field for each element.  Is there a way using my approach that I can override for certain elements but just auto-populate the rest utilizing the tags in the struct as per a standard unmarshal without generating individual types for struct fields?</p>
  
  <p>I have posted the full code  on the <a href="https://play.golang.org/p/ewHfN6LDIOI" rel="nofollow noreferrer">go playground</a> : </p>
  
  <p>I hope this makes some sense.</p>
  
  <p>I have updated my approach and question, to use custom types and custom unmarshalling on them.</p>
  
  <p>The main struct has been updated as follows:</p>
  
  <pre><code>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&gt;ASIN"`
      ItemCondition     string     `xml:"Identifier&gt;ItemCondition"`
      TimeOfOfferChange string     `xml:"Identifier&gt;TimeOfOfferChange"`
      TotalOfferCount   int        `xml:"Summary&gt;TotalOfferCount"`
      ListPrice         float32    `xml:"Summary&gt;ListPrice&gt;Amount"`
      OfferCount        offerCount `xml:"Summary&gt;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&gt;BuyBoxPrices"`
      LowestPrices         lowestPrices         `xml:"Summary&gt;LowestPrices"`
      BuyBoxEligibleOffers buyBoxEligibleOffers `xml:"Summary&gt;BuyBoxEligibleOffers"`
  
      Offers []struct {
          SubCondition                 string  `xml:"SubCondition"`
          SellerPositiveFeedbackRating float32 `xml:"SellerFeedbackRating&gt;SellerPositiveFeedbackRating"`
          FeedbackCount                int     `xml:"SellerFeedbackRating&gt;FeedbackCount"`
          ShippingTime                 struct {
              MinimumHours     int    `xml:"minimumHours,attr"`
              MaximumHours     int    `xml:"maximumHours,attr"`
              AvailabilityType string `xml:"availabilityType,attr"`
          }
          ListingPrice        float32 `xml:"ListingPrice&gt;Amount"`
          Shipping            float32 `xml:"Shipping&gt;Amount"`
          ShipsFrom           string  `xml:"ShipsFrom&gt;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&gt;Offer"`
  } `xml:"GetLowestPricedOffersForASINResult"`
  </code></pre>
  
  <p>}</p>
  
  <p>It includes the 'All' struct which seemed to be the only way to get the unmarshalling of 'status' from the GetLowestPricedOffersForASINResult element.  Ideally I would like to get rid of this wrapper struct, but I am not sure that this is possible.</p>
  
  <p>Some of the custom types are maps, to allow for easy retrieval of data:</p>
  
  <pre><code>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(&amp;value, &amp;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
  
  }
  </code></pre>
  
  <p>I am also trying to work out how to set  CurrencyCode via the lowestPrices  type, not sure if that is possible?</p>
  
  <p>The full updated code is on the <a href="https://play.golang.org/p/MPqO1Z2JGHH" rel="nofollow noreferrer">go playground</a> for general comment or advice.</p>