北京理工大学 20981 陈罡
expat xml解析库是一个非常强大的xml解析库,有了它的支持可以将很多参数设置或者内容编排、组织都集成到程序中去。5mbox的杂志内容解析、显示的基础 就是expat解析库。目前,我已经让这个库可以在s60 2nd, 3rd以及moto mobilinux上面顺利运行了,还差win mobile平台和uiq平台,就基本上都有了。
这次借助开发win mobile5的东风,既frame buffer库、jpeg/png/gif库之后,就把expat库给移植上去。在我的概念里面,写得好的c、c++代码要比java的代码可移植性更高!
简单的看了一下,expat 2.0主要有用的文件有5个,它们分别是:
xmlparse.c : 定义了dtd的支持和外部XML_Parser的函数
xmlrole.c : 定义了关键字和内容列表什么的
xmltok.c : 这个就是解析部分的包装了,呵呵,难得作者用c语言实现了所谓的"vtable"虚拟函数表
xmltok_impl.c : 这个是对普通xmltag的解析的实现
xmltok_ns.c : 这个是对名字空间的解析的实现
第一步,需要把原有的.c改为.cpp文件,然后在.h中,把必要的声明部分都加入:
#ifdef __cplusplus
extern "C" {
#endif
....声明部分代码
#ifdef __cplusplus
}
#endif
然后就是编译,会发现有一些地方会出现类型不对的问题,这主要是expat的作者用enum来表示这些变量了(而不是用defene),而c++的编译器对类型检查非常严格,因此会出这些问题。强制类型转换一下,然后
再一些没有初始化的变量上把初始值加上。这样就没有警告了。
第二步,发现一些奇特的错误如下所示:
/expat/xmltok_impl.c(90) : error C2061: syntax error : identifier 'scanComment'
/expat/xmltok_impl.c(90) : error C2059: syntax error : ';'
/xmltok_impl.c(90) : error C2059: syntax error : 'type'
/expat/xmltok_impl.c(128) : error C2061: syntax error : identifier 'scanDecl'
/expat/xmltok_impl.c(128) : error C2059: syntax error : ';'
/expat/xmltok_impl.c(128) : error C2059: syntax error : 'type'
/expat/xmltok_impl.c(175) : error C2061: syntax error : identifier 'checkPiTarget'
/expat/xmltok_impl.c(175) : error C2059: syntax error : ';'
/expat/xmltok_impl.c(175) : error C2059: syntax error : 'type'
/expat/xmltok_impl.c(220) : error C2061: syntax error : identifier 'scanPi'
/expat/xmltok_impl.c(220) : error C2059: syntax error : ';'
/expat/xmltok_impl.c(220) : error C2059: syntax error : 'type'
/expat/xmltok_impl.c(282) : error C2061: syntax error : identifier 'scanCdataSection'
/expat/xmltok_impl.c(282) : error C2059: syntax error : ';'
/expat/xmltok_impl.c(282) : error C2059: syntax error : 'type'
等等,类似这样的错误。
这个错误是如何引起的呢?
仔细看xmltok.c文件,就会发现它有#include "xmltok_impl.c",这是什么意思呢?
原来,作者是靠#include把xmltok_impl.c里面的函数“集成”到xmltok.c中使用。
从vs2005的输出看来,似乎不支持这种在一个.cpp文件中#include另外一个.cpp文件的方法。
通过源代码浏览可以看出,作者用xmltok.c这个文件include了xmltok_impl.c和xmltok_ns.c才会
出现上述的定义问题。
解决的方法是,注释掉这个#include "xmltok_impl.c"以及#include "xmltok_ns.c",然后把这两个
.c文件的内容直接复制到xmltok.c里面#include这两个.c的相应位置。重新编译就可以通过了。
expat库的基本使用方法如下:
#include <stdio.h>
#include "xmlparse.h" // 这是v1.0版的expat的头文件
#include "expat.h" // 这是v2.0版的expat的头文件
//tag中的字符处理函数
void CharacterDataHandler(void *userData, const XML_Char *s, int len)
{
char* str = (char*)malloc (len + 1);
strncpy (str, s, len);
puts (str);
}
// tag的开头处理函数
void startElement(void *userData, const char *name, const char **atts)
{
int i;
int *depthPtr = userData;
for (i = 0; i < *depthPtr; i++)
putchar('/t');
//puts(name);
printf ("XML: <%s", name);
i = 0;
while (atts[i] && *atts[i] && atts[i][0] != 0)
{
if (i % 2)
{
printf ("=");
printf ("/"%s/"", atts[i]);
}
else
{
printf (" ");
printf ("%s", atts[i]);
}
i++;
}
printf (">/n");
*depthPtr += 1;
}
// tag的结束处理函数
void endElement(void *userData, const char *name)
{
int *depthPtr = userData;
*depthPtr -= 1;
}
int main()
{
char buf[BUFSIZ];
// 创建XML_Parser对象
XML_Parser parser = XML_ParserCreate(NULL);
int done;
int depth = 0;
// 设置自定义数据
XML_SetUserData(parser, &depth);
// 设置tag的处理函数
XML_SetElementHandler(parser, startElement, endElement);
// 设置tag中包含的字符处理函数
// 例如:<tag>这部分字符</tag>
XML_SetCharacterDataHandler(parser, CharacterDataHandler);
// 这个循环就是多次load文件中的xml数据,然后处理
do {
size_t len = fread(buf, 1, sizeof(buf), stdin);
done = len < sizeof(buf);
if (!XML_Parse(parser, buf, len, done)) {
fprintf(stderr,
"%s at line %d/n",
XML_ErrorString(XML_GetErrorCode(parser)),
XML_GetCurrentLineNumber(parser));
return 1;
}
} while (!done);
// 最后不要忘记释放这个xml解析器的对象
XML_ParserFree(parser);
return 0;
}
为了后来人能够不必象我一样在往嵌入式系统中修改和移植expat遇到这么多麻烦的问题,加之expat本身
就是开源的软件。我打算开放这个expat v2.0 for win mobile 5的源代码。
希望能够对各位有用!
|
文件: |
expat_wm5_port.rar |
大小: |
69KB |
下载: |
下载 |
|
注意,这个移植不是生成dll或者lib的,而是直接可以加入到工程中的代码。使用方法是在win mobile中添加新的目录,然后把整个expat目录中的文件都添加进去,然后在使用的地方加入#include "expat.h"。然后在vs2005中添加相关的include目录,就可以在vs2005中编译和运行了。
祝大家好运!
|
网友: igogo |
时间:2008-01-08 11:37:58 IP地址:124.193.156.★ |
|
|
|
我想在MTK平台下用expat,发现如果定义static void XMLCALL startElement(void *userData, const char *name, const char **atts),在 XML_SetElementHandler(parser, startElement, endElement);就会死机,如果用static void XMLCALL startElement(void *UserData, const char *Name, const char **Atts),则可以正确设置,开机,但是无法执行到那个函数内。能帮忙想想可能是什么问题吗 |
|
|
|
网友: chenwayne |
时间:2008-01-08 12:55:10 IP地址:125.34.128.★ |
|
|
|
你可以考虑看看我的for win mobile 5的port试试,应该是可以的,检查一下是不是有指针越界或者死循环的问题。 |
|
|
|
网友: pirate_wb |
时间:2008-03-04 16:06:30 IP地址:222.66.57.★ |
|
|
|
你好陈罡,我现在在做s60 3rd的一个应用,但是目前expat无法在上面使用,你说在3rd上实现了,如果不介意的话能否共享一下你在3rd上的实现。
[email protected] |
|
|
|
网友: pirate_wb |
时间:2008-03-05 21:46:59 IP地址:124.79.87.★ |
|
|
|
陈罡人不错,呵呵,今天就把代码给我发过来了。
很遗憾的是你给我的版本跟之前我用的一个一样,虽然成功编译出dll,但是在应用中只要调用任何一个导出函数就会进不了应用,报epoc.exe异常,郁闷。。。 |
|
|
|
网友: chenwayne |
时间:2008-03-05 22:54:32 IP地址:125.34.130.★ |
|
|
|
那个syexpat2是没有问题的,检查你的调用代码以及包含的lib文件。
这个dll我已经在3rd上用到项目中去了,没问题。 |
|