最近在做项目的过程中,需要解析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
这几个类之间的关系。这需要大家不断的调试,尝试。欢迎大家交流指正,谢谢大家。