金融系统中BER-TLV是一个常用的数据交换协议,TLV是(TAG-LENGTH-VALUE)的缩写,其具体的规范在ISO7616-4中有明确的定义。目前简单描述下关于TLV的编码规则,下文所有的数据表示均为16进制编码。
TAG域:
TAG域的第一个字节编码
TAG域的第二个字节编码
其中注意第一个字节的第六位,其分为基本数据对象和结构数据对象。简单解释下基本数据对象和结构数据对象,简单举两个例子,下面几个都是符合tlv编码的数据流:
70069F3803010203
9F3803010203
可以看到,70 TAG的值(value)域也是由TLV结构组成的。
而9F38 TAG的值域则是由简单数据构成(010203)不需要符合TLV结构编码。
基于这个原则,TLV可以设计成多层嵌套的关系。
例如:
6F30840E325041592E5359532E4444463031A51EBF0C1B61194F08A000000333010101500A50424F43204445424954870101
如果解析嵌套,可以如下表示(以缩进关系表示嵌套关系)
6F(TAG)
30(6F的LEN域)
840E325041592E5359532E4444463031A51EBF0C1B61194F08A000000333010101500A50424F43204445424954870101(6F的VALUE域)
84(TAG)
0E(84的LEN域)
325041592E5359532E4444463031(84的VALUE域)
A5(TAG)
1E(A5的LEN域)
BF0C1B61194F08A000000333010101500A50424F43204445424954870101(A5的VALUE域)
BF0C(TAG)
1B(BFOC的LEN域)
61194F08A000000333010101500A50424F43204445424954870101(BFOC的VALUE域)
61(TAG)
19(61的LEN域)
4F08A000000333010101500A50424F43204445424954870101(61的VALUE域)
4F(TAG)
08(4F的LEN域)
A000000333010101(4F的VALUE域)
50(TAG)
0A(50的LEN域)
50424F43204445424954(50的VALUE域)
87(TAG)
01(87的LEN域)
01(87的VALUE域)
讲完了TAG域,下面简单说明下长度(LEN)域,长度域相比TAG域简单多了,ISO的原文就能很好的说明问题了。
讲完了TLV的基本结构,现在来讲讲目前设计的实现。目前网上实现的TLV代码也很多,但是很多是基于解析的,没有搜索到有关是基于修改的。
因为TVL存在嵌套结构,因此一个多层嵌套的TLV结构被更改了,可能会导致一连串的TLV结构LEN域和值域都需要修改。还是上文的那个6FTLV结构为例,如果底层的87被改了,那么除了和他同级别的50、4F和简单结构的84是不需要改变的,其包含了他的所有嵌套结构的TLV结构,都需要改变(6F\A5\BFOC\61),而不巧,本人碰到了多次需要改变该值的情况,特别如果是长度变化了,那整个TLV结构的长度都需要重新算,比较痛苦,因此就设计了以下的模式。
上面是简单介绍TLV和一些前因后果,下面是实现。
====================================================================
从上文的分析中可以看到,针对一个复合的tlv结构,那么他可以抽象成存在他的值域全是他的下层TLV结构。而一个简单的TLV机构,则可以抽象成他没有下层TLV结构。而真对一个TLV数据串,就可以抽象成多个复杂TLV机构或者简单TLV结构的首尾拼接,各个TLV段之间是平级的。
这个抽象是不是很像二叉树,因此,就考虑用二叉树的方式去实现这个结构,目前定义的为左边的节点均是他的兄弟(同一级别),右边的节点均是他的儿子(他的下级),由此针对上文的6F,抽象成树的结构就是如下图示:
因此,如果我们如果需要求一个简单结构的值,则只需要将值直接放在节点上,如果需要求一个复杂结构的值,只需要把它的儿子做一个左右中遍历(将简单机构直接连接成tlv串,如果是复杂结构则直接取之前的串加上自己的TAG和LENGTH)就能够获得他的value了。
如果是增加一个TLV结构,例如我需要再插入一个A5,其值为9F380101,在原有的84后A5前,则我需要将这个A5首先构造成一个串,然后将左子树连新的A5,将老的A5变为新的A5的左子树,其变化图如下:
当然如果是简单结构,那就直接是树的节点的插入,这边就不在说了。
当然,删除也就是插入的逆向操作,这里也不说了。(嘿嘿,偷懒下了)
最后,程序的输出可以是XML或者JSON的显示,由于目前项目的选择,列子就以JSON的表示了:
插入之前:
[ { "funccode" : 0 }, [ { "6F" : "840E325041592E5359532E4444463031A51EBF0C1B61194F08A000000333010101500A50424F43204445424954870101", "tlvstr" : "6F30840E325041592E5359532E4444463031A51EBF0C1B61194F08A000000333010101500A50424F43204445424954870101" }, [ { "84" : "325041592E5359532E4444463031", "tlvstr" : "840E325041592E5359532E4444463031" }, { "A5" : "BF0C1B61194F08A000000333010101500A50424F43204445424954870101", "tlvstr" : "A51EBF0C1B61194F08A000000333010101500A50424F43204445424954870101" }, [ { "BF0C" : "61194F08A000000333010101500A50424F43204445424954870101", "tlvstr" : "BF0C1B61194F08A000000333010101500A50424F43204445424954870101" }, [ { "61" : "4F08A000000333010101500A50424F43204445424954870101", "tlvstr" : "61194F08A000000333010101500A50424F43204445424954870101" }, [ { "4F" : "A000000333010101", "tlvstr" : "4F08A000000333010101" }, { "50" : "50424F43204445424954", "tlvstr" : "500A50424F43204445424954" }, { "87" : "01", "tlvstr" : "870101" } ] ] ] ] ] ]
插入之后
[ [ { "6F" : "840E325041592E5359532E4444463031A5049F380101A51EBF0C1B61194F08A000000333010101500A50424F43204445424954870101", "tlvstr" : "6F36840E325041592E5359532E4444463031A5049F380101A51EBF0C1B61194F08A000000333010101500A50424F43204445424954870101" }, [ { "84" : "325041592E5359532E4444463031", "tlvstr" : "840E325041592E5359532E4444463031" }, { "A5" : "9F380101", "tlvstr" : "A5049F380101" }, [ { "9F38" : "01", "tlvstr" : "9F380101" } ], { "A5" : "BF0C1B61194F08A000000333010101500A50424F43204445424954870101", "tlvstr" : "A51EBF0C1B61194F08A000000333010101500A50424F43204445424954870101" }, [ { "BF0C" : "61194F08A000000333010101500A50424F43204445424954870101", "tlvstr" : "BF0C1B61194F08A000000333010101500A50424F43204445424954870101" }, [ { "61" : "4F08A000000333010101500A50424F43204445424954870101", "tlvstr" : "61194F08A000000333010101500A50424F43204445424954870101" }, [ { "4F" : "A000000333010101", "tlvstr" : "4F08A000000333010101" }, { "50" : "50424F43204445424954", "tlvstr" : "500A50424F43204445424954" }, { "87" : "01", "tlvstr" : "870101" } ] ] ] ] ], { "funccode" : 0 } ]