和HTML一样,可扩展置标语言XML(eXtensible Markup Language)也是一种置标语言。它同样依赖于描述一定规则的标签和能够读懂这些标签的应用处理工具来发挥它的强大功能。这一点,从XML的命名上也可窥见一斑。
c++操作xml
安装后的vc环境下,在c:/windows/system32文件中有操作xml的动态链接库,比如:msxml2,msxml3等。不过后面我们要用到的是msxml4.dll文件。这需要从微软的官方网站下载。当然调用这样的dll并不是用loadliberary()函数,它是一种com组件,不仅c++语言能够调用,其他的vb等都可以通过com接口来调用。在你编写的代码的头文件中加上#import <msxml4.dll> named_guids, 代码编译一次后就不在需要改dll文件了,也是普通dll文件不同的地方。咱们最常用到的接口是
MSXML2::IXMLDOMDocumentPtr m_plDocument; 文档接口。一个这样的指针就代表一个xml文件。
MSXML2::IXMLDOMElementPtr m_plEle; 文档元素。
MSXML2::IXMLDOMNodePtr m_pRootNode; 根节点。通过元素指针得到的根节点,当然每个文档只有一个根节点。
MSXML2::IXMLDOMNodeListPtr m_pNodeList; 节点下所包含的所有节点。
下面的例子是一个合格的xml文档,表示前面的几种接口:
< processes >
< process >
< name > qq.exe </ name >
< user > SYSTEM </ user >
< class > 正常 </ class >
< description > 聊天工具 </ description >
</ process >
< process >
< name > svhost32.exe </ name >
< user > SYSTEM </ user >
< class > 病毒 </ class >
< description > 未知道是什么 </ description >
</ process >
< processes >
这样的文档能够清晰得表示了进程的描述,每一个个进程所具有的四种特征:名字、进程的用户、进程的种类、进程的描述。这也是形成一个规格的xml文档所必须的最少元素。m_plDocument就是一个指向该文档的指针,m_plEle可以代表进程的节点元素,m_pRootNode指向根节点processes,而m_pNodeList表示所有的进程。所以在引用一个文档不管是读还是写文档前所需要做的初始化工作如下:
HRESULT hr = m_plDocument.CreateInstance(MSXML2::CLSID_DOMDocument); // 创建示例
if (FAILED(hr))
... {
_com_error er(hr);
AfxMessageBox(er.ErrorMessage());
}
// specify xml file name
CString strFileNamec (strFileName);
// convert xml file name string to something COM can handle (BSTR)
_bstr_t bstrFileName;
bstrFileName = strFileNamec.AllocSysString();
// call the IXMLDOMDocumentPtr's load function to load the XML document
variant_t vResult;
vResult = m_plDocument -> load(bstrFileName); // 把硬盘上的文件载进内存
HRESULT hr1;
if ((( bool )vResult) == TRUE) // success!
... {
// now that the document is loaded, we need to initialize the root pointer
hr1 = m_plDocument->get_documentElement(&m_plEle); //通过文档指针得到元素指针
if (SUCCEEDED(hr1))
...{
hr1 = m_plEle->QueryInterface(IID_IXMLDOMNode, (void **)&m_pRootNode);//得到文档根节点
if (SUCCEEDED(hr1))
...{
m_pRootNode->get_childNodes(&m_pNodeList);
m_pNodeList->get_length(&nLength);
}
}
}
::UnCoInitialize; // 卸载com组建
把文档从硬盘载到内存后,并且得到了文档的根节点指针后就可以做真正做想做的事情了,比如增加节点,删除节点,修改节点了。
可以灵活的操作节点,我们可以把每个节点代表一个数据库中的一条记录。如上例,<processes>包含了2个子<process>节点,每个<process>节点又包括四个子节点<name>,<user>,<class>,<description>.所以你想要操作一个节点,就要得到指向该节点的指针。
增加节点.
节点属性: name(devenv.exe), user(zhao), class(正常), description(microsoft.net开发环境);
操作函数: createNode(CComVariantm, BSTR, BSTR), appendChild(MSXML2::IXMLDOMNodePtr);
具体实现:
MSXML2::IXMLDOMNodeListPtr m_pOneNodeList;
MSXML2::IXMLDOMNodePtr m_pTwoNode1, m_pTwoNode2, m_pTwoNode3, m_pTwoNode4;
CComVariant varType(NODE_ELEMENT);
CString strNodeName = _T( " process " );
m_pOneNode = m_plDocument -> createNode(varType, strNodeName.AllocSysString(), (BSTR)NULL);
strNodeName = _T( " name " );
m_pTwoNode1 = m_plDocument -> createNode(varType, strNodeName.AllocSysString(), (BSTR)NULL);
m_pTwoNode1 -> put_text(_com_util::ConvertStringToBSTR(ProcessName));
m_pOneNode -> appendChild(m_pTwoNode1);
strNodeName = _T( " user " );
m_pTwoNode2 = m_plDocument -> createNode(varType, strNodeName.AllocSysString(), (BSTR)NULL);
m_pTwoNode2 -> put_text(_com_util::ConvertStringToBSTR(strUserIn));
m_pOneNode -> appendChild(m_pTwoNode2);
strNodeName = _T( " class " );
m_pTwoNode3 = m_plDocument -> createNode(varType, strNodeName.AllocSysString(), (BSTR)NULL);
m_pTwoNode3 -> put_text(_com_util::ConvertStringToBSTR(strClass));
m_pOneNode -> appendChild(m_pTwoNode3);
strNodeName = _T( " description " );
m_pTwoNode4 = m_plDocument -> createNode(varType, strNodeName.AllocSysString(), (BSTR)NULL);
m_pTwoNode4 -> put_text(_com_util::ConvertStringToBSTR(Description));
m_pOneNode -> appendChild(m_pTwoNode4);
m_pRootNode -> appendChild(m_pOneNode);
m_plDocument -> save( " ProcessInfo.xml " ); // 把内存中的xml文档保存到硬盘中且文件名为processInfo.xml;
删除节点.
节点名: name(svchost32.exe)
操作函数:removeChild(MSXML2::IXMLDOMNodePtr )
具体实现:
MSXML2::IXMLDOMNodeListPtr m_pOneNodeList;
// MSXML2::IXMLDOMNodePtr m_pTwoNode1, m_pTwoNode2, m_pTwoNode3;
m_pRootNode -> get_childNodes( & m_pOneNodeList);
m_pOneNodeList -> get_item( 1 , & m_pOneNode);
m_pRootNode -> removeChild(m_pOneNode);
m_plDocument -> save( " ProcessInfo.xml " );
修改节点.
节点名: name(svchost32.exe), 把class属性改为"正常";
操作函数:put_text
具体实现:
char strName[ 32 ];
SXML2::IXMLDOMNodePtr m_pOneNode = NULL, m_pOneNode1;
MSXML2::IXMLDOMNodeListPtr m_pOneNodeList, m_pOneNodeList1;
// MSXML2::IXMLDOMNodePtr m_pTwoNode1, m_pTwoNode2, m_pTwoNode3;
m_pRootNode -> get_childNodes( & m_pOneNodeList);
int nLength;
m_pOneNodeList -> get_length( & nLength);
for ( int i = 0 ; i < nLength; i ++ )
... {
m_pOneNodeList->get_item(i, &m_pOneNode);
m_pOneNode->get_childNodes(&m_pOneNodeList1);
m_pOneNodeList1->get_item(0, &m_pOneNode1);
m_pOneNode1->get_text(&bText);
memcpy(strName, _com_util::ConvertBSTRToString(bText), sizeof(strName));
if (!strcmp("svchost32.exe", strName))
...{
m_pOneNodeList1->get_item(1, &m_pOneNode1);
m_pOneNode1->put_text(_com_util::ConvertStringToBSTR("正常"));
break;
}
}
m_plDocument -> save( " ProcessInfo.xml " );
扫尾工作:
m_pRootNode.Release();
m_plEle.Release();
m_plDocument.Release();