使用微信支付的时候遇到这样一种情况:支付成功之后微信会发送一个通知过来,这个通知包含xml格式的数据,其中有一个字段是这样的:

coupon_id_n,代金券或立减优惠ID,n ,代金券或立减优惠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元素进行解析了。

<xml><h:appid xmlns:h="http://www.w3school.com.cn/furniture"><![CDATA[wx2421b1c4370ec43b]]></h:appid><attach name="yuanjize"><![CDATA[支付测试]]></attach><bank_type>CFT</bank_type><fee_type><![CDATA[CNY]]></fee_type><is_subscribe><![CDATA[Y]]></is_subscribe><mch_id><![CDATA[10000100]]></mch_id><nonce_str><![CDATA[<hello>5d2b6c2a8db53831f7eda20af46e531c</hello>]]></nonce_str><openid><![CDATA[oUpF8uMEb4qRXf22hE3X68TekukE]]></openid><out_trade_no><![CDATA[1409811653]]></out_trade_no><result_code><![CDATA[SUCCESS]]></result_code><return_code><![CDATA[SUCCESS]]></return_code><sign><![CDATA[B552ED6B279343CB493C5DD0D78AB241]]></sign><sub_mch_id><![CDATA[10000100]]></sub_mch_id><time_end><![CDATA[20140903131540]]></time_end><total_fee>1</total_fee><coupon_fee><![CDATA[10]]></coupon_fee><coupon_count><![CDATA[1]]></coupon_count><coupon_type><![CDATA[CASH]]></coupon_type><coupon_id><![CDATA[10000]]></coupon_id><coupon_fee_0><![CDATA[100]]></coupon_fee_0><trade_type><![CDATA[JSAPI]]></trade_type><transaction_id><![CDATA[1004400740201409030005092168]]></transaction_id>
</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] = datafmt.Println(key,",",data)}}}
}

上面的代码用微信的返回数据作为例子,代码比较简单,流程上就是读取一个TOKEN,判断TOKEN的类型然后把数据填到map里面。下面在说Name这个结构体之前先来料及一下XML的命名空间。

命名空间是什么?看一下下面这个例子,

<table><leg>4<leg>
<table><table><tr><td>15<td><td>16<td><tr>
<table>

可以看到第一个table标签表示的是一个桌子,第二个table标签表示的是一个表格,如果把这个两个标签一起返回给你你就不知道两个标签各自代表的什么意思了,所以我们可以给标签加一个命名空间(也可以叫标签前缀)来区分它们:

<a:table><leg>4<leg>
</a:table><b:table><tr><td>15<td><td>16<td><tr>
</b:table>

这样当读取到标签名字是table的时候,可以通过读取前缀来进行区分。

下面来说Name这个结构体:

type Name struct {Space, Local string
}

StartElementEndElement类型都有这个Name字段,它有两个字段,Space字段代表的是命名空间,Local字段是这个标签的名称。

比如<a:table> </a:table> 那么Space就是a,Local就是table。

如果命名空间是这样声明的<a:table xmls:a="www.baidu.com"> </a:table>,那么Space就是 www.baidu.com,Local还是table

这里再普及一下CDATA:xml解析器是不会解析CDATA标签中的内容。比如当解析器解析到<![CDATA[<hello>CNY</hello>]]>的时候解析出来的是一个文本类型,文本内容是<hello>CNY</hello>。也就是说把<hello>CNY</hello>看成一个单个的文本,不会去再解析hello标签。

最后贴一下上面程序的运行结果:

SE.NAME.SPACE:
SE.NAME.LOCAL: xmlAttrs: [{{xmlns h} http://www.w3school.com.cn/furniture}]
SE.NAME.SPACE: http://www.w3school.com.cn/furniture
SE.NAME.LOCAL: appidAttrs: [{{ name} yuanjize}]
SE.NAME.SPACE: b
SE.NAME.LOCAL: attachSE.NAME.SPACE:
SE.NAME.LOCAL: bank_typeSE.NAME.SPACE:
SE.NAME.LOCAL: fee_typeSE.NAME.SPACE:
SE.NAME.LOCAL: is_subscribeSE.NAME.SPACE:
SE.NAME.LOCAL: mch_idSE.NAME.SPACE:
SE.NAME.LOCAL: nonce_strSE.NAME.SPACE:
SE.NAME.LOCAL: openidSE.NAME.SPACE:
SE.NAME.LOCAL: out_trade_noSE.NAME.SPACE:
SE.NAME.LOCAL: result_codeSE.NAME.SPACE:
SE.NAME.LOCAL: return_codeSE.NAME.SPACE:
SE.NAME.LOCAL: signSE.NAME.SPACE:
SE.NAME.LOCAL: sub_mch_idSE.NAME.SPACE:
SE.NAME.LOCAL: time_endSE.NAME.SPACE:
SE.NAME.LOCAL: total_feeSE.NAME.SPACE:
SE.NAME.LOCAL: coupon_feeSE.NAME.SPACE:
SE.NAME.LOCAL: coupon_countSE.NAME.SPACE:
SE.NAME.LOCAL: coupon_typeSE.NAME.SPACE:
SE.NAME.LOCAL: coupon_idSE.NAME.SPACE:
SE.NAME.LOCAL: coupon_fee_0SE.NAME.SPACE:
SE.NAME.LOCAL: trade_typeSE.NAME.SPACE:
SE.NAME.LOCAL: transaction_id
parse Finish

参考资料:
XML命名空间:http://www.w3school.com.cn/xml/xml_namespaces.asp
XML CDATA:http://www.w3school.com.cn/xml/xml_cdata.asp
golang XML解析:https://my.oschina.net/solate/blog/724958

golang XML解析相关推荐

  1. golang xml和json的解析与生成

    golang中解析xml时我们通常会创建与之对应的结构体,一层层嵌套,完成复杂的xml解析. package main;import ("encoding/xml""fm ...

  2. golang 踩坑:xml解析问题,chanel使用问题

    最近在用golang,记录一下印象比较深的坑 1.第一个是xml解析时的结构体关键字首字母一定要大写,之前解析xml一直解析不了,我一直以为是我结构体构建有问题,对来对去都看不出问题,最后才在一篇不显 ...

  3. golang的xml解析

    <?xml version="1.0" encoding="utf-8"?> <servers version="1"&g ...

  4. Golang配置文件解析-oozgconf

    代码地址如下: http://www.demodashi.com/demo/14411.html 简介 oozgconf基于Golang开发,用于项目中配置文件的读取以及加载,是一个轻量级的配置文件工 ...

  5. c语言解析xml字符串_Python XML解析

    Python XML解析 什么是XML? XML 指可扩展标记语言(eXtensible Markup Language). 你可以通过本站学习XML教程 XML 被设计用来传输和存储数据. XML是 ...

  6. XML解析简介及Xerces-C++简单使用举例

    XML是由World WideWeb联盟(W3C)定义的元语言.它已经成为一种通用的数据交换格式,它的平台无关性,语言无关性,系统无关性,给数据集成与交互带来了极大的方便.XML在不同的语言里解析方式 ...

  7. Java XML解析工具 dom4j介绍及使用实例

    Java XML解析工具 dom4j介绍及使用实例 dom4j介绍 dom4j的项目地址:http://sourceforge.net/projects/dom4j/?source=directory ...

  8. C++ XML解析之TinyXML篇[转]

    最 近使用TinyXML进行C++ XML解析,感觉使用起来比较简单,很容易上手,本文给出一个使用TinyXML进行XML解析的简单例子,很多复杂的应用都可以基于本例子的方法来完 成.以后的文章里会讲 ...

  9. Java XML解析器

    使用Apache Xerces解析XML文档 一.技术概述 在用Java解析XML时候,一般都使用现成XML解析器来完成,自己编码解析是一件很棘手的问题,对程序员要求很高,一般也没有专业厂商或者开源组 ...

最新文章

  1. 刻意练习:LeetCode实战 -- Task21. 二叉树的最大深度
  2. Python SSH爆破以及Python3线程池控制线程数
  3. MDK调试错误之assert_failed
  4. java 从网络Url中下载文件
  5. 用c语言编辑一个通讯录,C语言实现一个通讯录
  6. 算法与数据结构——并查集
  7. [js] 在DOM上同时绑定两个点击事件(一个用捕获,一个用冒泡),事件总共会执行几次,先执行哪个事件?
  8. mybatis映射longtext类型数据_全网首例全栈实践(五)Spring Boot 集成Mybatis
  9. 鼠标方式自动弹出内容html,html 在一个超链接上面,鼠标移动上去时,也显示一串文字,如何实现...
  10. 首尾非零正则_推荐收藏一波,工作中常用的正则表达式总结!
  11. 安居客 Android App 走向平台化 | CSDN 博文精选
  12. 局域网文件共享软件 开源_4个用于共享文件的开源工具
  13. 采用计算机对酒店客房进行管理,酒店客房部计算机管理.doc
  14. ibm17个量子纠缠计算机,走近量子纠缠-17-量子计算机
  15. linux中引号的作用是什么意思,Linux中的双引号的作用
  16. 【XSS跨站脚本】反射型xss(非持久型)
  17. 化繁为简,聊一聊复制状态机系统架构抽象
  18. 微分几何的24-33节笔记暂记(第一基本形式,第二基本形式)
  19. 计算机技术应用广泛以下属于科学计算方面,2016年12月计算机二级MSoffice选择题习题...
  20. NPN三极管和N沟道MOS管引脚定义

热门文章

  1. 最牛语义匹配算法_速围观!
  2. MySQL数据库基础知识7,查询的执行过程
  3. Jquery的on方法绑定事件
  4. 《机器学习笔记(三):多元线性回归与正态分布最大似然估计》
  5. python和tkinter实现摄像头实时无闪烁显示
  6. 上市公司基本面分析的项目
  7. Verilog任意整数分频器
  8. S5PV210芯片的uboot烧录脚本目录(sd_fusing)完整解析
  9. linux将文件内容全角转半角,字符串半角全角互转详解
  10. Minecraft 1.12.2模组开发(四十) buff效果(Potion Effect)