具体实施方式
以下结合附图对本发明的具体实施方式进行说明。
本发明将所描述的编码规则称为“BXML(Binary XML)”,以示与WBXML的区别。
本发明所述方法的流程示意图参见图1。本发明的基本思想是先建立BXML编码格式,包括对版本号、消息长度、字符集和不定结构等等的描述;按照BXML编码格式,构造结构化数据描述文件;然后使用BXML编译器读取所述结构化数据描述文件,BXML编译器根据命令生成某种具体的计算机语言的源代码,与具体的应用逻辑和传输方式相结合,实现应用数据结构到计算机语言的数据结构映射,同时自动实现结构标签的编码映射。
以下分别对建立BXML编码格式,构造结构化数据描述文件以及生成某种具体的计算机语言的源代码进行说明。
本发明提出的BXML编码格式如下:
BXMLMessage =version msgLength charset ANY
version =u_int8containing BXML version number
msgLength =u_int16
charset =mb_u_int32indicating the charset
ANY =[SWITCH_PAGH codepage]TAG[struct]
struct =*content END
content =INTERNAL_TAG[integer|string|binary|struct|union|enum|array|ANY]
integer =mb_int32
string =string terminated with zero
binary =length*byte
length =integer
union =content
enum =integer
array =*arrayItem END
arrayItem=ARRAY_ITEM(integer|string|binary|struct)
版本号version=u_int8containing BXML version number
所有BXML编码的初始字节代表BXML的版本号,其编码规则与WBXML相同。它的高四位比特代表主版本号减一,低四比特代表从版本号。例如,版本2.7被编码成0X17。如果将本发明的版本号指定为1.1,则被编码成0X01。
消息长度msgLength=u_int16
消息长度指后续的BXML编码的可变字节数,不包括版本号和消息长度本身所占用的字节数。它被编码成一个双字节整数(按网络序)。该域的目的是方便BXML编码在面向连接的传输(如TCP)中使用,对解码器无影响。
字符集charset=mb_u_int32
字符集定义后续的BXML编码中的所有字符串基本类型所采用的编码字符集。该域本身被编码成一个多字节整数,其整数值是IANA为字符集分配的MIB号。字符集为零,则代表编解码双方预先已经约定默认的字符集。
考虑到代码生成的简单性,本发明不接受那些在C语言中结尾标记不是一个单字节零值的字符集,如UTF-16。事实上,也很少有人用这样的字符集作为传输数据的编码,而且我们总是可以用其他字符集来替换他们,如UTF-8或任何专用字符集(如GB2312)等。
不定结构ANY=[SWITCH_PAGH codepage]TAG[struct]
ANY部分是一个带标签的结构,解码器可以通过标签值知道结构的类型。TAG值由BXML编译器自动分配。BXML编译器总是按照一个BXML结构描述文件中结构定义的顺序从0X05开始递增地分配TAG值。结构的TAG值仅仅在对应的codepage空间中有效。
缺省的codepage值是零。如果codepage不是零,则SWITCH_PAGH codepage必须出现,而且它指定的codepage值仅仅对紧接着的struct生效。这点与WBXML不同,在WBXML中,codepage始终生效直到下一个SWITCH__PAGH codepage出现。本发明的考虑在于,一个结构中内含的结构可能位于其他的codepage空间,如果按照WBXML的编码规则,则SWITCH_PAGH可能反复地出现,而本发明认为解码器已经预知了任何结构成员的类型,所以对结构的成员根本不需要codepage和结构TAG,因此我们定义SWITCH_PAGH仅仅生效一次。这样还可以避免解码器需要记住codepage状态。
TAG及其所属空间
TAG被编码成一个单字节,它具备下面的结构:
一个TAG总是在它所属的空间中有效,有三种类型的TAG空间,如下表所示:
结构struct=*content END
一个结构由若干个内容的编码和一个END标签组成,每个内容代表了一个结构的成员,结构成员出现与否由应用逻辑自行决定,成员的出现可以带值也可以不带值,也由应用逻辑自行决定。
内容content=INTERNAL_TAG[integer|string|binary|struct|union|enum|array|ANY]
一个内容代表结构或联合的一个成员,它可以带值出现,或不带值出现。它由一个内部标签和对应的值的编码组成。
整数integer =mb_int32
一个整数被编码成一个多字节整数,规则与WBXML相同。它由一系列字节组成,每个字节的第7(最高)比特为连续标记,如果它为1,表示该整数还包括后续字节编码,否则表示当前字节是该整数的最后一个字节编码。该整数值由这一系列的字节去除连续标记后剩余的比特位串接起来表示(由高到低)。
字符串string=string terminated with a single zero byte
一个字符串按照字符集指定的编码方式进行编码,并用一个单字节零结尾。考虑到代码生成的简单性,本发明不接受那些在C语言中结尾标记不是一个单字节零值的字符集,如UTF-16。事实上,也很少有人用这样的字符集作为传输数据的编码,而且我们总是可以用其他字符集来替换他们,如UTF-8或任何专用字符集(如GB2323)等。
二进制数据串binary =length*byte
任意的二进制数据串的编码规则与WBXML中的opaque相同,由一个长度指示和若干字节数据组成。其中,长度指示指该二进制数据串的字节数,不包括其自身的字节数,它被编码成一个多字节整数。
联合union=content
联合由一个单一的内容编码组成,它可以带值或不带值。
枚举enum=integer
枚举被编码成多字节整数,代表所定义的枚举值。
数组array=*arrayItem END
数组由若干数组元素的编码和一个END标签组成。
数组元素arrayItem=ARRAY_ITEM(integer|string|binary|struct)
一个数组元素由一个ARRAY_ITEM标签和元素值的编码组成。数组元素类型对解码器是预知的。
本发明的BXML编码格式继承的WBXML的特性,主要包括:
继承了WBXML中的元素(Element)所具备的特性,包括元素的嵌套、缺省、无内容单一元素等;
在编码上仍然对元素标签(Element tag)采用单字节编码,并采用编码空间(codepage)避免编码冲突;
继承了部分全局标签(Global token),如SWITCH_PAGE,END等。
基本数据类型编码规则与WBXML相同,如多字节整数(mb_int),内联字符串(inline string)和不透明数据(opaque)等;
基于BXML编码的开发过程和代码自动生成
开发过程如图2所示。本发明针对最常用的计算机语言C++和JAVA说明代码自动生成的原理。
首先需要根据具体应用需求编写结构化数据描述文件,然后使用BXML编译器读取这些描述文件,BXML编译器根据命令生成某种具体的计算机语言的源代码,如C++、JAVA。这些自动生成的代码包含下面的主要功能:
用同名的类名、成员名直接表达结构化数据类型,开发人员可利用这些代码直接设置或提取结构化数据的内容,而不需要象DOM或SAXAPI那样间接地访问。
代码中包含编解码函数,可用于生成或解析BXML编码数据。
代码中可包含自打印功能,方便调试。
在使用BXML编译器生成源代码以后,开发人员可利用这些代码与具体的应用逻辑和传输方式结合起来,实现应用数据的交换。开发人员不需要再编写任何编解码的代码,也不用再间接访问结构化数据。
结构化数据的描述文件
结构化数据描述文件用于描述事先确定的结构化数据的结构,其地位类似于XML的DTD文件或Schema文件,但与XML DTD或Schema文件不同的是,它的目的不是用于对BXML编码进行校验,而是用于指导编译器自动生成程序源代码,并告知编译器应生成什么样的编解码代码。
以下是有关结构化数据描述文件的规则:
1)任何数据交换总是发生在一定的上下文(Context)中,比如一个特定的协议接口等等。一个结构化数据描述总是针对这样的一个上下文的,一个上下文描述可以由一个或多个BXML结构描述文件组成。BXML编译器的一次运行也总是针对一个上下文的,它需要同时读入该上下文的所有描述文件。
2)每个BXML结构描述文件在文件开头必须使用“page”关键字指定该文件的codepage空间,它对该文件内描述的所有结构有效。在一个上下文中,codepage必须是唯一的。
3)每个BXML结构描述文件应在page关键字之后指明生成程序源代码时所需要的JAVA包名或C++命名空间,他们对该文件中的所有描述有效。对一个上下文中的不同的描述文件,可以指定相同或不同的JAVA包名或C++命名空间。
4)在一个BXML结构描述文件中可以直接使用同一上下文的任何一个BXML描述文件中定义的数据类型,但是同一上下文的任何数据类型不能重名。
5)用关键字定义的数据类型,包括:
整数:关键字为int
字符串:关键字为string
不透明二进制字节序列:关键字为binary
枚举:关键字为enum
联合:关键字为union
结构:关键字为struct
不定结构:关键字为ANY
数组:关键字为arrayof
6)在一个BXML结构描述文件中的结构定义顺序是重要的,它影响BXML编译器分配的TAG值。数据交换双方必须使用相同的BXML结构描述文件。
7)一个结构或联合内部的成员定义顺序也是重要的,它影响BXML编译器分配的内部标签值。数据交换双方必须使用相同的BXML结构描述文件。
为了开发人员书写方便,本发明采用类似C语言头文件的方式描述结构化数据,下面的例子说明了描述文件的格式。其中,下划线部分为关键字,所有关键字均被展示。
//file test.bxml,only for test,no actual meaning
page=0;
package com.test;//for java
namespace com::test;//for c++
enum SessionType{
inband=1;
outband=2;
}
union SessionAddress{
string url;
int ipAddress;
}
struct SessionDescriptor{
_SessionType type;
SessionAddress address;
stringsessionID;
}
struct UserInfo{
string userID;
int age;
binary key;
}
arrayofUserInfoUserInfoList;
arrayofint IntegerList;
arrayofstring StringList;
arrayofbinary BinaryList;
struct LoginReq{
string deviceID;
UserInfoList userList;
BinaryList blist;
StringList slist;
IntegerList ilist;
}
struct LoginRes{}
structMessage{
SessionDescriptor desc;
ANY msgBody;
int time;
ANY addition;
}
//end of the test.xml
代码生成的一般规则
事实上,从BXML结构描述文件向某种计算机编程语言的映射方法应该不会是唯一的,本发明首先描述一般的规则;随后,简要描述向C++和JAVA语言的典型映射。
1)任何数据交换总是发生在一定的上下文(Context)中,比如一个特定的协议接口等等。一个结构化数据描述总是针对这样的一个上下文的,一个上下文描述可以由一个或多个BXML结构描述文件组成。BXML编译器的一次运行也总是针对一个上下文的,它需要同时读入该上下文的所有描述文件。为方便起见,通常应将一个上下文的所有BXML结构描述文件放置在同一个根目录下。
2)一个应用程序可以同时拥有不同的上下文,比如,它可能同时拥有多个不同类型的通讯接口,与不同的实体交换数据。这样,需要使用BXML编译器分别对各个上下文进行编译,尽管不同上下文的结构标签值会冲突,但他们应使用在不同的通讯接口(地址)中,这种标签值的重复不会有任何问题。但是不同上下文中可能有数据类型名冲突的情况,这种情况应使用不同的JAVA包名或C++命名空间来解决。
3)在一次上下文编译中,BXML编译器针对每个描述文件分别从0X05开始依次为每个结构分配结构TAG。如果结构太多,可以分布到不同的文件(codepage)中。一个上下文的应用结构最大数为:
256co depages*(128tags-5predefined)=31488
对绝大多数应用来说已经足够了。
4)BXML编译器分别为每一个结构或联合的成员依次从0X05开始分配内部标签,一个结构或联合的内部标签的最大数为:
128tags-5predefined=123
对绝大多数结构或联合来说也足够了。
下面通过具体示例分别描述向C++和JAVA语言的典型映射。
向C++语言的典型映射
枚举的映射:
联合的映射:
结构的映射:
数组的映射:
整型的映射:
一个整型被映射成C++的DWORD类型,在BXML运行库中有一个BXMLInt类用来支持对它进行编解码和可打印字符串的输出功能。
字符串的映射:
一个字符串被映射成C++的STL string类型,在BXML运行库中有一个BXMLString类用来支持对它进行编解码和可打印字符串的输出功能。
二进制字节序列的映射:
一个二进制字节序列被映射成C++的STL vecotor<BYTE>类型,在BXML运行库中有一个BXMLBinary类用来支持对它进行编解码和可打印字符串的输出功能。
不定结构的映射:
不定结构被映射成BXML运行库中的ANY类,它也是所有结构映射成C++类的基类。ANY类的定义摘要如下:
class ANY
{
public:
static ANY*parseANY(uBYTEid,BXMLBuffer & buffer,BXMLParser & p);
virtual~ANY(){};
virtual ANY*duplicate()=0;
virtual uBYTE getCodepage()=0;
virtual uBYTE getTag()=0;
virtual ANY*parse(uBYTE id,BXMLBuffer & buffer,BXMLParser & p)=0;
virtual void write(BXMLBuffer & buffer,BXMLWriter & w,bool withtag)=0;
virtual string toString(int level,bool withtag)=0;
};
另外,BXML运行库中还有两个重要的类:BXMLWriter和BXMLParser,用来支持对顶层BXML数据进行编解码。
向JAVA语言的映射
枚举的映射:
联合的映射:
结构的映射:
数组的映射:
整型的映射:
一个整型被映射成JAVA的Integer类型,在BXML运行库中有一个BXMLInt类用来支持对它进行编解码和可打印字符串的输出功能。
字符串的映射:
一个字符串被映射成JAVA的String类型,在BXML运行库中有一个BXMLString类用来支持对它进行编解码和可打印字符串的输出功能。
二进制字节序列的映射:
一个二进制字节序列被映射成JAVA的byte[]类型,在BXML运行库中有一个BXMLBinary类用来支持对它进行编解码和可打印字符串的输出功能。
不定结构的映射:
不定结构被映射成BXML运行库中的ANY类,它也是所有结构映射成JAVA类的基类。ANY类的定义摘要如下:
public abstract class ANY
{
public static ANY parseANY(int id,InputStream in,BXMLParser p);
public abstract ANY parse(int id,InputStream in,BXMLParser p);
public abstract void write(OutputStream out,BXMLWriter w,boolean withtag);
public abstract int getCodepage();
public abstract int getTag();
public abstract String toString(int level,boolean withtag);
}
另外,BXML运行库中还有两个重要的类:BXMLWriter和BXMLParser,用来支持对顶层BXML数据进行编解码。
一个应用程序运行示例
用前面示例过的BXML结构描述文件,然后用BXML编译器生成的源代码开发了一个应用程序,该程序以描述文件中定义的Message结构作为顶层结构构造了一个结构化数据,再用该结构的自打印功能输出数据内容,并用编码函数进行BXML编码。
Message结构的自打印输出:
Message
desc
type
outband
address
url
sip:joe.li@utstar.com
sessionID
abcd
msgBody
LoginReq
deviceID
UTStarcomABC
userList
UserInfo
userID
Joe.li
age
29
key
0c 16 00 17
UserInfo
userID
Mike
age
25
key
38 23 0c 43 45
blist
4e c8
15 19 06
slist
string1
string2
ilist
30
800
time
540394
addition
LoginRes
经编码函数进行编码以后的数据总长度为138个字节,其内容用16进制表示如下:
01 00 87 6a 89 85 85 02 86 85 73 69 70 3a 6a 6f 65 2e 6c 69 40 75 74 73 74 61 72 2e 63 6f 6d 00 87 6162 63 64 00 01 86 87 85 55 54 53 74 61 72 63 6f 6d 41 42 43 00 86 86 85 4a 6f 65 2e 6c 69 00 86 1d 87 040c 16 00 17 01 86 85 4d 69 6b 65 00 86 19 87 05 38 23 0c 43 45 01 01 87 82 02 4e c8 82 03 15 19 06 01 8882 73 74 72 69 6e 67 31 00 82 73 74 72 69 6e 67 32 00 01 89 82 1e 82 86 20 01 01 87 a0 fd 6a 88 08 01
对上述BXML编码的解释如下表所示:
综上所述,本发明对WBXML的改进主要包括:
将WBXML的元素与计算机语言的结构数据类型相对应,所有的元素标签代表相应的结构类型编码;
增加内部标签(Internal tag)的概念,内部标签在一个结构内解释,代表一个相应的结构成员,内部标签根据运行时需要可携带标签内容(即成员值),也可不携带内容(即无值出现),或者不出现(即成员缺席);
内部标签所携带的内容不再需要任何其他tag标记,因为类型是预知的,除非是成员类型为不定结构(ANY)的情况;
内部标签所携带的内容直接按照所对应的成员类型进行编码,如整型按多字节整数进行编码,不象WBXML仍然采用字符串编码;
增加一个预定义的全局标记——ARRAY_ITEM,用于分隔数组元素;
不考虑专门支持WBXML的属性(Attribute),但是可以通过增加结构成员来表达属性;
不考虑专门支持WBXML中的字符串常量,但是可以通过枚举类型来表达;
虽然已经参考附图对本发明的方法以举例方式进行了描述,但是本发明不限于上述这些细节,并且本申请含盖权利要求范围之内的各种变型或改变。