简介

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

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

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