高通在BREW平台中并没有为我们提供一个可以方便使用的API来实现XML文件的解析,在很多情况下,我们需要操作一个XML文件。就这事我曾电话咨询过博路的工程师,他给出的答复是可以购买一个商业组件来实现这个功能。事实上,没必要如此复杂,我们完全可以利用互联网上的免费的开源代码来实现这个功能。
本文要介绍的开源代码就是:Martyn C Brown为我们提供的一个完全基于ANSI C实现的MCBXml。 这是一个很纯的标准C实现,所以,要移植到BREW上是比较容易的。
第一步:我们直接把它揣进一个BREW工程中,编译一下,就会发现很多的编译错误出来了。(这一步的目的就是要看看它都有哪些东西不符合BREW的要求,这正是我们需要修改的地方)。
第二步:现在可以修改代码了,简单地利用#define将它使用的一些函数替换成BREW可以接受的形式。当然在这之前先移掉几个头引用,加入BREW的引用。对于头文件的修改就这么简单而已。而对于MCBXml.c的修改其它除了用#define来替换以外,还有一种方法就是“查找替换”法,呵呵,比如free换成FREE,malloc换成MALLOC之类的。
#include "AEEStdLib.h"
#define _T(name) (name) #define _tcscpy(a,b) STRCPY(a,b) #define _tcsstr(a,b) STRSTR(a,b) #define _tcschr(a,b) STRCHR(a,b) #define _tcslen(a) STRLEN(a) #define _tcsnicmp(a,b,c) STRNICMP(a,b,c)
在MCBXml.c中,还有一个操作,我将函数McbGetError整个给注掉了(就是为了省事,如果你还要保留这个函数,额外做些工作就可以了)。
还有一个McbClearTags()函数的修改如下:
McbClearTag
*
McbGetClearTags()
...
{ struct McbClearTag * tags = (McbClearTag * )MALLOC(sizeof(McbClearTag) * 6 ); // struct McbClearTag tags[] = // { // { _T("<![CDATA["), _T("]]>") }, // { _T("<PRE>"), _T("</PRE>") }, // { _T("<Script>"), _T("</Script>") }, // { _T("<!--"), _T("-->") }, // { _T("<!DOCTYPE"), _T(">") }, // { NULL, NULL } // }; MEMSET(tags,0 ,sizeof(McbClearTag) * 6 ); tags[ 0 ].lpszOpen = STRDUP( " <![CDATA[ " ); tags[ 0 ].lpszClose = STRDUP( " ]]> " ); tags[ 1 ].lpszOpen = STRDUP( " <PRE> " ); tags[ 1 ].lpszClose = STRDUP( " </PRE> " ); tags[ 2 ].lpszOpen = STRDUP( " <!-- " ); tags[ 2 ].lpszClose = STRDUP( " --> " ); tags[ 3 ].lpszOpen = STRDUP( " <!DOCTYPE " ); tags[ 3 ].lpszClose = STRDUP( " > " ); tags[ 4 ].lpszOpen = STRDUP( " <Script " ); tags[ 4 ].lpszClose = STRDUP( " </Script> " ); tags[ 5 ].lpszOpen = NULL; tags[ 5 ].lpszClose = NULL; return tags; }
/**/
/* McbGetClearTags */
在函数McbXMLElement * McbParseXML(LPCTSTR lpszXML, McbXMLResults *pResults)的实现中,最后还要注意释放掉上面弄出来的字串:
要想编译通过,还有一个地方要注意的,所有的assert也掉处理掉。经过上述处理,现在这两个文件MCBXml.h/MCBXml.c已经可以嵌入我们的BREW工程中编译成功了。
不过,因为它缺省使用的属性值是不带双引号的,所以还需要做一点修改方便使用:
LPTSTR McbStrdup(LPCTSTR lpszData,
int
cbData)
...
{ // 以下是新的逻辑 by YanCheng(2007-12-14) // 去掉引号 LPTSTR lpszNew; if ( cbData == 0 ) cbData = _tcslen(lpszData); if ( (lpszData[ 0 ] == ' " ' && lpszData[cbData - 1 ] == ' " ' ) || (lpszData[ 0 ] == ' ' ' && lpszData[cbData - 1 ] == ' ' ' ) ) ... { cbData -= 2 ; lpszNew = MALLOC((cbData + 1 ) * sizeof (TCHAR)); if (lpszNew) ... { MEMCPY(lpszNew,lpszData + 1 ,(cbData) * sizeof (TCHAR)); lpszNew[cbData] = (TCHAR)NULL; } } else ... { lpszNew = MALLOC((cbData + 1 ) * sizeof (TCHAR)); if (lpszNew) ... { MEMCPY(lpszNew, lpszData, (cbData) * sizeof (TCHAR)); lpszNew[cbData] = (TCHAR)NULL; } } return lpszNew; }
/**/
/* McbStrdup */
同样,在构造XML字串时,要将这个引号恢复出来,即:
/**/
/* ***************************************************** * "Attrib=Value " ***************************************************** */
cb
=
McbLENSTR(pAttr
->
lpszValue);
if
(cb)
...
{ // modify by yancheng if ( lpszMarker ) ... { lpszMarker[nResult] = _T( ' = ' ); lpszMarker[nResult + 1 ] = _T( ' " ' ); _tcscpy( & lpszMarker[nResult + 2 ],pAttr -> lpszValue); lpszMarker[nResult + 1 + cb + 1 ] = _T( ' " ' ); } nResult += cb + 1 + 2 ; }
if
(lpszMarker)
...
{ lpszMarker[nResult] = _T( ' ' ); }
nResult
++
; } }
break
;
我已经将修改后的这两个文件打包放在我的资源中了,可以直接下载使用:http://download.csdn.net/source/313498
最后,简要介绍一下它的使用方法,可参看MCBXml.h中的函数定义,其实是很方便的。
如何解析XML文件,只需要简单地调用McbParseXML完成解析操作,传入的第一个参数是一个XML的字串,返回值是一个McbXMLElement结构类型的变量,McbXMLElement结构定义如下:
typedef
struct
McbXMLElement
...
{ LPTSTR lpszName; // 元素名称 int nSize; // 子节点的个数 int nMax; // 最大分配的节点个数 int nIsDeclaration; // 是否子节点是XML格式 struct McbXMLNode * pEntries; // 子节点数组 struct McbXMLElement * pParent; // 父节点 }
McbXMLElement;
由此看出,通过它就可以访问到整个XML的DOM树上的任何一个节点数据了。例如这样:
//
加载背景图
for
(i
=
0
;i
<
pXNode
->
node.pElement
->
nSize;i
++
)
...
{ if (pXNode -> node.pElement -> pEntries[i].type == eNodeAttribute && STRICMP( " background " ,pXNode -> node.pElement -> pEntries[i].node.pAttrib -> lpszName) == 0 ) ... { pMe -> m_pImageBk = ISHELL_LoadImage(pMe -> m_pIShell,pXNode -> node.pElement -> pEntries[i].node.pAttrib -> lpszValue); if (pMe -> m_pImageBk) pMe -> m_isOwnBk = TRUE; break ; } }
这里的pXNode是一个McbXMLNode结构类型的指针变量。
至于如何创建或修改DOM树的内容,也有相应的函数,具体可以参看头文件中的函数定义。我就不罗嗦了。有问题可以与我联系。