摘要:VC++中操作XML XML在Win32程序方面应该没有在Web方面应用得多,很多Win32程序也只是用XML来存存配置信息而已,而且没有足够的好处的话还不如用ini。VC++里操作XML有两个库可以用:MSXML和XmlLite。MSXML又细分了两种接口:

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

VC++中操作XMLWin32实例的更多相关文章

  1. VC++中操作XML(MFC、SDK)转

    [转]VC++中操作XML(MFC.SDK) XML在Win32程序方面应该没有在Web方面应用得多,很多Win32程序也只是用XML来存存配置信息而已,而且没有足够的好处的话还不如用ini.VC++ ...

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

    XML在Win32程序方面应该没有在Web方面应用得多,很多Win32程序也只是用XML来存存配置信息而已,而且没有足够的好处的话还不如用ini.VC++里操作XML有两个库可以用:MSXML和Xml ...

  3. C#开发中使用Npoi操作excel实例代码

    C#开发中使用Npoi操作excel实例代码 出处:西西整理 作者:西西 日期:2012/11/16 9:35:50 [大 中 小] 评论: 0 | 我要发表看法 Npoi 是什么? 1.整个Exce ...

  4. 不借助工具在浏览器中通过Web API执行Dynamics 365操作(Action)实例

    摘要: 本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复262或者20170727可方便获取本文,同时可以在第一间得到我发布的最新的博文信息,follow me!我的网站是 www.luoyon ...

  5. VC在线程中操作界面

    http://blog.csdn.net/tingsking18/article/details/4399199 多线程是我们在编程中经常遇到的问题,线程执行完后往往要把执行的结果传给主线程,但是MF ...

  6. VC线程中操作控件,引起程序卡死的问题。

    [问题还原] 线程中操作控件,具体为控制一个按键的使能,使能后结束线程. 主程序中有一个死循环,等待线程结束. 然后,就没有然后了-- [解决方案] 在主程序死循环中,如果检测到界面消息,优先处理掉.

  7. Selenium2学习-014-WebUI自动化实战实例-012-Selenium 操作下拉列表实例-div+{js|jquery}

    之前已经讲过了 Selenium 操作 Select 实现的下拉列表:Selenium2学习-010-WebUI自动化实战实例-008-Selenium 操作下拉列表实例-Select,但是在实际的日 ...

  8. VC++学习之VC中常见问题

    VC++学习之VC中常见问题 (1)为什么某个类突然在工作区间里面突然看不见了? 只是类隐藏了,打开FILEVIEW,找到隐藏类的头文件,随便敲一下键盘的空格键,类就会在CLASSVIEW中显示了 ( ...

  9. VC中GetLastError()获取错误信息的使用,以及错误代码的含义

    转载:http://www.seacha.com/article.php/knowledge/windows/mfc/2011/0423/335.html VC中GetLastError()获取错误信 ...

随机推荐

  1. 认识div(division)在排版中的作用

    在网页制作过程过中,可以把一些独立的逻辑部分划分出来,放在一个<div>标签中,这个<div>标签的作用就相当于一个容器. 语法: <div>…</div&g ...

  2. CSS 布局Float 【1】

    1.HTML元素分类 HTML元素大题可分为内联(inline)元素和块(block)元素. 1.1 内联元素(inline) ①元素显示方式:"文本方式",1个挨着1个,不独自占 ...

  3. 设置Imindmap默认字体

    创建一个新的字体样式 根据如下步骤创建新的字体样式: 1.打开一个mindmap,选中工具栏上的 [样式][Styles ]. 2.选择 Font > Create New Font Optio ...

  4. PHP文件类型检查类-比较全的

    在CSDN上淘来的一个文件类型的类,还不错,留下自己看! <? /** * 检证文件类型类 * * @author */ class FileTypeValidation { // 文件类型,不 ...

  5. bzoj4171 or 省队集训day3 chess: Rhl的游戏

    [题目描述] RHL最近迷上一个小游戏:Flip it.游戏的规则很简单,在一个N*M的格子上,有一些格子是黑色,有一些是白色.每选择一个格子按一次,格子以及周围边相邻的格子都会翻转颜色(边相邻指至少 ...

  6. Objective-C释解 Target-Action模式

    Objective-C释解 Target-Action模式   Target-Action模式是ObjC里非常常见的对象之间方法调用的方式,不过ObjC把方法调用叫做Send Message. 一帮情 ...

  7. mobox:推进企业文档管理走向信息化之路

    随着“大数据”时代的到来,越来越多的人们对数据库管理信息抱有认可态度,这是近年来信息化发展的必然结果.企业作为推进社会经济发展的主力军,也必然要紧跟大数据时代潮流,利用计算机技术全面普及企业的信息化管 ...

  8. 开发者应该避免使用的6个Java功能(转)

    本文作者是一名拥有多年Java开发经验的程序员,他从经验中得出,并不是所有的Java SE功能/API都值得程序员去使用,比如本文列举的这6个,大家在使用前得慎重对待.以下是对原文的摘译. 多年的Ja ...

  9. centos ppp拨号

    CentOS 6.4 电信ADSL 拨号连接的配置,亲测 .下载 rp-pppoe-3.8.tar.gz http://down1.chinaunix.net/distfiles/rp-pppoe-3 ...

  10. WordPress NextGEN Gallery ‘upload.php’任意文件上传漏洞

    漏洞名称: WordPress NextGEN Gallery ‘upload.php’任意文件上传漏洞 CNNVD编号: CNNVD-201306-259 发布时间: 2013-06-20 更新时间 ...