使用MSXML2解析XML文件

最近在做项目的过程中,需要解析XML文件的内容。本篇文章记录一下自己使用MSXML2解析XML文件。

1.什么是XML?XML文件的存储格式是怎样的?

1.XML文件的定义:
可扩展标记语言,标准通用标记语言的子集,简称XML,是一种用于标记电子文件使其具有结构性的标记语言。——摘自百度百科。大家可以参考什么是XML文件
2.XML文件的格式或者内容长什么样子呢

<?xml version="1.0" encoding="UTF-8"?>
<site>
  <name>RUNOOB</name>
  <url>https://www.runoob.com</url>
  <logo>runoob-logo.png</logo>
  <desc>编程学习网站</desc>
</site>

如上所述,第一行以XML开头,用来描述文档的一些信息。
,,, 都是标签,分别包含了要传递的信息。
标签必须成对出现,又开始标签就有结束标签。
XML文件形成了一种树结构,它从“根部“”开始,然后扩展到“枝叶”。
根元素:
开始标签:
结束标签:
接下来是描述根的子元素:




还有包含在子元素的中的文本分别是:
RUNOOB
https://www.runoob.com
runoob-logo.png
编程学习网站
下面看一张图更加的直观,有助于理解
在这里插入图片描述

<bookstore>
    <book category="COOKING">
        <title lang="en">Everyday Italian</title>
        <author>Giada De Laurentiis</author>
        <year>2005</year>
        <price>30.00</price>
    </book>
    <book category="CHILDREN">
        <title lang="en">Harry Potter</title>
        <author>J K. Rowling</author>
        <year>2005</year>
        <price>29.99</price>
    </book>
    <book category="WEB">
        <title lang="en">Learning XML</title>
        <author>Erik T. Ray</author>
        <year>2003</year>
        <price>39.95</price>
    </book>
</bookstore>

实例中的根元素是 。文档中的所有 元素都被包含在 中。
元素有 4 个子元素:、、、。

关于XML文档更加详细的说明大家可以参考[菜鸟教程]中的说明。(https://www.runoob.com/xml/xml-tree.html)

2.什么是MSXML2?

百度百科上的说法是:msxml指微软的xml语言解析器,用来解释xml语言的。
MSXML的主要接口有哪些呢:
1.DOM Document
DOMDocument对象是XML DOM的基础,你可以利用它所暴露的属性和方法来允许你浏览、查询和修改XML文档的内容和结构。DOMDocument表示了树的顶层节点。它实现了DOM文档的所有的基本的方法并且提供了额外的成员函数来支持XSL和XSLT。它创建了一个文档对象,所有其他的对象都可以从这个文档对象中得到和创建。
2.IXML DOMNode
IXMLDOMNode是文档对象模型(DOM)中的基本的对象,元素,属性,注释,过程指令和其他的文档组件都可以认为是IXMLDOMNode,事实上,DOMDocument对象本身也是一个IXMLDOMNode对象。
3.IXML DOM NodeList
IXMLDOMNodeList实际上是一个节点(Node)对象的集合,节点的增加、删除和变化都可以在集合中立刻反映出来,可以通过“for…next”结构来遍历所有的节点。
4、IXMLDOMParseError
IXMLDOMParseError接口用来返回在解析过程中所出现的详细的信息,包括错误号,行号,字符位置和文本描述。

3.如何使用MSXML2解析XML文件?

MSXML2的使用方法大家可以参考MSXML2使用教程
下面我讲一下我使用MSXML2解析XML文件:
我用的是VS2022.
第一步:
在framework.h中添加如下语句:

#import"C:\\Windows\\System32\\msxml6.dll"
using namespace MSXML2;

// 最好把这一段也加上
#ifdef _UNICODE
#if defined _M_IX86
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
#elif defined _M_X64
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#else
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#endif
#endif

大家如果找不到msxml6.dll的话,可以使用everything搜索即可。
由于我的项目是对话框项目,界面如下:
在这里插入图片描述
第二步:编写创建和读写XML文件的代码
1.我的项目名称叫做ReadWriteXML,创建XML文件的按钮代码如下:

void CReadWriteXMLDlg::OnBnClickedBtnCreate()
{
	// TODO: 在此添加控件通知处理程序代码
	// 创建一个文档指针
	MSXML2::IXMLDOMDocumentPtr pDoc;
	MSXML2::IXMLDOMElementPtr pRoot;
	// 实例化文档指针
	HRESULT hr = pDoc.CreateInstance(__uuidof(MSXML2::DOMDocument60));

	if (!SUCCEEDED(hr))
	{
		MessageBox(_T("XML文件创建失败!"));
		return;
	}

	pDoc->raw_createElement((_bstr_t)_T("China"),&pRoot);
	pDoc->raw_appendChild(pRoot,NULL);

	MSXML2::IXMLDOMElementPtr pElemNode;
	pDoc->raw_createElement((_bstr_t)_T("City"), &pElemNode);
	pElemNode->Puttext(_T("上海"));
	pElemNode->setAttribute(_T("Population"),_T("5000"));
	pElemNode->setAttribute(_T("Area"), _T("3000"));
	pRoot->appendChild(pElemNode);

	pDoc->raw_createElement((_bstr_t)_T("City"), &pElemNode);
	pElemNode->Puttext(_T("深圳"));
	pElemNode->setAttribute(_T("Population"), _T("2000"));
	pElemNode->setAttribute(_T("Area"), _T("1000"));
	pRoot->appendChild(pElemNode);

	pDoc->raw_createElement((_bstr_t)_T("City"), &pElemNode);
	pElemNode->Puttext(_T("北京"));
	pElemNode->setAttribute(_T("Population"), _T("8000"));
	pElemNode->setAttribute(_T("Area"), _T("6000"));
	pRoot->appendChild(pElemNode);

	pDoc->raw_createElement((_bstr_t)_T("City"), &pElemNode);
	pElemNode->Puttext(_T("广州"));
	pElemNode->setAttribute(_T("Population"), _T("9000"));
	pElemNode->setAttribute(_T("Area"), _T("7000"));
	pRoot->appendChild(pElemNode);
	pDoc->save(_T("..\\Bin\\MyTest.xml"));
}

创建的XML文件内容如下:

<China>
<City Population="5000" Area="3000">上海</City>
<City Population="2000" Area="1000">深圳</City>
<City Population="8000" Area="6000">北京</City>
<City Population="9000" Area="7000">广州</City>
</China>

2.读取XML文件的代码如下:

void CReadWriteXMLDlg::OnBnClickedBtnRead()
{
	// TODO: 在此添加控件通知处理程序代码
	// 先删除所有,再读取
	m_ListXMLInfo.DeleteAllItems();

	// 创建一个XML文档指针
    MSXML2::IXMLDOMDocumentPtr pDoc;
	// 实例化一个文档指针
	HRESULT hr = pDoc.CreateInstance(__uuidof(MSXML2::DOMDocument60));
	if (!SUCCEEDED(hr))
	{
		MessageBox(_T("加载XML文件错误!"));
		return;
	}
	// 加载XML文件
	VARIANT_BOOL Load = pDoc->load((_bstr_t)_T("..\\Bin\\MyTest.xml"));
	if (Load != -1)
	{
		MessageBox(_T("加载XML文件错误!"));
		return;
	}
	// 声明一个元素指针
	MSXML2::IXMLDOMElementPtr pElemNode;
	// 获取元素的信息;selectSingleNode():如果查询到一个或者多个结点,则返回第一个结点。否则返回NULL
	pElemNode = (MSXML2::IXMLDOMElementPtr)(pDoc->selectSingleNode(_T("//China")));

	// 声明一个容器类型,该类型通常用于容纳属性
	MSXML2::IXMLDOMNamedNodeMapPtr pAttrs = NULL;
	// 声明一个结点链表指针,可以增加,或者删除结点
	MSXML2::IXMLDOMNodeListPtr pNodeList = NULL;

	// 声明结点指针
	MSXML2::IXMLDOMNodePtr pAttrItem = NULL;
	// 获取pNodeList指向的子节点
	pElemNode->get_childNodes(&pNodeList);

	long nCount, iCount;
	MSXML2::IXMLDOMElementPtr pCurNode;
	// 获取pNodeList中结点的个数
	pNodeList->get_length(&iCount);

	for (int i = 0; i < iCount; i++)
	{
		// nextNode:获取当前节点和CObList链表很像
		pCurNode = pNodeList->nextNode();
		// getAttribute:获取当前结点的属性集
		CString strPopular = pCurNode->getAttribute(_T("Population"));
		CString strArea = pCurNode->getAttribute(_T("Area"));
		// Gettext:获取属性对应的文本;Puttext():设置文本
		CString strElemText = (_bstr_t)pCurNode->Gettext();
		// 将获取的属性值添加到CListCtrl控件中
		m_ListXMLInfo.InsertItem(i, strElemText);
		m_ListXMLInfo.SetItemText(i,1, strPopular);
		m_ListXMLInfo.SetItemText(i, 2, strArea);
	}
}

从XML文件中读取的内容如下:
在这里插入图片描述
3.添加结点的代码如下:

void CReadWriteXMLDlg::OnBnClickedBtnAddinfo()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);

	MSXML2::IXMLDOMDocumentPtr pDoc;

	HRESULT hr = pDoc.CreateInstance(__uuidof(MSXML2::DOMDocument60));
	if (!SUCCEEDED(hr))
	{
		MessageBox(_T("加载XML文件错误!"));
		return;
	}

	VARIANT_BOOL Load = pDoc->load((_bstr_t)_T("..\\Bin\\MyTest.xml"));
	if (Load != -1)
	{
		MessageBox(_T("加载XML文件错误!"));
		return;
	}

	MSXML2::IXMLDOMElementPtr pElemNode;
	pDoc->raw_createElement((_bstr_t)_T("City"), &pElemNode);
	pElemNode->Puttext((_bstr_t)m_strCity);
	CString strPeople, strArae;
	strPeople.Format(_T("%d"), m_nPeople);
	strArae.Format(_T("%d"), m_nArea);
	pElemNode->setAttribute(_T("Population"), (_bstr_t)strPeople);
	pElemNode->setAttribute(_T("Area"), (_bstr_t)strArae);
	MSXML2::IXMLDOMElementPtr pRoot;
	pRoot = (MSXML2::IXMLDOMElementPtr)(pDoc->selectSingleNode(_T("//China")));
	pRoot->appendChild(pElemNode);
	pDoc->save(_T("..\\Bin\\MyTest.xml"));
	m_ListXMLInfo.DeleteAllItems();
	OnBnClickedBtnRead();
}

添加结点的效果如下:
在这里插入图片描述
4.删除结点的代码如下:

void CReadWriteXMLDlg::OnBnClickedBtnDelete()
{
	// TODO: 在此添加控件通知处理程序代码
	MSXML2::IXMLDOMDocumentPtr pDoc;
	HRESULT hr = pDoc.CreateInstance(__uuidof(MSXML2::DOMDocument60));
	if (!SUCCEEDED(hr))
	{
		MessageBox(_T("加载XML文件错误!"));
		return;
	}

	VARIANT_BOOL Load = pDoc->load((_bstr_t)_T("..\\Bin\\MyTest.xml"));
	if (Load != -1)
	{
		MessageBox(_T("加载XML文件错误!"));
		return;
	}

	MSXML2::IXMLDOMElementPtr pRoot;
	pRoot = (MSXML2::IXMLDOMElementPtr)(pDoc->selectSingleNode(_T("//China")));
	
	MSXML2::IXMLDOMNodeListPtr pNodeList;
	pNodeList = pRoot->selectNodes(_T("City"));
	MSXML2::IXMLDOMNodePtr pNode;
	pNode = pNodeList->Getitem(m_nIndex);
	MSXML2::IXMLDOMNodePtr pOldNode;
	pRoot->raw_removeChild(pNode,&pOldNode);
	pDoc->save(_T("..\\Bin\\MyTest.xml"));
	m_ListXMLInfo.DeleteAllItems();
	OnBnClickedBtnRead();
}

删除结点的效果如下:
在这里插入图片描述
小结:使用MSXML2解析XML文件,最主要是要弄清楚MSXML2::IXMLDOMDocumentPtr、MSXML2::IXMLDOMElementPtr、MSXML2::IXMLDOMNodeListPtr、
MSXML2::IXMLDOMNodePtr
这几个类之间的关系。这需要大家不断的调试,尝试。欢迎大家交流指正,谢谢大家。

关于项目的源码大家可以参考码云
文章参考:
全面解析XML
菜鸟教程

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值