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
.