简介
在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/
最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!
欢送关注我的公众号:「程序那些事」,懂技术,更懂你!