关于xml,多说无益,的确是一个好东西。它是一种可扩展的置标语言,关于xml和sgml以及html的区别和联系,相关的书籍太多了,我在这里也没啥资格废话。想说说自己在wince下做xml parser的一点想法。
wince 5.0目前支持到微软的msxml 3.0(据说pc上有7.0的版本,我的电脑上只有6.0)。关于各个版本的区别差异,也不是一句话两句话的问题。只谈谈xml解析方法。
xml解析有两个接口,DOM和SAX,DOM(Document Object Model),SAX(Simple Application interface for XML)。前者是最基本应用编程接口,后者提供了比较底层的接口,编程比较灵活。初学咋练,只研究DOM。据说DOM接口使用了COM的技术,是把一个xml文档,解释成一棵节点树。然后对这个树进行访问来处理节点上的信息,如属性和元素等等。
为了解析一个xml文档,首先要创建一个document对象,也就是一个IXMLDOMDocument接口的实例。首先,为了使用COM对象,需要使用CoInitialize函数来初始化COM环境。需要注意的事,wince下,并不支持CoInitialize,而是CoInitializeEx,这个函数提供了一个额外的参数让用户选择多线程模式还是单线程模式。关于这两者的区别,目前我说不清楚,不过不是简单的字面的解释,编程中会有一点小问题。这里我选择了多线程模式。
CoInitializeEx(NULL,COINIT_MULTITHREADED)
建立document对象,使用CoCreateInstance函数,参数使用网上经典的几个参数,第一个是CLSID值,CLSID_DOMDocument,包含在objsafe.h中。接口类型选择IID_IXMLDOMDocument。关于这个函数的使用,往上有很多不同版本的文章,有的是用名字空间什么的,我这里没有用。
CoCreateInstance(CLSID_DOMDocument,NULL,CLSCTX_INPROC_SERVER,IID_IXMLDOMDocument,(void**)&pDoc)
建立了实例以后,调用这个接口的一个方法,load,(loadxml方法也可以加载一个xml文件,但是loadxml也可以加载文件的一个部分,更灵活一点),第一个参数是VARIANT,第二个参数是VARIANT_BOOL。这两个参数曾经弄得我很头痛,后者其实就是一个short,前者是一个无类型的变量,可以用任何类型赋值,究其根本,就是一个结构体,里面用union做的多种类型。在msdn中可以找到。想要说明的是,如果VARIANT表示一个字符串,字符串的类型是BSTR。网上有很多文章介绍到这里关于字符串的处理,有的用到MFC的CString,有的用到了ATL的CComVariant,为了不用这些乱七八糟的东西(主要是重新配置wince image来支持这些东西有点麻烦,一个DocList的DLL找不到,如果有人可以告诉这个dll怎么搞定,不圣感谢),我用了下面的比较简单的方法。
VARIANT vFile ;
vFile.vt = VT_BSTR ;
vFile.bstrVal = SysAllocString(L"\\release\\a.xml");
VARIANT_BOOL vBool;
pDoc->load(vFile,&vBool);
这样,就得到了这个XML文件的根节点,接下来处理节点信息就简单了。
除了IXMLDOMDocument接口,比较常用的还有IXMLDOMNodeList,IXMLDOMNode,IXMLDOMElement这几个接口,今天不想写太多关于这些接口的方法和属性了,列出一个简单的小程序,里面用一个小堆栈,实现了对XML树结点的遍历。
#include "stdafx.h"
#include "objsafe.h"
#include "Msxml2.h"
#include "Objbase.h"
#include "comutil.h"
typedef struct _node{
IXMLDOMNode *Node;
int level;
}nodes;
nodes NodeStack[100];
int top=0;
void pushStack(nodes node)
{
NodeStack[top].Node = node.Node;
NodeStack[top].level = node.level;
top++;
}
void popStack(nodes * node)
{
top–;
(*node).Node = NodeStack[top].Node;
(*node).level = NodeStack[top].level;
}
int isStackEmpty()
{
if(top==0) return 1;
else return 0;
}
int WINAPI WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
IXMLDOMDocument *pDoc = NULL;
IXMLDOMNodeList *pNodelist = NULL;
IXMLDOMNode *pNode = NULL;
IXMLDOMElement *pRootElement = NULL;
nodes curNode;
if(SUCCEEDED(CoInitializeEx(NULL,COINIT_MULTITHREADED)))
{
if(SUCCEEDED(CoCreateInstance(CLSID_DOMDocument,NULL,CLSCTX_INPROC_SERVER,IID_IXMLDOMDocument,(void**)&pDoc)))
{
VARIANT vFile ;
vFile.vt = VT_BSTR ;
vFile.bstrVal = SysAllocString(L"\\release\\a.xml");
VARIANT_BOOL vBool;
pDoc->load(vFile,&vBool);
if(vBool != VARIANT_TRUE)
{
printf("not load");
return 1;
}
else printf("load");
/
HRESULT hr;
hr = pDoc->get_documentElement(&pRootElement);
if(SUCCEEDED(hr))
{
hr = pRootElement->QueryInterface(IID_IXMLDOMNode,(void**)&pNode);
if(SUCCEEDED(hr))
{
BSTR bsxml;
curNode.Node = pNode;
curNode.level = 1;
pushStack(curNode);
int curLevel;
while(1)
{
if(isStackEmpty()) break;
popStack(&curNode);
pNode = curNode.Node;
curLevel = curNode.level;
pNode->hasChildNodes(&vBool);
if(vBool == VARIANT_TRUE)
{
hr = pNode->get_nodeName(&bsxml);
if(SUCCEEDED(hr))
{
wprintf(L"%d,%s",curLevel,bsxml);
}
long value;
pNode->get_childNodes(&pNodelist);
pNode->Release();
pNodelist->get_length(&value);
for(int i=value-1;i>=0;i–)
{
pNodelist->get_item(i,&pNode);
curNode.Node = pNode;
curNode.level = curLevel+1;
pushStack(curNode);
//printf("top:%d",top);
}
pNodelist->Release();
}
else pNode->Release();
}
}
}
//
pDoc->Release();
}
else printf("not cocreatinstance");
CoUninitialize();
}
else printf("not CoInitializeEx");
return 0;
}