详解netty中常用的xml编码解码器

目录
  • 简介
  • XmlFrameDecoder
  • XmlDecoder
  • 总结

简介

在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已经为我们造好轮子了,我们就不需要再自行发明了。

到此这篇关于netty中常用的xml编码解码器的文章就介绍到这了,更多相关netty解码器内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Netty分布式固定长度解码器实现原理剖析

    固定长度解码器 上一小节:解码器读取数据不完整的逻辑剖析 我们了解到, 解码器需要继承ByteToMessageDecoder, 并重写decode方法, 将解析出来的对象放入集合中集合, ByteToMessageDecoder中可以将解析出来的对象向下进行传播, 这一小节带大家剖析一个最简单的解码器FixedLengthFrameDecoder, 从它入手了解码器的相关原理 FixedLengthFrameDecoder是一个固定长度的解码器, 功能就是根据固定长度, 截取固定大小的字节数进

  • Netty分布式解码器读取数据不完整的逻辑剖析

    目录 概述 第一节: ByteToMessageDecoder 我们看他的定义 我们看其channelRead方法 我们看cumulator属性 我们回到channRead方法中 概述 在我们上一个章节遗留过一个问题, 就是如果Server在读取客户端的数据的时候, 如果一次读取不完整, 就触发channelRead事件, 那么Netty是如何处理这类问题的, 在这一章中, 会对此做详细剖析 之前的章节我们学习过pipeline, 事件在pipeline中传递, handler可以将事件截取并对

  • Netty分布式行解码器逻辑源码解析

    目录 行解码器LineBasedFrameDecoder 首先看其参数 我们跟到重载的decode方法中 我们看findEndOfLine(buffer)方法 这一小节了解下行解码器LineBasedFrameDecoder, 行解码器的功能是一个字节流, 以\r\n或者直接以\n结尾进行解码, 也就是以换行符为分隔进行解析 同样, 这个解码器也继承了ByteToMessageDecoder 行解码器LineBasedFrameDecoder 首先看其参数 //数据包的最大长度, 超过该长度会进

  • 详解Netty编码器和解码器

    目录 一.java的编解码 二.Netty编解码器 2.1 解码器(Decoder) 2.2 代码实现 2.3 编码器(Encoder) 2.4 代码实现 2.5 测试结果 三.编码解码器Codec 3.1 代码实现: 一.java的编解码 1.编码(Encode)称为序列化, 它将对象序列化为字节数组,用于网络传输.数据持久化或者其它 用途. 2.解码(Decode)称为反序列化,它把从网络.磁盘等读取的字节数组还原成原始对象(通常是原 始对象的拷贝),以方便后续的业务逻辑操作. java序列

  • 详解netty中的frame解码器

    目录 简介 LineBasedFrameDecoder DelimiterBasedFrameDecoder FixedLengthFrameDecoder LengthFieldBasedFrameDecoder 总结 简介 netty中的数据是通过ByteBuf来进行传输的,一个ByteBuf中可能包含多个有意义的数据,这些数据可以被称作frame,也就是说一个ByteBuf中可以包含多个Frame. 对于消息的接收方来说,接收到了ByteBuf,还需要从ByteBuf中解析出有用而数据,那

  • 详解netty中常用的xml编码解码器

    目录 简介 XmlFrameDecoder XmlDecoder 总结 简介 在json之前,xml是最常用的数据传输格式,虽然xml的冗余数据有点多,但是xml的结构简单清晰,至今仍然运用在程序中的不同地方,对于netty来说自然也提供了对于xml数据的支持. netty对xml的支持表现在两个方面,第一个方面是将编码过后的多个xml数据进行frame拆分,每个frame包含一个完整的xml.另一方面是将分割好的frame进行xml的语义解析. 进行frame拆分可以使用XmlFrameDec

  • 详解Python中常用的图片处理函数的使用

    目录 cvtColor函数 split()和merge() threshold()函数 自定义threshold函数进行二值化 色度函数applyColorMap cvtColor函数 这个函数有两个参数 1,src 要进行变换的原图像 2,code 转换代码标识 例子: import cv2 image=cv2.imread("ddd.jpg") image1=cv2.cvtColor(image,cv2.COLOR_BGR2BGRA) cv2.imshow(""

  • 详解C++中常用的四种类型转换方式

    目录 1.静态类型转换:static_cast(exp) 2.动态类型转换:dynamic_cast(exp) 3.常类型转换:const_case(exp) 4. 解释类型转换: reinterpret_cast(exp) 1.静态类型转换:static_cast(exp) 1.1静态类型转换主要用于两种转换环境 1.1.1 C++内置类型的转换:与C风格强转类似. 与c相同的地方: #include <iostream> using namespace std; int main() {

  • 详解flutter中常用的container layout实例

    目录 简介 Container的使用 旋转Container Container中的BoxConstraints 总结 简介 在上一篇文章中,我们列举了flutter中的所有layout类,并且详细介绍了两个非常常用的layout:Row和Column. 掌握了上面两个基本的layout还是不够的,如果需要应付日常的layout使用,我们还需要掌握多一些layout组件.今天我们会介绍一个功能强大的layout:Container layout. Container的使用 Container是一

  • 详解Mybatis中常用的约束文件

    SqlMapConfig.xml的约束,也就是Mybatis主配置文件的约束 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> 持久层接口映射文件的

  • 详解JavaScript中常用的函数类型

    网页中的java代码需要写在JavaScript中,里面部分少不了函数,介绍一下JavaScript中常用的函数类型. 1.可变函数 <script> function show(){ alert("第一个..."); } function show(str){ alert("第二个"); } function show(a,b){ alert("第三个..."); alert(a+":"+b); } </s

  • 详解VUE中常用的几种import(模块、文件)引入方式

    1 引入第三方插件 import echarts from 'echarts' 2 引入工具类 第一种是引入单个方法 import {axiosfetch} from './util'; 下面是写法,需要export导出 export function axiosfetch(options) { } 第二种  导入成组的方法 import * as tools from './libs/tools' 其中tools.js中有多个export方法,把tools里所有export的方法导入 vue中

  • 详解js中的几种常用设计模式

    工厂模式 function createPerson(name, age){ var o = new Object(); // 创建一个对象 o.name = name; o.age = age; o.sayName = function(){ console.log(this.name) } return o; // 返回这个对象 } var person1 = createPerson('ccc', 18) var person2 = createPerson('www', 18) 工厂函数

  • 详解idea中web.xml默认版本问题解决

    问题描述:用idea的maven新建一个webapp项目,自动生成的web.xml默认版本是2.3版本(这版本连EL表达式都默认不能使用,无语了). Servlet 2.3: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "h

随机推荐