[转]VC++中操作XML(MFC、SDK)

1 篇文章 0 订阅

http://www.cnblogs.com/lingyun1120/archive/2011/11/02/2232709.html

XML在Win32程序方面应该没有在Web方面应用得多,很多Win32程序也只是用XML来存存配置信息而已,而且没有足够的好处的话还不如用ini。VC++里操作XML有两个库可以用:MSXML和XmlLite。MSXML又细分了两种接口:DOM和SAX2。XP没自带有XmlLite,只自带有2.x、3.x版的MSXML,不支持SAX2(需要MSXML 4.0以上),所以优先使用DOM。
DOM是以COM形式提供的,VC++里调用DOM可以分3种方法:
1、MFC里用CComPtr调用
2、SDK里直接调用DOM接口
3、SDK里用智能指针调用
这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",nodeType为NODE_TEXT,nodeValue就是"text");也可以用get_text直接得到"text",但是对于这样的节点<tag>text<childtag>childtext</childtag></tag>,get_text会同时得到"text"和"childtext",不过这样的节点应该是不允许的。
DOM里使用的字符串(BSTR)都是OLESTR类型,默认情况下OLESTR是Unicode字符,MFC里可以用COLE2CT把LPCOLESTR转换为LPCTSTR。
对于自己定义的XML,大多数时候不需要遍历,可以通过调用selectNodes、selectSingleNode指定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 ) ;   //得到childnode1的attrib1属性

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 ;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值