在golang中解析xml文本

Haven't had any luck parsing this snippet of xml text from the output of nmap. I'm interested in parsing the protocol, portid and reason fields out of the xml text. Initially, I tried extracting only the first two fields:

var data = []byte(`
 <ports><extraports state="filtered" count="65526">
    <extrareasons reason="no-responses" count="65526"/>
    </extraports>
    <port protocol="tcp" portid="1"><state state="closed" reason="conn-refused" reason_ttl="0"/><service name="tcpmux" method="table" conf="3"/></port>
    <port protocol="tcp" portid="2"><state state="closed" reason="conn-refused" reason_ttl="0"/><service name="compressnet" method="table" conf="3"/></port>
    <port protocol="tcp" portid="8"><state state="closed" reason="conn-refused" reason_ttl="0"/><service name="unknown" method="table" conf="3"/></port>
    <port protocol="tcp" portid="2709"><state state="closed" reason="conn-refused" reason_ttl="0"/></port>
    <port protocol="tcp" portid="7748"><state state="closed" reason="conn-refused" reason_ttl="0"/></port>
    <port protocol="tcp" portid="12946"><state state="closed" reason="conn-refused" reason_ttl="0"/></port>
    <port protocol="tcp" portid="53094"><state state="closed" reason="conn-refused" reason_ttl="0"/></port>
    <port protocol="tcp" portid="58137"><state state="closed" reason="conn-refused" reason_ttl="0"/></port>
    <port protocol="tcp" portid="63139"><state state="closed" reason="conn-refused" reason_ttl="0"/></port>
    </ports>
`)

I defined my structures as below:

type PortData struct {
    Protocol string `xml:"protocol,attr"`
    Port uint32 `xml:"portid,attr"`
}

type Nmap struct {
    IgnoreMe xml.Name `xml:"ports"`
    Data []PortData `xml:"port"`    
}

func main() {
    var m Nmap
    if err := xml.Unmarshal(data, &m); err == nil {
        log.Fatalln(err)
    }
    log.Println("Succeeded")
    fmt.Printf("%#v
", m)
}

How can I fix my struct definitions to extract the fields of interest? Thanks

You can extract the reason field by updating your structs to read:

type State struct {
    Reason string `xml:"reason,attr"`
}

type PortData struct {
    Protocol string `xml:"protocol,attr"`
    Port     uint32 `xml:"portid,attr"`
    State    State  `xml:"state"`
}

Unfortunately you can't decode the reason attribute into a PortData field. While the package does support picking nested elements, it won't let you combine that with attribute selection (i.e. xml:"state>reason,attr" will result in an error from Unmarshal).

Secondly, there is a small error in your test program: you are bailing out when err is nil, rather than the reverse. With those two changes you should be able to extract the data you're after.

You can experiment with this at: http://play.golang.org/p/hVxLzZ03cC

You just have a typo. It should be err != nil.