golang XML动态解析

0
1689

今天在使用微信支付的时候遇到这样一种情况:支付成功之后微信会发送一个通知过来,这个通知包含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里面。

回复

请输入你的评论!
请在这里输入您的名字