今天在使用微信支付的时候遇到这样一种情况:支付成功之后微信会发送一个通知过来,这个通知包含xml格式的数据,其中有一个字段是这样的:
coupon_id_n,代金券或立减优惠ID, n , Unknown node type: a 或立减优惠ID,n,代金券或立减优惠ID,n为下标,从0开始编号
也就是说我们收到的xml可能是 <coupon_id_1></coupon_id_1>也可能是<coupon_id_10></coupon_id_10>总之这个字段的名字是随着n的变化而变化的,这样的xml我们在使用golang解析的时候直接给结构体设置TAG接着使用xml.Unmarshal解析是行不通的,因为这个TAG是不确定的。这里只能挨个读取xml元素进行解析了。
func XmlDecode(data string) map[string]string{ decoder := xml.NewDecoder(strings.NewReader(data)) result := make(map[string]string) key := "" for{ token, err := decoder.Token() //读取一个标签或者文本内容 if err==io.EOF{ fmt.Println("parse Finish") return result } if err!=nil{ fmt.Println("parse Fail:",err) return result } switch tp := token.(type) { //读取的TOKEN可以是以下三种类型:StartElement起始标签,EndElement结束标签,CharData文本内容 case xml.StartElement: se := xml.StartElement(tp) //强制类型转换 if se.Name.Local!="xml"{ key=se.Name.Local } if len(se.Attr)!=0{ //读取标签属性 fmt.Println("Attrs:",se.Attr) } fmt.Println("SE.NAME.SPACE:",se.Name.Space) //读取命名空间 fmt.Println("SE.NAME.LOCAL:",se.Name.Local) //读取标签名称 fmt.Println() case xml.EndElement: ee := xml.EndElement(tp) if ee.Name.Local == "xml"{ return result } fmt.Println("EE.NAME.SPACE:",ee.Name.Space) fmt.Println("EE.NAME.LOCAL:",ee.Name.Local) case xml.CharData: //文本数据,注意一个结束标签和另一个起始标签之间可能有空格 cd := xml.CharData(tp) data := strings.TrimSpace(string(cd)) if len(data)!=0{ result[key] = data fmt.Println(key,",",data) } } } }
上面的代码用微信的返回数据作为例子,代码比较简单,流程上就是读取一个TOKEN,判断TOKEN的类型然后把数据填到map里面。