简介

在json之前,xml是最常用的数据传输格式,虽然xml的冗余数据有点多,但是xml的结构简单清晰,至今仍然运用在程序中的不同地方,对于netty来说自然也提供了对于xml数据的支持。

netty对xml的支持表现在两个方面,第一个方面是将编码过后的多个xml数据进行frame拆分,每个frame包含一个完整的xml。另一方面是将分割好的frame进行xml的语义解析。

进行frame拆分可以使用XmlFrameDecoder,进行xml文件内容的解析则可以使用XmlDecoder,接下来我们会详细讲解两个decoder实现和使用。

XmlFrameDecoder

因为我们收到的是数据流,所以不确定收到的数据到底是什么样的,一个正常的xml数据可能会被拆分成多个数据frame。

如下所示:

   +-------+-----+--------------+
| <this | IsA | XMLElement/> |
+-------+-----+--------------+

这是一个正常的xml数据,但是被拆分成为了三个frame,所以我们需要将其合并成为一个frame如下:

   +-----------------+
| <thisIsAXMLElement/> |
+-----------------+

还有可能不同的xml数据被分拆在多个frame中的情况,如下所示:

   +-----+-----+-----------+-----+----------------------------------+
| <an | Xml | Element/> | <ro | ot><child>content</child></root> |
+-----+-----+-----------+-----+----------------------------------+

上面的数据需要拆分成为两个frame:

   +-----------------+-------------------------------------+
| <anXmlElement/> | <root><child>content</child></root> |
+-----------------+-------------------------------------+

拆分的逻辑很简单,主要是通过判断xml的分隔符的位置来判断xml是否开始或者结束。xml中的分隔符有三个,分别是'<', '>' 和 '/'。

在decode方法中只需要判断这三个分隔符即可。

另外还有一些额外的判断逻辑,比如是否是有效的xml开始字符:

    private static boolean isValidStartCharForXmlElement(final byte b) {
return b >= 'a' && b <= 'z' || b >= 'A' && b <= 'Z' || b == ':' || b == '_';
}

是否是注释:

    private static boolean isCommentBlockStart(final ByteBuf in, final int i) {
return i < in.writerIndex() - 3
&& in.getByte(i + 2) == '-'
&& in.getByte(i + 3) == '-';
}

是否是CDATA数据:

    private static boolean isCDATABlockStart(final ByteBuf in, final int i) {
return i < in.writerIndex() - 8
&& in.getByte(i + 2) == '['
&& in.getByte(i + 3) == 'C'
&& in.getByte(i + 4) == 'D'
&& in.getByte(i + 5) == 'A'
&& in.getByte(i + 6) == 'T'
&& in.getByte(i + 7) == 'A'
&& in.getByte(i + 8) == '[';

通过使用这些方法判断好xml数据的起始位置之后,就可以调用extractFrame方法将要使用的ByteBuf从原始数据中拷贝出来,最后放到out中去:

final ByteBuf frame =
extractFrame(in, readerIndex + leadingWhiteSpaceCount, xmlElementLength - leadingWhiteSpaceCount);
in.skipBytes(xmlElementLength);
out.add(frame);

XmlDecoder

将xml数据拆分成为一个个frame之后,接下来就是对xml中具体数据的解析了。

netty提供了一个xml数据解析的方法叫做XmlDecoder,主要用来对已经是一个单独的xml数据的frame进行实质内容的解析,它的定义如下:

public class XmlDecoder extends ByteToMessageDecoder

XmlDecoder根据读取到的xml内容,将xml的部分拆分为XmlElementStart,XmlAttribute,XmlNamespace,XmlElementEnd,XmlProcessingInstruction,XmlCharacters,XmlComment,XmlSpace,XmlDocumentStart,XmlEntityReference,XmlDTD和XmlCdata。

这些数据基本上覆盖了xml中所有可能出现的元素。

所有的这些元素都是定义在io.netty.handler.codec.xml包中的。

但是XmlDecoder对xml的读取解析则是借用了第三方xml工具包:fasterxml。

XmlDecoder使用了fasterxml中的AsyncXMLStreamReader和AsyncByteArrayFeeder用来进行xml数据的解析。

这两个属性的定义如下:

    private static final AsyncXMLInputFactory XML_INPUT_FACTORY = new InputFactoryImpl();
private final AsyncXMLStreamReader<AsyncByteArrayFeeder> streamReader;
private final AsyncByteArrayFeeder streamFeeder; this.streamReader = XML_INPUT_FACTORY.createAsyncForByteArray();
this.streamFeeder = (AsyncByteArrayFeeder)this.streamReader.getInputFeeder();

decode的逻辑是通过判断xml element的类型来分别进行不同数据的读取,最后将读取到的数据封装成上面我们提到的各种xml对象,最后将xml对象添加到out list中返回。

总结

我们可以借助XmlFrameDecoder和XmlDecoder来实现非常方便的xml数据解析,netty已经为我们造好轮子了,我们就不需要再自行发明了。

本文已收录于 http://www.flydean.com/14-7-netty-codec-xml/

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!

欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!

netty系列之:netty中常用的xml编码解码器的更多相关文章

  1. Netty 系列之 Netty 高性能之道 高性能的三个主题 Netty使得开发者能够轻松地接受大量打开的套接字 Java 序列化

    Netty系列之Netty高性能之道 https://www.infoq.cn/article/netty-high-performance 李林锋 2014 年 5 月 29 日 话题:性能调优语言 ...

  2. 【读后感】Netty 系列之 Netty 高性能之道 - 相比 Mina 怎样 ?

    [读后感]Netty 系列之 Netty 高性能之道 - 相比 Mina 怎样 ? 太阳火神的漂亮人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商 ...

  3. ES6系列之项目中常用的新特性

    ES6系列之项目中常用的新特性 ES6常用特性 平时项目开发中灵活运用ES6+语法可以让开发者减少很多开发时间,提高工作效率.ES6版本提供了很多新的特性,接下来我列举项目中常用的ES6+的特性: l ...

  4. netty系列之:netty中常用的字符串编码解码器

    目录 简介 netty中的字符串编码解码器 不同平台的换行符 字符串编码的实现 总结 简介 字符串是我们程序中最常用到的消息格式,也是最简单的消息格式,但是正因为字符串string太过简单,不能附加更 ...

  5. netty系列之:netty中各不同种类的channel详解

    目录 简介 ServerChannel和它的类型 Epoll和Kqueue AbstractServerChannel ServerSocketChannel ServerDomainSocketCh ...

  6. netty系列之:netty实现http2中的流控制

    目录 简介 http2中的流控制 netty对http2流控制的封装 Http2FlowController Http2LocalFlowController Http2RemoteFlowContr ...

  7. netty系列之:netty中的核心编码器bytes数组

    目录 简介 byte是什么 netty中的byte数组的工具类 netty中byte的编码器 总结 简介 我们知道netty中数据传输的核心是ByteBuf,ByteBuf提供了多种数据读写的方法,包 ...

  8. Netty 系列之 Netty 高性能之道

    1. 背景 1.1. 惊人的性能数据 最近一个圈内朋友通过私信告诉我,通过使用 Netty4 + Thrift 压缩二进制编解码技术,他们实现了 10 W TPS(1 K 的复杂 POJO 对象)的跨 ...

  9. Netty系列之Netty高性能之道

    转载自http://www.infoq.com/cn/articles/netty-high-performance 1. 背景 1.1. 惊人的性能数据 最近一个圈内朋友通过私信告诉我,通过使用Ne ...

随机推荐

  1. Django的多数据库与读写分离

    1.多个数据库 settings.py DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.pa ...

  2. Streamlit:快速数据可视化界面工具

    目录 Streamlit简介 Streamlit使用指南 常用命令 显示文本 显示数据 显示图表 显示媒体 交互组件 侧边栏 缓存机制 Streamlit使用Hack Streamlit的替代品 相关 ...

  3. 4.1 ROS元功能包

    4.1 ROS元功能包 场景:完成ROS中一个系统性的功能,可能涉及到多个功能包,比如实现了机器人导航模块,该模块下有地图.定位.路径规划...等不同的子级功能包.那么调用者安装该模块时,需要逐一的安 ...

  4. iView 一周年了,同时发布了 2.0 正式版,但这只是开始...

    两年前,我开始接触 Vue.js 框架,当时就被它的轻量.组件化和友好的 API 所吸引.之后我将 Vue.js 和 Webpack 技术栈引入我的公司(TalkingData)可视化团队,并经过一年 ...

  5. JS 用状态机的思想看Generator之基本语法篇

    前言 最近学习了阮一峰老师的<ECMAScript 6 入门>里的Generator相关知识,以及<你不知道的JS>中卷的异步编程部分.同时在SegmentFault问答区看到 ...

  6. SpringCloud微服务治理技术入门(SCN)

    1.集群.分布式.微服务 首先先理解三个感念 什么是集群?: 同一个业务,部署在多个服务器上,目的是实现高可用,保证节点可用! 什么是分布式?: 一个业务分拆成多个子业务,部署在不同的服务器上,每个子 ...

  7. vscode代码格式化快捷键及保存时自动格式化

    一.实现vs code中代码格式化快捷键:[Shift]+[Alt]+ F 二.实现保存时自动代码格式化: 1)文件 ------.>[首选项]---------->[设置]: 2)搜索  ...

  8. Python简单文件读写

    ''' 用文件存储账户信息 使用列表存储多个账户信息,每个账户为一个字典对象 ''' users=[] #创建一个空列表 users.append({'id':'admin','pwd':'1235@ ...

  9. 微信小程序HTTP接口请求封装

    1.方法封装(新建文件夹util,工具文件,在文件夹下创建request.js文件,用于对方法封装)request.js: var app = getApp(); //项目URL相同部分,减轻代码量, ...

  10. TypeScript学习文档-基础篇(完结)

    目录 TypeScript学习第一章:TypeScript初识 1.1 TypeScript学习初见 1.2 TypeScript介绍 1.3 JS .TS 和 ES之间的关系 1.4 TS的竞争者有 ...