使用(xpath)条件解组XML

时间:2014-12-17 21:00:19

标签: xml-parsing go

我正在尝试解组一些XML,其结构类似于以下示例:

<player>
 <stat type="first_name">Somebody</stat>
 <stat type="last_name">Something</stat>
 <stat type="birthday">06-12-1987</stat>
</player>

很容易将其解组为像

这样的结构
type Player struct {
  Stats []Stat `xml:"stat"`
}

但是我希望找到一种方法将它解组成一个更像是

的结构
type Player struct {
  FirstName string `xml:"stat[@Type='first_name']"`
  LastName  string `xml:"stat[@Type='last_name']"`
  Birthday  Time   `xml:"stat[@Type='birthday']"`
}

有没有办法用标准的encoding / xml包来做到这一点? 如果没有,你能不能给我一个暗示如何分解这样一个“问题”? (基本上,这种任务的软件架构的最佳实践)。

谢谢你!

1 个答案:

答案 0 :(得分:0)

encoding/xml包不实现xpath,但确实有一组可以使用的选择方法。

以下是如何使用encoding/xml解组您所拥有的XML的示例。因为统计数据都是相同的类型,具有相同的属性,解码它们的最简单方法将是相同类型的切片。 http://play.golang.org/p/My10GFiWDa

var doc = []byte(`<player>
 <stat type="first_name">Somebody</stat>
 <stat type="last_name">Something</stat>
 <stat type="birthday">06-12-1987</stat>
</player>`)

type Player struct {
    XMLName xml.Name     `xml:"player"`
    Stats   []PlayerStat `xml:"stat"`
}

type PlayerStat struct {
    Type  string `xml:"type,attr"`
    Value string `xml:",chardata"`
}

如果您需要经常转换,可以使用UnamrshalXML方法进行转换:http://play.golang.org/p/htoOSa81Cn

type Player struct {
    XMLName   xml.Name `xml:"player"`
    FirstName string
    LastName  string
    Birthday  string
}

func (p *Player) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
    for {
        t, err := d.Token()
        if err == io.EOF {
            break
        } else if err != nil {
            return err
        }

        if se, ok := t.(xml.StartElement); ok {

            t, err = d.Token()
            if err != nil {
                return err
            }

            var val string
            if c, ok := t.(xml.CharData); ok {
                val = string(c)
            } else {
                // not char data, skip for now
                continue
            }

            // assuming we have exactly one Attr
            switch se.Attr[0].Value {
            case "first_name":
                p.FirstName = val
            case "last_name":
                p.LastName = val
            case "birthday":
                p.Birthday = val
            }
        }
    }
    return nil
}