MFC/VC++中操作XML(MFC、SDK)解析

VC++中操作XMLMFCSDK) 

XMLWin32程序方面應該沒有在Web方面應用得多,很多Win32程序也只是用XML來存存配置信息而已,而且沒有足夠的好處的話還不如用iniVC++裏操作XML有兩個庫可以用:MSXMLXmlLiteMSXML又細分了兩種接口:DOMSAX2XP沒自帶有XmlLite,只自帶有2.x3.x版的MSXML,不支持SAX2(需要MSXML 4.0以上),所以優先使用DOM
DOM是以COM形式提供的,VC++裏調用DOM可以分3種方法:
1MFC裏用CComPtr調用
2SDK裏直接調用DOM接口
3SDK裏用智能指針調用
3種方法本質上是一樣的,區別只不過在於需要編碼的多少而已,用CComPtr可以極大的簡化代碼,下面是幾個例子。
例子stocks.xml

<?xml version="1.0" encoding="utf-8"?>
<root>
<node1>text1</node1>
<node2>
<childnode1 attrib1="value1" attrib2="value2"/>
<childnode2 attrib1="value1" attrib2="value2">childtext1</childnode2>
</node2>
</root>


這個例子應該包含了XML最常見的特徵了吧?

MFC
MFC裏可以直接使用DOM,不需要手動添加額外的頭文件,只需要在CWinApp::InitInstance()裏調用CoInitialize(NULL)初始化COM,在CWinApp::ExitInstance裏調用CoUninitialize()釋放COM就行了。

//讀取XML
CComPtr<IXMLDOMDocument> spDoc; //DOM
spDoc.CoCreateInstance(CLSID_DOMDocument);
VARIANT_BOOL vb;
spDoc->load(CComVariant(OLESTR("stocks.xml")), &vb); //加載XML文件
CComPtr<IXMLDOMElement> spRootEle;
spDoc->get_documentElement(&spRootEle); //根節點
CComPtr<IXMLDOMNodeList> spNodeList;
spRootEle->get_childNodes(&spNodeList); //子節點列表
long nLen;
spNodeList->get_length(&nLen); //子節點數
for (long i = 0; i != nLen; ++i) //遍歷子節點
{
CComPtr<IXMLDOMNode> spNode;
spNodeList->get_item(i, &spNode);
ProcessNode(spNode); //節點處理函數
}

//寫入XML
CComPtr<IXMLDOMNode> spNode;
spRootEle->selectSingleNode(OLESTR("/root/node1"), &spNode);
spNode->put_text(OLESTR("newText")); //寫入text
spRootEle->selectSingleNode(OLESTR("/root/node2/childnode1/@attrib1"), &spNode);
spNode->put_nodeValue(CComVariant(OLESTR("newValue"))); //寫入value
CComPtr<IXMLDOMNode> spNewNode;
spDoc->createNode(CComVariant(NODE_ELEMENT), OLESTR("childnode3"), OLESTR(""), &spNewNode); //創建新節點
spRootEle->selectSingleNode(OLESTR("/root/node2"), &spNode);
spNode->appendChild(spNewNode, &spNewNode); //將新節點加爲node2的子節點
spNewNode->put_text(OLESTR("childtext2")); //寫入新節點text
CComQIPtr<IXMLDOMElement> spEle = spNewNode; //注意這裏使用CComQIPtr
spEle->setAttribute(OLESTR("attrib1"), CComVariant(OLESTR("value1")));//給新節點添加屬性
spDoc->save(CComVariant(OLESTR("stocks.xml")));

//節點處理函數
void ProcessNode(CComPtr<IXMLDOMNode>& spNode)
{
CComBSTR bsNodeName;
spNode->get_nodeName(&bsNodeName); //節點名
AfxMessageBox(COLE2CT(bsNodeName));
CComVariant varVal;
spNode->get_nodeValue(&varVal); //節點值
AfxMessageBox(COLE2CT(varVal.bstrVal));

DOMNodeType eNodeType;
spNode->get_nodeType(&eNodeType);
if (eNodeType == NODE_ELEMENT) //只有NODE_ELEMENT類型才能包含有屬性和子節點
{
//遞歸遍歷節點屬性
CComPtr<IXMLDOMNamedNodeMap> spNameNodeMap;
spNode->get_attributes(&spNameNodeMap);
long nLength;
spNameNodeMap->get_length(&nLength);
for (long i = 0; i != nLength; ++i)
{
CComPtr<IXMLDOMNode> spNodeAttrib; //注意屬性也是一個IXMLDOMNode
spNameNodeMap->get_item(i, &spNodeAttrib);
ProcessNode(spNodeAttrib);
}

//遞歸遍歷子節點
CComPtr<IXMLDOMNodeList> spNodeList;
spNode->get_childNodes(&spNodeList);
spNodeList->get_length(&nLength);
for (long i = 0; i != nLength; ++i)
{
CComPtr<IXMLDOMNode> spChildNode;
spNodeList->get_item(i, &spChildNode);
ProcessNode(spChildNode);
}
}
}


對於<tag>text</tag>這樣的節點,get_nodeValue會得到空,要得到"text"的話可以遍歷子節點(只有一個子節點,它的nodeName"#text"nodeTypeNODE_TEXTnodeValue就是"text");也可以用get_text直接得到"text",但是對於這樣的節點<tag>text<childtag>childtext</childtag></tag>get_text會同時得到"text""childtext",不過這樣的節點應該是不允許的。
DOM裏使用的字符串(BSTR)都是OLESTR類型,默認情況下OLESTRUnicode字符,MFC裏可以用COLE2CTLPCOLESTR轉換爲LPCTSTR
對於自己定義的XML,大多數時候不需要遍歷,可以通過調用selectNodesselectSingleNode指定XPath直接讀取某個節點或屬性:

CComPtr<IXMLDOMDocument> spDoc; //DOM
spDoc.CoCreateInstance(CLSID_DOMDocument);
VARIANT_BOOL vb;
spDoc->load(CComVariant(OLESTR("stocks.xml")), &vb); //加載XML文件
CComPtr<IXMLDOMElement> spRootEle;
spDoc->get_documentElement(&spRootEle); //根節點

CComPtr<IXMLDOMNodeList> spNodeList;
CComPtr<IXMLDOMNode> spNode;
spRootEle->selectNodes(OLESTR("/root/node2/*"), &spNodeList); //得到node2下的所有子節點
spRootEle->selectSingleNode(OLESTR("/root/node2/childnode1/@attrib1"), &spNode); //得到childnode1attrib1屬性


XPath的語法可以參考XML文檔或MSDN

SDK
SDK中也可以使用智能指針,和MFC沒太大區別,同樣很方便,直接給代碼:


#include <iostream>
#include <tchar.h>

#import <msxml3.dll>

//節點處理函數
void ProcessNode(MSXML2::IXMLDOMNodePtr spNode)
{
std::cout << "nodeName: " << spNode->nodeName;
if (spNode->nodeType == NODE_ATTRIBUTE || spNode->nodeType == NODE_TEXT)
std::cout << "\tnodeValue: " << _bstr_t(spNode->nodeValue);
std::cout << std::endl;

if (spNode->nodeType == NODE_ELEMENT)
{
MSXML2::IXMLDOMNamedNodeMapPtr spNameNodeMap = spNode->attributes;
for (long i = 0; i != spNameNodeMap->length; ++i) //遍歷節點屬性
ProcessNode(spNameNodeMap->item[i]);

MSXML2::IXMLDOMNodeListPtr spNodeList = spNode->childNodes;
for (long i = 0; i != spNodeList->length; ++i) //遍歷子節點
ProcessNode(spNodeList->item[i]);
}
}

int _tmain(int argc, _TCHAR* argv[])
{
CoInitialize(NULL);
//讀取XML
MSXML2::IXMLDOMDocumentPtr spXMLDoc;
spXMLDoc.CreateInstance(__uuidof(MSXML2::DOMDocument30));
spXMLDoc->load(L"stocks.xml");
MSXML2::IXMLDOMElementPtr spRoot = spXMLDoc->documentElement; //根節點
MSXML2::IXMLDOMNodeListPtr spNodeList = spRoot->childNodes;
for (long i = 0; i != spNodeList->length; ++i) //遍歷子節點
ProcessNode(spNodeList->item[i]);

//寫入XML
spRoot->selectSingleNode(L"/root/node1")->text = L"newText";
spRoot->selectSingleNode(L"/root/node2/childnode1/@attrib1")->nodeValue = L"newValue";
MSXML2::IXMLDOMNodePtr spNewNode = spRoot->selectSingleNode(L"/root/node2")->appendChild(
spXMLDoc->createNode(_variant_t(NODE_ELEMENT), L"childnode3", L"")
); //node2創建新子節點childnode3
spNewNode->text = L"childtext2";
MSXML2::IXMLDOMElementPtr spEle = spNewNode;
spEle->setAttribute(L"attrib1", _variant_t(L"value1")); //添加新屬性
spXMLDoc->save(_variant_t(L"stocks.xml"));

spNewNode.Release();
spEle.Release();
spNodeList.Release();
spRoot.Release();
spXMLDoc.Release();
CoUninitialize();

system("pause");
return 0;
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

VC MSXML4.0 操作

(2006-07-25 12:08:34)

轉載▼

 

分類:關於VC

//#import "msxml4.dll"
//AfxOleInit();
 MSXML2::IXMLDOMDocumentPtr doc;
 CString msg("<ebody><version>1.0</version><command>logon</command><body><UserName>zayu</UserName><Password>123</Password></body></ebody>");
 if(SUCCEEDED(doc.CreateInstance(CLSID_DOMDocument)))
 {
 if(S_OK == doc->loadXML(msg.AllocSysString()))
 {
 MSXML2::IXMLDOMNodePtr node;
 node = doc->selectSingleNode("ebody//command");
 CString str1;
 str1.Format("%s",(char *)node->text);
 }
 }

#define ReportMessage(hr,resID); \
 if(FAILED(hr))\
 {\
  m_strErrorMessage.LoadString(resID);\
  break;\
 }
//讀取doc
#define ReadNode(doc,node,name,content,resID); \
 ReportMessage(doc->selectSingleNode(name,&node),resID);\
 if(node == NULL) \
 {\
  m_strErrorMessage.LoadString(resID+1);\
  break;\
 }\
 ReportMessage(node->get_text(&content),resID+2);\
 node.Release();\
 node = NULL;


//////////////////////////////////////////////////////////////////////////////////
 try
 {

  //文檔接口
  CComPtr<IXMLDOMDocument> doc = NULL;
  //接點接口
  CComPtr<IXMLDOMNode>  node=NULL;
  ////接點名字
  _bstr_t      name;
  //接點內容
  BSTR      content;

  do
  {
   ReportMessage(doc.CoCreateInstance(CLSID_DOMDocument),IDS_CREATE_XML_INTERFACE);

   VARIANT_BOOL var_bool = VARIANT_TRUE;

   ReportMessage(doc->load(_variant_t(strFileName),&var_bool),IDS_READ_CONFIG);
   if(var_bool != VARIANT_TRUE)
   {
    m_strErrorMessage.LoadString(IDS_READ_CONFIG_ERROR);
    //CComPtr<IXMLDOMParseError> pObjError = NULL;
    //BSTR bstrMessage;
    //doc->get_parseError(&pObjError);
    //pObjError->get_reason(&bstrMessage);
    //m_strErrorMessage.Format("加載配置文件錯誤%S\n",(LPCSTR)_bstr_t(bstrMessage));
    break;
   }

   name = "config//server//port";
   ReadNode(doc,node,name,content,IDS_READ_PORT);
   m_config.nPort = atoi((char*)_bstr_t(content));

   name = "config//server//count";
   ReadNode(doc,node,name,content,IDS_READ_COUNT);
   m_config.nCount = atoi((char*)_bstr_t(content));

 

 

發佈了23 篇原創文章 · 獲贊 8 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章