前面介绍了JSON格式的报文解析,虽然json串短小精悍,也能有效表达层次结构,但是每个元素只能找到对应的元素值,不能体现更丰富的样式特征。比如某个元素除了要传输它的字符串文本,还想传输该文本的类型、字体大小、字体颜色等特征,且这些额外的风格样式与业务逻辑无关,自然不适合为它们单独设立参数字段。倘若采用JSON格式定义包括样式特征在内的文本元素,要么摒弃风格样式这种附加属性,要么将风格样式单列为专门的字段参数,然而不管哪种做法,都未能妥善解决附加属性的表达问题。可见轻量级的JSON格式依然存在力不从心的情况,为此人们早早发明了拥有强大表示能力的XML格式,XML的全称是“Extensible Markup Language”(可扩展标记语言),它不但支持结构化数据的描述,还支持各类附加属性的定义,非常适合在网络中传输信息。
下面先看一个XML报文格式的购物订单样例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

<?xml version="1.0" encoding="gbk"?> 思无邪

桃花岛水帘洞123号

15960238696 Mate30 1 8888 格力中央空调 1 58000 红蜻蜓皮鞋 3 999

接着对上面的XML样例庖丁解牛,分析一下XML格式都有哪些特点,分析结果罗列如下:
1、每个元素依然由参数名称和参数值组成,参数名称为尖括号所包裹,且分为标记头与标记尾两部分,标记尾在尖括号内部多了个斜杆。如此一来,一个字段的完整形式为“<参数名称>参数值</参数名称>”。
2、因为每个元素都自带标记头与标记尾,很容易区分在哪开始在哪结束,所以元素之间无需额外的分隔符,只要有标记头与标记尾就足够辨别了。
3、每个结构也需要专门的标记头与标记尾,中间再填入若干元素或者其它结构。
4、对于数组形式的数据,XML报文采用多个同名的结构标记并排列举,表示这里存在同名结构的数组信息,也可看作是清单信息。
5、XML格式允许在报文开头的encoding属性处指定当前报文的字符编码类型,常见的有汉字内码规范GBK,以及世界通用编码规范UTF-8。
6、每个结构或者元素节点,也支持在标记头部分填充附加属性,用于指定参数值以外的特定信息。
大致了解了XML报文的格式规范,还得在程序中加以解析才行。传统的XML解析方式有DOM和SAX两种,DOM方式会把整个XML报文读进来,并且所有节点全被自动加载到一个树状结构,以后每个节点值都到该树状结构中读取。SAX方式不会事先读入整个XML报文,而是根据节点名称从报文起点开始扫描,一旦找到该节点的标记头位置,即刻往后寻找该节点的标记尾,那么节点标记头尾之间的数据便是节点值了。单就某个节点值的解析过程而言,加载所有节点的DOM方式显然较费功夫,从头顺序查找的SAX方式执行效率更高。但若要求同时获取多个节点的数值,则采取树状结构遍历的DOM方式总体性能更加,而每次都从头找起的SAX方式无疑做了重复劳动。总之两种方式的解析效果各有优劣,需要按照实际场景决定取舍。
尽管JDK集成了DOM与SAX的解析工具,其中DOM解析工具封装在包org.w3c.dom中,SAX解析工具封装在包javax.xml.parsers中,可是它俩用起来着实费劲,解析过程艰深晦涩,实际开发当中基本不予采用。应用比较多的XML解析工具反而是第三方的Dom4j,Dom4j的解析方式遵循DOM规则,但比起Java自带的DOM工具要易用得多,其性能也很优异,几乎成为Java开发必备的XML解析神器了。通过Dom4j解析XML报文的步骤主要有下列五步:
1、创建SAXReader阅读器对象;
2、把字符串形式的XML报文转换为输入流对象;
3、命令阅读器对象从输入流中读取Document文档对象;
4、获得文档对象的根节点Element;
5、从根节点往下依次解析每个层级的节点值;
在具体的节点解析过程之中,会频繁调用Element的相关方法,它的常用方法说明如下:
getText:获得当前节点的字符串值。
element:获得当前节点下面指定名称的子节点对象。
elementText:获得当前节点下面指定名称的子节点值。
elements:获得当前节点下面指定名称的子节点清单。
attribute:获得当前节点自身指定名称的属性对象。
attributeValue:获得当前节点自身指定名称的属性值。
attributes:获得当前节点拥有的全部属性清单。

仍以前述的XML报文为例,下面是采用Dom4j解析该XML串的代码例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// 通过dom4j解析xml串
private static GoodsOrder testParserByDom4j(String xml) {
GoodsOrder order = new GoodsOrder(); // 创建一个购物订单对象
// 创建SAXReader阅读器对象
SAXReader reader = new SAXReader();
// 根据字符串构建字节数组输入流
try (InputStream is = new ByteArrayInputStream(xml.getBytes(CHARSET))) {
// 命令阅读器从输入流中读取文档对象
Document document = reader.read(is);
// 获得文档对象的根节点
Element root = document.getRootElement();
// 获取根节点下面名叫user_info的节点
Element user_info = root.element(“user_info”);
// 获取user_info节点下面名叫name的节点值
order.user_info.name = user_info.element(“name”).getText();
// 获取user_info节点下面名叫address的节点值
order.user_info.address = user_info.element(“address”).getText();
// 获取user_info节点下面名叫phone的节点值
order.user_info.phone = user_info.element(“phone”).getText();
System.out.println(String.format(“用户信息如下:姓名=%s,地址=%s,手机号=%s”,
order.user_info.name, order.user_info.address, order.user_info.phone));
// 获取根节点下面名叫goods_list的节点清单
List goods_list = root.element(“goods_list”).elements();
for (int i=0; i<goods_list.size(); i++) { // 遍历商品节点清单
Element goods_item = goods_list.get(i);
GoodsItem item = new GoodsItem(); // 创建一项商品对象
// 获取当前商品项节点下面名叫goods_name的节点值
item.goods_name = goods_item.element(“goods_name”).getText();
// 获取当前商品项节点下面名叫goods_number的节点值
item.goods_number = Integer.parseInt(goods_item.element(“goods_number”).getText());
// 获取当前商品项节点下面名叫goods_price的节点值
item.goods_price = Double.parseDouble(goods_item.element(“goods_price”).getText());
System.out.println(String.format(“第%d个商品:名称=%s,数量=%d,价格=%f”,
i+1, item.goods_name, item.goods_number, item.goods_price));
order.goods_list.add(item); // 往商品清单中添加指定商品对象
}
} catch (Exception e) {
e.printStackTrace();
}
return order; // 返回解析后的购物订单对象
}

运行以上的解析代码,观察到以下的购物订单日志,可见成功实现了xml串到对象的解析操作:

1
2
3
4
用户信息如下:姓名=思无邪,地址=桃花岛水帘洞123号,手机号=15960238696
第1个商品:名称=Mate30,数量=1,价格=8888.000000
第2个商品:名称=格力中央空调,数量=1,价格=58000.000000
第3个商品:名称=红蜻蜓皮鞋,数量=3,价格=999.000000
除了解析各节点的节点值,Dom4j还能解析各节点的属性值,若想正常解析指定名称的属性值,则需明确下列三个要素:该属性的上级节点对象、该属性所在节点的节点名称,该属性的属性名称。有了这三个要素,即可通过以下方法从指定节点的指定属性成功获取属性值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 打印指定节点名称的指定属性值
private static void printValueAndAttr(Element parent, String node_name, String attr_name) {
// 获取父节点下面指定名称的子节点
Element element = parent.element(node_name);
// 获得子节点的节点值
String node_value = element.getText();
String attr_value = “”;
// 根据属性名称获取子节点的对应属性对象
Attribute attr = element.attribute(attr_name);
if (attr != null) {
attr_value = attr.getText(); // 获取该属性的属性值
}
// 打印子节点的详细信息,包括节点名称、节点值、属性名称、属性值
System.out.println(String.format(“节点名称=%s, 节点值=%s, 属性名称=%s, 属性值=%s”,
node_name, node_value, attr_name, attr_value));
}

接下来在原先的XML解析代码里补充如下的一行属性解析代码:

1
2
// 打印user_info节点的name子节点的type属性值
printValueAndAttr(user_info, “name”, “type”);

再次运行XML解析代码,在输出的购物订单日志中观察到多了下面这行日志,表示解析到了name节点的type属性值:

1
节点名称=name, 节点值=思无邪, 属性名称=type, 属性值=string

原文:https://www.cnblogs.com/pinlantu/p/11000515.html

Java开发笔记(一百零九)XML报文的定义和解析相关推荐

  1. Java开发笔记XML报文的解析

    Java开发笔记XML报文的解析 前言 正文 代码示例 结语 前言 项目任务里需要解析xml报文. 于是开始着手学习相关知识,在查看了多篇博文后找到了一篇不错的,讲的很实用. 转载来源:Java开发笔 ...

  2. Java开发笔记(一百零一)通过加解锁避免资源冲突

    前面介绍了如何通过线程同步来避免多线程并发的资源冲突问题,然而添加synchronized的方式只在简单场合够用,在一些高级场合就暴露出它的局限性,包括但不限于下列几点: 1.synchronized ...

  3. Java开发笔记(一百零三)线程间的通信方式

    前面介绍了多线程并发之时的资源抢占情况,以及利用同步.加锁.信号量等机制解决资源冲突问题,不过这些机制只适合同一资源的共享分配,并未涉及到某件事由的前因后果.日常生活中,经常存在两个前后关联的事务,像 ...

  4. (硅谷课堂项目)Java开发笔记4:前端基础知识(二)

    文章目录 (硅谷课堂项目)Java开发笔记4:前端基础知识(二) 一.NPM 1.NPM简介 1.1.什么是NPM 1.2.NPM工具的安装位置 2.使用npm管理项目 2.1.创建文件夹npm 2. ...

  5. Java开发笔记(一百一十三)HttpClient实现下载与上传

    前面介绍了通过HttpClient实现HTTP接口的GET方式调用和POST方式调用,那么文件下载与文件上传又该如何操作呢?其实在HttpClient看来,文件下载属于特殊的GET调用,只不过应答报文 ...

  6. 微信公众号Java开发-笔记02【开发接入准备、开发接入】

    学习视频网址:哔哩哔哩网站 微信公众号开发-Java版 [P01-P02]微信公众号Java开发-笔记01[微信公众号介绍.开发环境搭建] [P03-P04]微信公众号Java开发-笔记02[开发接入 ...

  7. 微信公众号Java开发-笔记01【微信公众号介绍、开发环境搭建】

    学习网址:哔哩哔哩网站 微信公众号开发-Java版 微信公众号Java开发-笔记01[微信公众号介绍.开发环境搭建] 微信公众号Java开发-笔记02[] 微信公众号Java开发-笔记03[] 微信公 ...

  8. Java开发笔记(三十三)字符包装类型

    正如整型int有对应的包装整型Integer那样,字符型char也有对应的包装字符型Character.初始化字符包装变量也有三种方式,分别是:直接用等号赋值.调用包装类型的valueOf方法.使用关 ...

  9. Java开发笔记(二十三)数组工具Arrays

    数组作为一种组合形式的数据类型,必然要求提供一些处理数组的简便办法,包括数组比较.数组复制.数组排序等等.为此Java专门设计了Arrays工具,该工具包含了几个常用方法,方便程序员对数组进行加工操作 ...

最新文章

  1. Android OkHttp框架解析
  2. 完美解决小程序一维数组循环渲染列表不够用问题
  3. minst0-9对应81-30-3的特征频率曲线
  4. centos 卸载_CentOS「linux」学习笔记12:磁盘管理、分区挂载卸载操作
  5. UVA10561 Treblecross
  6. 2011年倒数第三天,下雪,第一次写博客
  7. 某班的成绩出来了,现在老师要把班级的成绩打印出来,和 显示当前时间
  8. JSP项目引入Vue.js进行项目开发(工程搭建)
  9. Java面向对象练习题之定义交通工具类型,控制速度
  10. 计算机系统汉字编码分为,计算机中的汉字编码
  11. 不懂面试官想要哪种数据分析师,简历写的再好也没用!文末有福利
  12. 量化敏捷项目管理案例分享
  13. APP兼容性测试---testin云测试平台
  14. 尚硅谷python入门
  15. 第16章 调色盘管理器
  16. 【快乐摸鱼】— 用python开发益智游戏
  17. 中山大学 精品课程C++ 视频教学
  18. 【算法基础】堆排序——O(nlogn)
  19. 同行者语音助手_车载语音搭载率接近八成,“后价格战”时代的错位竞争GGAI头条...
  20. 同城小程序应该怎么做?

热门文章

  1. css超出隐藏变成...
  2. 确保计时服务执行无误 Cloudflare将推出Roughtime
  3. 多功能智能感应台灯设计(FAQ)
  4. 用PYthon绘制一个可爱的猪
  5. SCU - 4438 KMP
  6. Mac os 安装Maven
  7. 百度UNIT 关于导航的连续意图识别的解决方案
  8. 智能汽车行业深度报告:华为入局智能汽车,产业价值链面临重构
  9. Rimworld 太好玩了,强烈推荐 尤其是加了各种mod后
  10. 威漫哨兵机器人_漫威:哨兵机器VS毒液谁更胜一筹?只能说哨兵机器人还不够强!...