关于java:netty系列之netty中常用的xml编码解码器

7次阅读

共计 2998 个字符,预计需要花费 8 分钟才能阅读完成。

简介

在 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/

最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!

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

正文完
 0