Golang XML解析(Unmarshal)值覆盖问题

huangapple go评论77阅读模式
英文:

Golang XML Unmarshal value overwriting issue

问题

<GetCompetitivePricingForASINResult ASIN="0547569653" status="Success">
<Product xmlns:ns2="http://mws.amazonservices.com/schema/Products/2011-10-01/default.xsd"
xmlns="http://mws.amazonservices.com/schema/Products/2011-10-01">
<Identifiers>
<MarketplaceASIN>
<MarketplaceId>ATVPDKIKX0DER</MarketplaceId>
<ASIN>0547569653</ASIN>
</MarketplaceASIN>
</Identifiers>
<CompetitivePricing>
<CompetitivePrices>
<CompetitivePrice belongsToRequester="false" condition="Used" subcondition="Good">
<CompetitivePriceId>2</CompetitivePriceId>
<Price>
<LandedPrice>
<CurrencyCode>USD</CurrencyCode>
<Amount>9.95</Amount>
</LandedPrice>
<ListingPrice>
<CurrencyCode>USD</CurrencyCode>
<Amount>9.95</Amount>
</ListingPrice>
<Shipping>
<CurrencyCode>USD</CurrencyCode>
<Amount>0.00</Amount>
</Shipping>
</Price>
</CompetitivePrice>
</CompetitivePrices>
<NumberOfOfferListings>
<OfferListingCount condition="Any">113</OfferListingCount>
<OfferListingCount condition="Used">72</OfferListingCount>
<OfferListingCount condition="New">41</OfferListingCount>
</NumberOfOfferListings>
</CompetitivePricing>
<SalesRankings>
<SalesRank>
<ProductCategoryId>book_display_on_website</ProductCategoryId>
<Rank>48661</Rank>
</SalesRank>
<SalesRank>
<ProductCategoryId>4209</ProductCategoryId>
<Rank>31</Rank>
</SalesRank>
<SalesRank>
<ProductCategoryId>6511974011</ProductCategoryId>
<Rank>65</Rank>
</SalesRank>
<SalesRank>
<ProductCategoryId>16587</ProductCategoryId>
<Rank>93</Rank>
</SalesRank>
</SalesRankings>
</Product>
</GetCompetitivePricingForASINResult>

我正在尝试仅在ProductCategoryId等于"book_display_on_website"时检索"Rank"字段,但在我当前的尝试中,它似乎将Rank设置为最后一个SalesRank条目(93)(应该是48661)。有人可以指点我正确的方向吗?

使用这种Unmarshal方法是否可能?还是需要类似go-pkg-xmlx或gokogiri这样的工具?(我来自php,通常在php中使用simple_xml_parser处理这种类型的内容。)

type Data struct {
XMLName xml.Name xml:"GetCompetitivePricingForASINResponse"
Item []Item xml:"GetCompetitivePricingForASINResult"
}

type Item struct {
Pcat string xml:"Product>SalesRankings>SalesRank>ProductCategoryId"
ASIN string xml:"ASIN,attr"
Rank string xml:"Product>SalesRankings>SalesRank>Rank"
}

result, err := api.GetCompetitivePricingForASIN(asins)

if err != nil {
fmt.Println(err)
}

data := &Data{}

xml.Unmarshal([]byte(result), data)
if err != nil {
log.Fatal(err)
}

for i := 0; i < len(data.Item); i++ {
fmt.Printf("%s\n", data.Item[i])
}

英文:
&lt;GetCompetitivePricingForASINResult ASIN=&quot;0547569653&quot; status=&quot;Success&quot;&gt;
    &lt;Product xmlns:ns2=&quot;http://mws.amazonservices.com/schema/Products/2011-10-01/default.xsd&quot;
             xmlns=&quot;http://mws.amazonservices.com/schema/Products/2011-10-01&quot;&gt;
        &lt;Identifiers&gt;
            &lt;MarketplaceASIN&gt;
                &lt;MarketplaceId&gt;ATVPDKIKX0DER&lt;/MarketplaceId&gt;
                &lt;ASIN&gt;0547569653&lt;/ASIN&gt;
            &lt;/MarketplaceASIN&gt;
        &lt;/Identifiers&gt;
        &lt;CompetitivePricing&gt;
            &lt;CompetitivePrices&gt;
                &lt;CompetitivePrice belongsToRequester=&quot;false&quot; condition=&quot;Used&quot; subcondition=&quot;Good&quot;&gt;
                    &lt;CompetitivePriceId&gt;2&lt;/CompetitivePriceId&gt;
                    &lt;Price&gt;
                        &lt;LandedPrice&gt;
                            &lt;CurrencyCode&gt;USD&lt;/CurrencyCode&gt;
                            &lt;Amount&gt;9.95&lt;/Amount&gt;
                        &lt;/LandedPrice&gt;
                        &lt;ListingPrice&gt;
                            &lt;CurrencyCode&gt;USD&lt;/CurrencyCode&gt;
                            &lt;Amount&gt;9.95&lt;/Amount&gt;
                        &lt;/ListingPrice&gt;
                        &lt;Shipping&gt;
                            &lt;CurrencyCode&gt;USD&lt;/CurrencyCode&gt;
                            &lt;Amount&gt;0.00&lt;/Amount&gt;
                        &lt;/Shipping&gt;
                    &lt;/Price&gt;
                &lt;/CompetitivePrice&gt;
            &lt;/CompetitivePrices&gt;
            &lt;NumberOfOfferListings&gt;
                &lt;OfferListingCount condition=&quot;Any&quot;&gt;113&lt;/OfferListingCount&gt;
                &lt;OfferListingCount condition=&quot;Used&quot;&gt;72&lt;/OfferListingCount&gt;
                &lt;OfferListingCount condition=&quot;New&quot;&gt;41&lt;/OfferListingCount&gt;
            &lt;/NumberOfOfferListings&gt;
        &lt;/CompetitivePricing&gt;
        &lt;SalesRankings&gt;
            &lt;SalesRank&gt;
                &lt;ProductCategoryId&gt;book_display_on_website&lt;/ProductCategoryId&gt;
                &lt;Rank&gt;48661&lt;/Rank&gt;
            &lt;/SalesRank&gt;
            &lt;SalesRank&gt;
                &lt;ProductCategoryId&gt;4209&lt;/ProductCategoryId&gt;
                &lt;Rank&gt;31&lt;/Rank&gt;
            &lt;/SalesRank&gt;
            &lt;SalesRank&gt;
                &lt;ProductCategoryId&gt;6511974011&lt;/ProductCategoryId&gt;
                &lt;Rank&gt;65&lt;/Rank&gt;
            &lt;/SalesRank&gt;
            &lt;SalesRank&gt;
                &lt;ProductCategoryId&gt;16587&lt;/ProductCategoryId&gt;
                &lt;Rank&gt;93&lt;/Rank&gt;
            &lt;/SalesRank&gt;
        &lt;/SalesRankings&gt;
    &lt;/Product&gt;
&lt;/GetCompetitivePricingForASINResult&gt;

I am trying to retrieve the "Rank" field only when the ProductCategoryId is equal to "book_display_on_website", however, in my current attempt it appears to set it Rank to the last SalesRank Entry (93) (it should be (48661)). Can someone point me in the right direction?

Is this even possible using this Unmarshal method? or is something like go-pkg-xmlx or gokogiri required? (I am coming from php and usually use simple_xml_parser on php for this type of stuff.)

type Data struct {
XMLName xml.Name `xml:&quot;GetCompetitivePricingForASINResponse&quot;`
Item   []Item  `xml:&quot;GetCompetitivePricingForASINResult&quot;`
}

type Item struct {
Pcat string `xml:&quot;Product&gt;SalesRankings&gt;SalesRank&gt;ProductCategoryId&quot;`
ASIN string `xml:&quot;ASIN,attr&quot;`
Rank string `xml:&quot;Product&gt;SalesRankings&gt;SalesRank&gt;Rank&quot;`
}


	result, err := api.GetCompetitivePricingForASIN(asins)

	if (err != nil) {
		fmt.Println(err)
	}

	data := &amp;Data{}

	xml.Unmarshal([]byte(result), data)
	if err != nil {
		log.Fatal(err)
	}

	for i := 0; i &lt; len(data.Item); i++ {
		fmt.Printf(&quot;%s\n&quot;, data.Item[i])
	}

答案1

得分: 2

xml.Unmarshal() 返回一个你没有存储和检查的 error

xml.Unmarshal([]byte(result), data)
if (err != nil) {
    fmt.Println(err)
}

所以你在下一行测试的 err 不是 xml.Unmarshal() 的结果,而是之前由 api.GetCompetitivePricingForASIN(asins) 返回的相同值。

如果你修改它以正确存储 Unmarshal() 的结果:

err = xml.Unmarshal([]byte(result), data)

你将得到以下错误(已换行):

期望的元素类型为 <GetCompetitivePricingForASINResponse>,但实际为
<GetCompetitivePricingForASINResult>

你的模型没有正确描述 XML 输入。尝试使用以下结构来建模 XML(你想要提取的部分):

type Data struct {
    ASIN       string      `xml:"ASIN,attr"`
    SalesRanks []SalesRank `xml:"Product>SalesRankings>SalesRank"`
}

type SalesRank struct {
    Pcat string `xml:"ProductCategoryId"`
    Rank string `xml:"Rank"`
}

使用这个模型,你可以像这样打印结果:

for _, item := range data.SalesRanks {
    fmt.Printf("Cat: %s; Rank: %s\n", item.Pcat, item.Rank)
}

输出:

Cat: book_display_on_website; Rank: 48661
Cat: 4209; Rank: 31
Cat: 6511974011; Rank: 65
Cat: 16587; Rank: 93

Go Playground 上尝试完整的程序。

这里甚至有一个更简单和更详细的打印方式:

fmt.Printf("%+v", data)

输出(已换行):

&{ASIN:0547569653 SalesRanks:[{Pcat:book_display_on_website Rank:48661}
  {Pcat:4209 Rank:31} {Pcat:6511974011 Rank:65} {Pcat:16587 Rank:93}]}
英文:

xml.Unmarshal() returns an error which you don't store and don't examine:

xml.Unmarshal([]byte(result), data)
if (err != nil) {
    fmt.Println(err)
}

So the err you test in the next line is not the result of the xml.Unmarshal() but the same value returned previously by api.GetCompetitivePricingForASIN(asins).

If you modify it to properly store the result of Unmarshal():

err = xml.Unmarshal([]byte(result), data)

You will get the following error (wrapped):

expected element type &lt;GetCompetitivePricingForASINResponse&gt; but have
&lt;GetCompetitivePricingForASINResult&gt;

Your model doesn't properly describe the XML input. Try the following structure to model the XML (the part you want to take out):

type Data struct {
	ASIN       string      `xml:&quot;ASIN,attr&quot;`
	SalesRanks []SalesRank `xml:&quot;Product&gt;SalesRankings&gt;SalesRank&quot;`
}

type SalesRank struct {
	Pcat string `xml:&quot;ProductCategoryId&quot;`
	Rank string `xml:&quot;Rank&quot;`
}

Using this model, you can print the results like this:

for _, item := range data.SalesRanks {
	fmt.Printf(&quot;Cat: %s; Rank: %s\n&quot;, item.Pcat, item.Rank)
}

Output:

Cat: book_display_on_website; Rank: 48661
Cat: 4209; Rank: 31
Cat: 6511974011; Rank: 65
Cat: 16587; Rank: 93

Try the complete program on the Go Playground.

Here is even a more simple and more informative printing:

fmt.Printf(&quot;%+v&quot;, data)

Output (wrapped):

&amp;{ASIN:0547569653 SalesRanks:[{Pcat:book_display_on_website Rank:48661}
  {Pcat:4209 Rank:31} {Pcat:6511974011 Rank:65} {Pcat:16587 Rank:93}]}

huangapple
  • 本文由 发表于 2015年3月29日 09:14:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/29324564.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定