龙盟编程博客 | 无障碍搜索 | 云盘搜索神器
快速搜索
主页 > 软件开发 > C/C++开发 >

C++中处理XML文件

时间:2009-12-22 15:42来源:未知 作者:admin 点击:
分享到:
写Unmanaged Code在.NET时代成为一种很悲惨的事,当你需要处理XML文件时,这种感觉会变得尤其强烈。FCL中的System.XML多简单啊,连Steve Ballmer都知道怎么用。 事情不会总是那么理想的,假如

  写Unmanaged Code在.NET时代成为一种很悲惨的事,当你需要处理XML文件时,这种感觉会变得尤其强烈。FCL中的System.XML多简单啊,连Steve Ballmer都知道怎么用。

  

  事情不会总是那么理想的,假如你要在C/C++程序里处理XML怎么办呢?

  

  选择一:市面上的XML lib还是有几个的,最有名的当然是libXML。我一年前用过,很不错,我还特意写了一份简明教程,后来不知搁哪儿了。

  

  选择二:MS的MSXML,我要介绍的就是这个。

  

  先说一下在MSDN哪里找文档吧,往下看的时候也好有个参考:在Index里打:Windows Media Services 9 Series SDK=>Programming Reference=>Programming Reference (C++)=>XML DOM Interfaces (C++)。什么?Windows Media?呵呵,不错,我觉得这个guide反而是最清楚的,你直接找MSXML,得到的结果,我觉得还没这个好。

  

  在C程序里调用MSXML基本就是一堆COM接口,不过在Visual Studio里操作先要做点简单的设置:

  

  在你的Project里Add References=>COM标签=>Microsoft XML v4.0,5.0其实也有了,但因为是和Office一起发布的,觉得有点怪,不想用,反正也未必用什么很怪异的功能,4.0可以了。

  

  

  

  然后在加入这两行:

  

  #include

  #import

  

  头文件和dll库。什么?在哪里加?头文件或者c/cpp文件啊,哪里合适放哪儿。

  

  然后就开始编程了,先定义两个必用的变量:

  

  IXMLDOMDocumentPtr XMLFile = NULL;

  IXMLDOMElement* XMLRoot = NULL;

  

  为什么是必用的?  汗...

  

  第一步当然是初始化COM:

  

  if(FAILED(CoInitialize(NULL))) ....

  

  接下来初始化XMLFile对象:

  

  if(FAILED(XMLFile.CreateInstance("MsXML2.DOMDocument.4.0"))) ...

  

  然后就可以加载XML文件了:

  

  _variant_t varXML(L"C:est.XML"); //L for unicode

  VARIANT_BOOL varOut;

  XMLFile->load(varXML, &varOut);

  

  取得root element:

  

  XMLFile->get_documentElement(&XMLRoot))

  

  取得第一级element:

  

  IXMLDOMNodeList* XMLChildNodes = NULL;

  XMLRoot->get_childNodes(&XMLChildNodes);

  

  遍历所有第一级element:

  

  IXMLDOMNode* currentNode = NULL;

  while(!FAILED(XMLChildNodes->nextNode(¤tNode)) && currentNode != NULL)

  {

   //do something

  }

  

  取得当前element的名称:

  

  BSTR nodeName;

  currentNode->get_nodeName(&nodeName);

  

  取得当前element的一个attribute(假设这个attribute叫type)的值:

  

  IXMLDOMNamedNodeMap* attributes = NULL;

  IXMLDOMNode* attributeName = NULL;

  _bstr_t bstrAttributeName = "type";

  BSTR nameVal;

  currentNode->get_attributes(&attributes);

  attributes->getNamedItem(bstrAttributeName, &attributeName);

  attributeName->get_text(&nameVal);

  

  需要注重的是,你要记住释放所有的借口,IXMLDOM***->Release(),这可不是.NET,有人帮你GC,你得自己调用Release()来减reference count,it's COM, remember?

  

  好了,大致就这样,顺便提一下XPath:

  

  _bstr_t bstrXMLQuery = L"/books/book[@type=scifi and @author=fox]";

  

  IXMLDOMNodeList* nodes = NULL;

  if(FAILED(XMLRoot->selectNodes(bstrXMLQuery, &nodes)) FAILED(nodes->get_length(&length)) length == 0)

   //no match found or something went wrong

  else

   //match found

  

  上面是找这样的node:

  

  

   ....

  

  ....

  

  

  具体的XPath语法就查手册吧,到处都有。

  

  哦,对了,忘了说:假如你全部用ATL的类的话,借口的调用会简单一点,不过很轻易转换的,比如:

  

  IXMLDOMDocument* 对应 IXMLDOMDocumentPtr(我这里用了),其他基本也是加个Ptr,我不废话了。

  

  最后提供一个sample,我临时攒的。工作的时候写的程序当然不能拿来贴的,呵呵。这个sample基本就是遍历整个XML,然后报告一遍文件的结构,对每个node,假如它有一个叫id的attribute,就同时打印id的值。If you want the complete VS project, shoot me an email. But I guess no one really needs it anyway, right, : )

  

  #include "stdafx.h"

  #include

  #include

  #import

  

  HANDLE logFile = NULL;

  

  #define INDENT 4

  

  #define TESTHR(hr)

  {

   if(FAILED(hr)) goto fail;

  }

  

  void PrintChild(IXMLDOMNodeList* nodeList, int level)

  {

   if(nodeList == NULL)

   return;

  

   IXMLDOMNode* currentNode = NULL;

   IXMLDOMNodeList* childNodes = NULL;

   IXMLDOMNamedNodeMap* attributes = NULL;

   IXMLDOMNode* attributeID = NULL;

  

   while(!FAILED(nodeList->nextNode(¤tNode)) && currentNode != NULL)

   {

   BSTR nodeName;

   TESTHR(currentNode->get_nodeName(&nodeName));

   DWord dwBytesWritten;

   for(int i=0; i

   WriteFile(logFile, L" ", (Dword)(sizeof(WCHAR)), &dwBytesWritten, NULL);

  

   //WCHAR msg[MAX_SIZE];

   //wsprintf(msg, L"%s ", nodeName);

   WriteFile(logFile, nodeName, (Dword)(wcslen(nodeName)*sizeof(WCHAR)), &dwBytesWritten, NULL);

  

   TESTHR(currentNode->get_attributes(&attributes));

   if(attributes!=NULL)

   {

   _bstr_t bstrAttributeName = "id";

   BSTR idVal;

   TESTHR(attributes->getNamedItem(bstrAttributeName, &attributeID));

   if(attributeID != NULL)

   {

   TESTHR(attributeID->get_text(&idVal));

   WriteFile(logFile, L" ", (Dword)(sizeof(WCHAR)), &dwBytesWritten, NULL);

   WriteFile(logFile, idVal, (Dword)(wcslen(idVal)*sizeof(WCHAR)), &dwBytesWritten, NULL);

   WriteFile(logFile, L"

", (Dword)(2*sizeof(WCHAR)), &dwBytesWritten, NULL);

   attributeID->Release(); attributeID = NULL;

   }

   else

   {

   WriteFile(logFile, L"

", (Dword)(2*sizeof(WCHAR)), &dwBytesWritten, NULL);

  

   }

   attributes->Release(); attributes = NULL;

  

   }

   else

   {

   WriteFile(logFile, L"

", (Dword)(2*sizeof(WCHAR)), &dwBytesWritten, NULL);

   }

  

   TESTHR(currentNode->get_childNodes(&childNodes));

   PrintChild(childNodes, level+1);

   currentNode=NULL;

   }

  

  fail:

   if(childNodes!=NULL)

   childNodes->Release();

   if(attributeID!=NULL)

   attributeID->Release();

   if(attributes!=NULL)

   attributes->Release();

   if(currentNode != NULL)

   currentNode->Release();

  }

  

  int _tmain(int argc, _TCHAR* argv[])

  {

  

   IXMLDOMDocumentPtr XMLFile = NULL;

   IXMLDOMElement* XMLRoot = NULL;

   _variant_t varXML(L"C:demo1.XML");

  

   logFile = CreateFile(L"log.txt", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

   if(logFile == INVALID_HANDLE_VALUE)

   goto fail;

  

   TESTHR(CoInitialize(NULL));

  

   TESTHR(XMLFile.CreateInstance("MsXML2.DOMDocument.4.0"));

  

   VARIANT_BOOL varOut;

   TESTHR(XMLFile->load(varXML, &varOut));

  

   TESTHR(XMLFile->get_documentElement(&XMLRoot));

  

   BSTR rootName;

   Dword dwBytesWritten;

   TESTHR(XMLRoot->get_nodeName(&rootName));

   WriteFile(logFile, rootName, (Dword)(wcslen(rootName)*sizeof(WCHAR)), &dwBytesWritten, NULL);

   WriteFile(logFile, L"

", (Dword)(2*sizeof(WCHAR)), &dwBytesWritten, NULL);

  

   IXMLDOMNodeList* XMLChildNodes = NULL;

   TESTHR(XMLRoot->get_childNodes(&XMLChildNodes));

  

   PrintChild(XMLChildNodes, 2);

  

  fail:

   if(logFile != INVALID_HANDLE_VALUE)

   CloseHandle(logFile);

   if(XMLChildNodes!=NULL)

   XMLChildNodes->Release();

   if

  

精彩图集

赞助商链接