郝 伟
XML(Extensible Markup Language)即可扩展标记语言,它与HTML一样,都是SGML(Standard Generalized Markup Language,标准通用标记语言),即使用标记对内容进行区分。由于Xml是Internet环境中跨平台的,依赖于内容的技术,是当前处理结构化文档信息的有力工具[1]。
由于XML使用了大量的标记符,所以使用XML会占用更多的空间,但由于XML极其简单易于掌握和使用,加上现在硬件技术和软件水平的不断发挥,所以XML已经广泛应用于数据库技术和网络传输中[2]。
图形和图片在Internet中,是最常见到的文件格式,图片都是使用二进制进行存储,所以如果在基于文本的XML文件中传输的话,就很可能是破坏XML的内容。如,在二进制数据中,如果正好包含 “<>”这样的标记,原XML文件的内容就很可能会被破坏,接收端就无法正确的解析XML数据,从而造成数据传输的失败,所以一般图片都是与文本分开传输的。然而数据分开传输虽然能解决问题,但是传输的统一性就会被破坏,而且存储也需要在不同的空间完成,对于一些有一定安全性要求的场合就会不太适用。
笔者在之前的文章中已经提出了一种算法《一种基于XML的图像存储方法》,已经初步解决了这个问题,但是所使用的方法没有充分考虑效率,平均每一个码元会增加大量的冗余数据,所以当前的问题是进一步提高转换效率,从而适应提高传输效率。
现在各类压缩和加密算法很多,但是全都是基于二进制的,即都是取字节0-255的所有段来进行的,这些段时,除了包括数字,大小写字母,标点符号这些可见元素,还包括一些非可见的控件符,如回车,退格,表格等,同时还有一定几率包括一些XML的关键字和XML标记的左右括号等,所以使用XML进行传输可能会出现一定的问题。因此现有的加密算法不能解决这个问题[3]。
解决这个问题最关键的就是将图片中的所有二进制转换为可识别的二进制,即可以使用ASCII正常表示的,可以选用的包括大小写字母和数字。
在《一种基于XML的图像存储方法》一文中,所提出的方法是使用的是2个字节表示一个二进制码的办法,从而使一个字节变成了2个字符的表示方式,而在长度上,其容量增加了一倍。如果在大量的数据传输,那么增加的一倍会降低传输效率,同时也会导致数据传输时间的加长[4]。
因此,本方提出了一种新方法,减少转换后的数据量,从而增加传输效率。由于二进制中可显示的码元有限,常见的只有48-59,65-90,97-122这62的可用码元。要表示一个字节的二进制完全是不够的。
由于3个可见码元空间是62*62*62 = 238328>65536=256*256,所以可以采取用3个可见码元表示2个二进制数据的方法,从而减少了冗余数据量。
另外,由于52个码元的效果和62的码元的效果在减少码元长度上并没有区别,因为3个52进制编码所表示的范围是:52*52*52=140608>65536,即三个52进制的码元是可以完全包括4位16进制编码三元的,所以从简化的角度出发,只使用大小写字母的52个码元,不再使用数数字。当然,如果仍然使用数据除了计算上略有影响,与只使用字母没有任何区别。
将图片文件中的数据的每个字节转换成可识别的ASCII码,本方法将2字节二进制数据转换为3的52进制编码,计算方法如下:
1)设2字节的二进制编码为B1 B2,那么可以计算出其对应的十进制编码
D10 =B1*256+B2。 (D表示10进制编码,B1表示原码高位,B2表示原码低位)
2)将十进制转换为52进制,转换方法采取余的方式,转换后会有三位52进制码,转换公式如下:
bl = D10 % 52(bl表示低位)
bm = (D10 / 52) % 52 (bm表示中间位)
bh = (D10 / 52) / 52(bh表示高位)
3)将52进制转换为对应的大小写字母,转换方法如下:
C = C + 65 C∈[0, 25]
C + 97 - 26 C∈[26, 51]
4)将交换好的值,用对应的ASCII码表示。
即0-65535对应三位的大小写字母,如00 00对应AAA,FF FF 对应XLO。根据以上原理编,下面笔者使用程序语言进行编程,以对设计结果进行验证(以下代码均以C#代码为例)。
二进制的数据是以字节数据的进行读取过来,然后传递到程序中进行数据处理,所使用的数据转换程序如下所示。
//用于编码的函数
public string Encode(byte[] bts)
{
//建立变长数组,用于保存数据
StringBuilder builder = new StringBuilder();
int len = bts.Length / 2;
for (int i = 0; i < len; i++)
{
int t = bts[i] * 256 + bts[i + 1];
int v0 = t % 52;
t = t / 52;
int v1 = t % 52;
t = t / 52;
int v2 = t;
builder.Append(Transfer(v0));
builder.Append(Transfer(v1));
builder.Append(Transfer(v2));
}
return builder.ToString();
}
private string Transfer(int v)
{
v = v < 26 ? v + 65 : v + 97 - 26;
return ((char)v).ToString();
}
转换时先转换成52进制的编码,然后再根据0-25转换成A-Z,26-51转换成a-z的规则,将所有转换好的数值转换成字母。
加密后的数据以字符串的形式存在,读取后传递到程序中进行数据处理,所使用的数据转换程序如下所示。
//用于解码的函数。
public byte[] Decode(string s)
{
//建立用于保存二进制数据的数组。
byte[] bts = new byte[s.Length % 3];
int length = s.Length / 3;
//循环控制,
for (int i = 0; i < length; i++)
{
int t = Transfer1(s[i]) +
Transfer1(s[i + 1]) * 52 +
Transfer1(s[i + 2]) * 52 * 52;
bts[i] = (byte)(t / 256);
bts[i + 1] = (byte)(t % 256);
}
return bts;
}
private int Transfer1(char c)
{
int v = (int)c;
return v > 90 ? v - 97 + 32 : v - 65;
}
三位字符对应的值为A-Z对应0-25,a-z对应26-51,转换好以的三位a1,a2,a3再按照以下公式进行计算,从而还原原来的值。
计算公式为原先公式的逆运行,分为以下几步:
1)将大小写字母转换成52进制的数据。
2)将52进制的数据转换为10进制,公式为
b = a3*52*52 + a2 * 52 + a1,其中b为原值。
3)将10进制转换为二进制
从原始的二进制的数据里可以看到,原始数据中里包含着如“<”, “>”等大量这样的非字符码元,这些非法码元的存在有着很大的安全隐患,很可能会导致整个XML数据模块的解析失败,从而使原有XML文件的相关数据被二进制编码所破坏。
现在采取将《一种基于XML的图像存储方法》一文中的方法将其转换后,以小写字母和数字的形式出现,重新编码后的XML文件如下所示。这样经过编码以后,再使用XML就不会出现任何问题,但是长度比较度,为原来长度的2倍。于是采取本方中的新的编码方式,结果如下所示。
经过编码以后,XML的传输就不会出现任何问题,但是长度比较度,为原来长度的2倍。在采取本方中的新的编码方式,结果如下所示。
采用新的编码以后,码元的长度大大减少,达到了预期的目的。
本方提出了一种方法,将二进制的图片转换为可识别的字符串的,从而实现了在XML中传输图片。同时采用新的算法,较《一种基于XML的图像存储方法》一文中的方法大幅提高了算法的效率,兼顾了效率,减少了存储的容量,提高了传输效率。
[参 考 文 献]
[1] 郝 伟.一种基于XML的图像存储方法[J].电脑技术与应用, 2011(5).
[2] Steve Holzner. Inside XML[M].WROX PR,2000.
[3] Andrew Troelsen. Advcenced C# & .NET Program Design 4.0[M].北京:人民邮电出版社,2010.
[4] 李家同.算法设计与分析导论[M].北京:机械工业出版社,2008.
[5] 吕国英.算法设计与分析(第2版)[M]. 北京:清华大学出版社,2009.