高通在BREW平台中并没有为我们提供一个可以方便使用的API来实现XML文件的解析,在很多情况下,我们需要操作一个XML文件。就这事我曾电话咨询过博路的工程师,他给出的答复是可以购买一个商业组件来实现这个功能。事实上,没必要如此复杂,我们完全可以利用互联网上的免费的开源代码来实现这个功能。
本文要介绍的开源代码就是:Martyn C Brown为我们提供的一个完全基于ANSI C实现的MCBXml。
这是一个很纯的标准C实现,所以,要移植到BREW上是比较容易的。
第一步:我们直接把它揣进一个BREW工程中,编译一下,就会发现很多的编译错误出来了。(这一步的目的就是要看看它都有哪些东西不符合BREW的要求,这正是我们需要修改的地方)。
第二步:现在可以修改代码了,简单地利用#define将它使用的一些函数替换成BREW可以接受的形式。当然在这之前先移掉几个头引用,加入BREW的引用。对于头文件的修改就这么简单而已。而对于MCBXml.c的修改其它除了用#define来替换以外,还有一种方法就是“查找替换”法,呵呵,比如free换成FREE,malloc换成MALLOC之类的。
#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()函数的修改如下:
... {
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)的实现中,最后还要注意释放掉上面弄出来的字串:
int i;
for(i=0;i<6;i++)
...{
FREEIF(xml.pClrTags[i].lpszOpen);
FREEIF(xml.pClrTags[i].lpszClose);
}
FREEIF(xml.pClrTags);
}
return pElement;
要想编译通过,还有一个地方要注意的,所有的assert也掉处理掉。经过上述处理,现在这两个文件MCBXml.h/MCBXml.c已经可以嵌入我们的BREW工程中编译成功了。
不过,因为它缺省使用的属性值是不带双引号的,所以还需要做一点修改方便使用:
... {
//以下是新的逻辑 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结构定义如下:
... {
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树的内容,也有相应的函数,具体可以参看头文件中的函数定义。我就不罗嗦了。有问题可以与我联系。