使用(xpath)条件解组XML

I'm trying to unmarshall some XML which is structured like the following example:

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

It's dead easy to unmarshal this into a struct like

type Player struct {
  Stats []Stat `xml:"stat"`
}

but I'm looking to find a way to unmarshal it into a struct that's more like

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

is there any way to do this with the standard encoding/xml package? If not, can you give me a hint how one would split down such a "problem" in go? (best practices on go software architecture for such a task, basically).

thank you!

The encoding/xml package doesn't implement xpath, but does have a simple set of selection methods it can use.

Here's an example of how you could unmarshal the XML you have using encoding/xml. Because the stats are all of the same type, with the same attributes, the easiest way to decode them will be into a slice of the same type. 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"`
}

And if it's something you need to transform often, you could do the transformation by using an UnamrshalXML method: 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
}