金融系統中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 } ]