duanbin3021 2016-10-07 20:27
浏览 42
已采纳

使用相同的名称但元素分开的方式来解组嵌套数组

I have a problem where an API returns two nested XML arrays in a response both with the name rowset but different elements. Trying to unmarshal into a struct causes the error field "Attackers" with tag "rowset>row" conflicts with field "Items" with tag "rowset>row".

They both have an attribute name which are unique. Is it possible to influence the parser with this attribute?

See example: https://play.golang.org/p/BinDfC3XsW

  • 写回答

2条回答 默认 最新

  • douxin2002 2016-10-07 23:34
    关注

    If you can't change the structure of xml data, then defer unmarshaling rowset with the following steps (Working example can be found at Go Playground):

    1. Unmarshal elements except rowset which are related to victim. During this step, the rowset will be unmarshaled into raw XML data.
    2. Decode raw XML separately using Decoder.DecodeElement.

    First declare the data structure as follows (declaration of Victim, Attacker, Item is omitted):

    type Kill struct{
        // Generic kill information
        KillID              int64      `xml:"killID,attr"`
        Hash                string
        SolarSystemID       int64      `xml:"solarSystemID,attr"`
        MoonID              int64      `xml:"moonID,attr"`
        // Victim Information
        Victim              Victim     `xml:"victim"`      
        RawAttackersItems   []byte     `xml:",innerxml" json:"-"`
        Attackers           []Attacker `xml:"-"`
        Items               []Item     `xml:"-"`        
    } 
    
    type Kills struct {
        Kills []Kill `xml:"result>rowset>row"`
    }
    

    Next, code lines for unmarshaling the xml:

    //Step (1). Unmarshal to Kills
    v := &Kills{}
    if err := xml.Unmarshal([]byte(xmlText()), v); err != nil {
        fmt.Printf("Error unmarshaling: %v
    ", err)
        return
    }
    
    //Step (2). Decode attackers and items related to victim
    for i, k := range v.Kills {   
        v.Kills[i].Attackers, v.Kills[i].Items = decodeAttackerAndItems(k.RawAttackersItems)
    }
    

    and finally the decoder function:

    func decodeAttackerAndItems(data []byte) ([]Attacker, []Item) {
        xmlReader := bytes.NewReader(data)
        decoder := xml.NewDecoder(xmlReader)
    
        const (
            unknown int = iota
            attackers
            items
        )    
        rowset := unknown
    
        attackerList := []Attacker{}
        itemList := []Item{}
    
        for {
            t, _ := decoder.Token() 
            if t == nil { 
                break 
            } 
    
            switch se := t.(type) { 
            case xml.StartElement: 
                if se.Name.Local == "rowset" {
                    rowset = unknown
                    for _, attr := range se.Attr {
                        if attr.Name.Local == "name" {
                            if attr.Value == "attackers" {
                                rowset = attackers
                                break
                            } else if attr.Value == "items" {
                                rowset = items
                                break
                            }
                        }
                    }
                } else if se.Name.Local == "row" {
                    switch rowset {
                    case attackers:
                        a := Attacker{}
                        if err := decoder.DecodeElement(&a, &se); err == nil {
                            attackerList = append(attackerList, a)
                        }
                    case items:
                        it := Item{}
                        if err := decoder.DecodeElement(&it, &se); err == nil {
                            itemList = append(itemList, it)
                        }
                    }
                }
            }
        }
    
        return attackerList, itemList
    }
    

    展开全部

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)
编辑
预览

报告相同问题?

手机看
程序员都在用的中文IT技术交流社区

程序员都在用的中文IT技术交流社区

专业的中文 IT 技术社区,与千万技术人共成长

专业的中文 IT 技术社区,与千万技术人共成长

关注【CSDN】视频号,行业资讯、技术分享精彩不断,直播好礼送不停!

关注【CSDN】视频号,行业资讯、技术分享精彩不断,直播好礼送不停!

客服 返回
顶部