大家好,欢迎来到IT知识分享网。
VC 使用msxml6.dll动态链接库中的函数读写XML文件
目录
1 引言
2 .dll使用方法
3 常用函数总结
4 实例应用
5 运行效果预览
6 补充说明
7 不足之处
8 更新
引言:
在C:\WINDOWS\system32\下有msxml3.dll 和 msxml6.dll两个动态链接库可以提供操作XML文件的函数。这两个只是版本不同,使用其一即可。
.dll使用方法:
#import “C:\\WINDOWS\\system32\\msxml6.dll”
using namespace MSXML2;
常用函数总结:
a.创建xml文档对象
MSXML2::IXMLDOMDocumentPtr pDoc; //声明xml文档指针
HRESULT hr = pDoc.CreateInstance(__uuidof(MSXML2::DOMDocument30)); //实例化xml文档对象
delete pDoc;
b.创建"Element"、添加"Element"到xml文档对象中
MSXML2::IXMLDOMElementPtr xmlRoot; //声明"Element"指针
pDoc->raw_createElement( (_bstr_t)(char*)"China", &xmlRoot); //创建"Element"
pDoc->raw_appendChild(xmlRoot, NULL); //添加"Element"到xml文档对象中
c.为"Element"添加属性及其属性值
MSXML2::IXMLDOMElementPtr pElemNode;
pDoc->raw_createElement( (_bstr_t)(char*)"City", &childNode);
pElemNode->setAttribute("population","7000"); //1:属性名 2:属性值
d.元素之间的Text操作
MSXML2::IXMLDOMElementPtr pElemNode; //声明一个元素(Element)指针
pElemNode->Puttext("shanghai"); //设置Element之间的Text
CString strElemText = (char*)(_bstr_t)pElemNode->Gettext(); //获取Element之间的Text
e.创建、保存XML文档
pDoc->save(".\\test.xml"); //创建、保存并关闭xml文档
f.加载xml文档
MSXML2::IXMLDOMDocumentPtr pDoc;
HRESULT loadrs = pDoc->load(".\\test.xml"); //加载xml文档
g.查询"Element"
//查询到一个或多个节点,返回第一个节点;如果没有查询的任何节点返回 Nothing
pElemNode = (MSXML2::IXMLDOMElementPtr)(pDoc->selectSingleNode("//City")); //获取元素的信息
h.与xml一起常用的容器
//IXMLDOMNamedNodeMap 是一个结点容器,允许通过name或index访问
//这个容器是通常用于容纳属性
MSXML2::IXMLDOMNamedNodeMapPtr pAttrs = NULL;
//IXMLDOMNodeList 是一个动态容器,也就是说:添加、删除结点
//以及改变结点,都会立即更新容器
MSXML2::IXMLDOMNodeListPtr nodeList = NULL;
//结点指针
MSXML2::IXMLDOMNodePtr pAttrItem = NULL;
j.容器的使用
pElemNode->get_attributes(&pAttrs); //获取pElemNode指向的元素的属性集
pElemNode->get_childNodes(&nodeList); //获取子节点
long nCount, iCount;
//IXMLDOMNamedNodeMapPtr->get_length(long* ) 返回容器中保存属性的个数
pAttrs->get_length(&nCount); //获取结点属性个数 2
//IXMLDOMNodeListPtr->get_length(long* ) 返回容器中保存结点的个数
nodeList->get_length(&iCount); //获取子结点个数 1
for(int i = 0; i < iCount; i++ ) //根据需要可以添加数据到ListControl中
{
CString strElemText = (char*)(_bstr_t)pElemNode->Gettext(); //获取Element标签之间的Text文本,Puttext(LPCSTR)为设置Text文本
m_list.InsertItem(i,strElemText); //1:行索引 2:待添加的字串
for(int j = 0; j < nCount; j++ )
{
pAttrs->get_item(j,&pAttrItem); //获取结点信息-结点
//CString strAttrName = (char*)(_bstr_t)pAttrItem->nodeName; //当前元素(Element)指定属性的名称
CString strAttrVale = (char*)(_bstr_t)pAttrItem->nodeTypedValue; //当前元素指定属性的值
m_list.SetItemText(i,j+1,strAttrVale); //1:行索引 2:列索引 3:待添加的字串
//m_list.SetItemText(i,2,strAttrName);
}
}
k.重要的函数
<1>获取子元素
IXMLDOMNodeListPtr nodelist=NULL;
pElemNode->get_childNodes(&nodeList); //两个函数是等效的
nodelist = pElemNode->GetchildNodes();
保存pElementNode元素下的所有指向子元素的指针。
<book category="children">
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
如pElement指向 <book> </book>,则<title>、<author>、<year>、<price>都是pElement的子结点(或称为子元素)
<2>返回nodeList容器中当前结点(应该是一个游标指针来实现的)的下一个结点。
nodeList->nextNode()
例子:
pElemNode = pDoc->selectSingleNode("//China"); //获取元素的信息
MSXML2::IXMLDOMNodeListPtr nodeList = NULL; //list容器
pElemNode->get_childNodes(&nodeList); //获取子节点
pCurNode = nodeList->nextNode();
<3>pCurNode->GetnextSibling()
Retrieves the next sibling(元素处于同一树层级中) of this node in the parent's child list.如果无此节点,则返回 null。
备注:目前用法没有验证。
可配合下面两个函数使用:
get_firstChild Retrieves the first child of this node.
get_lastChild Retrieves the last child of this node.
<4>获取元素的属性值
<City population="12000" name="Wuhan"> </City>
m_pCurNode指向<City> </City>这个元素
CString varVal = m_pCurNode->getAttribute("population"); //varVal = "12000"
------特别注意--------
<China>
<City population="7000" area="2000">
<Area> QingShan </Area>
</City>
</China>
如果pElemNode当前指向<City> </City>这个节点,
那么
CString strElemText = (char*)(_bstr_t)pElemNode->Gettext();
strElemText的值就是“QingShan”
实例应用
应用1:
测试用的xml文件-- test.xml
<China>
<City population="7000" area="2000">shanghai</City>
<City population="39999" area="3322">beijing</City>
<City population="5000" area="40000">Wuhan</City>
</China>
#import "C:\\WINDOWS\\system32\\msxml6.dll"
using namespace MSXML2;
//创建xml文件
void COperateXMLDlg::OnBtnCreate()
{
// TODO: Add your control notification handler code here
::CoInitialize(NULL); //初始化COM
MSXML2::IXMLDOMDocumentPtr pDoc;
MSXML2::IXMLDOMElementPtr xmlRoot;
HRESULT hr = pDoc.CreateInstance(__uuidof(MSXML2::DOMDocument30));
if(!SUCCEEDED(hr))
{
MessageBox("XML文件创建失败");
return ;
}
pDoc->raw_createElement( (_bstr_t)(char*)"China", &xmlRoot);
pDoc->raw_appendChild(xmlRoot, NULL);
MSXML2::IXMLDOMElementPtr pElemNode;
pDoc->raw_createElement( (_bstr_t)(char*)"City", &pElemNode);
pElemNode->Puttext("shanghai");
pElemNode->setAttribute("population","7000");
pElemNode->setAttribute("area","2000");
xmlRoot->appendChild(pElemNode);
pDoc->raw_createElement( (_bstr_t)(char*)"City", &pElemNode);
pElemNode->Puttext("beijing");
pElemNode->setAttribute("population","39999");
pElemNode->setAttribute("area","3322");
xmlRoot->appendChild(pElemNode);
pDoc->raw_createElement( (_bstr_t)(char*)"City", &pElemNode);
pElemNode->Puttext("Wuhan");
pElemNode->setAttribute("population","5000");
pElemNode->setAttribute("area","40000");
xmlRoot->appendChild(pElemNode);
pDoc->save(".\\test.xml");
//如何释放pDoc占有的内存
::CoUninitialize(); //卸载COM
}
//读取xml文件
void COperateXMLDlg::OnBtnGetXML()
{
// TODO: Add your control notification handler code here
::CoInitialize(NULL); //初始化COM
m_list.DeleteAllItems(); //m_list是ListControl控件绑定的一个Value类型的变量
MSXML2::IXMLDOMDocumentPtr pDoc; //创建一个xml文档指针
HRESULT hr = pDoc.CreateInstance(__uuidof(MSXML2::DOMDocument30)); //实例化文档指针
if(!SUCCEEDED(hr))
{
MessageBox("加载XML错误");
return ;
}
VARIANT_BOOL loadrs = pDoc->load(".\\test.xml"); //加载xml文档
if( -1 != loadrs ) //查看load函数的定义(msxml3.tli)发现返回类型是VARIANT_BOOL,-1 == TRUE、0 == FALSE
MessageBox("加载XML错误");
MSXML2::IXMLDOMElementPtr pElemNode; //声明一个元素(Element)指针
// 在树中查找名为City的节点," // "表示在任意一层查找
//selectSingleNode方法如果查询到一个或多个节点,返回第一个节点;如果没有查询的任何节点返回 Nothing
//SelectNodes("//City")返回一个NodeList对象,可能包含多个节点
pElemNode = (MSXML2::IXMLDOMElementPtr)(pDoc->selectSingleNode("//China")); //获取元素的信息
//MSXML2::DOMNodeType nodeType; //结点类型
//childNode->get_nodeType(&nodeType);
//IXMLDOMNamedNodeMap 是一个结点容器,允许通过name或index访问
//这个容器是通常用于容纳属性
MSXML2::IXMLDOMNamedNodeMapPtr pAttrs = NULL;
//IXMLDOMNodeList 是一个动态容器,也就是说:添加、删除结点
//以及改变结点,都会立即更新容器
MSXML2::IXMLDOMNodeListPtr nodeList = NULL;
//结点指针
MSXML2::IXMLDOMNodePtr pAttrItem = NULL;
//pElemNode->get_attributes(&pAttrs); //获取pElemNode指向的元素的属性集
pElemNode->get_childNodes(&nodeList); //获取子节点
long nCount, iCount;
MSXML2::IXMLDOMElementPtr pCurNode;
//IXMLDOMNamedNodeMapPtr->get_length(long* ) 返回容器中保存属性的个数
//pAttrs->get_length(&nCount); //获取结点属性个数 2
//IXMLDOMNodeListPtr->get_length(long* ) 返回容器中保存结点的个数
nodeList->get_length(&iCount); //获取子结点(此处指"China"元素下的子元素"City")个数 2
for(int i = 0; i < iCount; i++ ) //根据需要可以添加数据到ListControl中
{
pCurNode = nodeList->nextNode();
CString strPoupula = pCurNode->getAttribute("population");
CString strArea= pCurNode->getAttribute("area");
CString strElemText = (char*)(_bstr_t)pCurNode->Gettext(); //获取Element标签之间的Text文本,Puttext(LPCSTR)为设置Text文本
m_list.InsertItem(i,strElemText); //1:行索引 2:待添加的字串
m_list.SetItemText(i,1,strPoupula); //1:行索引 2:列索引 3:待添加的字串
m_list.SetItemText(i,2,strArea);
}
::CoUninitialize(); //卸载COM
}
运行效果预览:
实例下载链接,上传到CSDN的资源库中,0分资源,支持VC6和VS2010IDE。下载此工程实例–VC6/VS2010
应用2:
<China>
<Provious name="Hubei">
<City population="1" area="100">YiChang</City>
<City population="2" area="40000">Wuhan</City>
</Provious>
<Provious name="HeBei">
<City population="39999" area="3322">beijing</City>
<City population="39999" area="3322">QingDao</City>
</Provious>
<Provious name="JiangSu">
<City population="7000" area="2000">shanghai</City>
</Provious>
</China>
void COperateXMLDlg::OnBtnGetXML()
{
// TODO: Add your control notification handler code here
::CoInitialize(NULL); //初始化COM
m_list.DeleteAllItems();
MSXML2::IXMLDOMDocumentPtr pDoc; //创建一个xml文档指针
HRESULT hr = pDoc.CreateInstance(__uuidof(MSXML2::DOMDocument30)); //实例化文档指针
if(!SUCCEEDED(hr))
{
MessageBox("加载XML错误");
return ;
}
VARIANT_BOOL loadrs = pDoc->load(".\\test.xml"); //加载xml文档
if( -1 != loadrs ) //查看load函数的定义(msxml3.tli)发现返回类型是VARIANT_BOOL,-1 == TRUE、0 == FALSE
MessageBox("加载XML错误");
MSXML2::IXMLDOMElementPtr pElemNode; //声明一个元素(Element)指针
// 在树中查找名为City的节点," // "表示在任意一层查找
pElemNode = (MSXML2::IXMLDOMElementPtr)(pDoc->selectSingleNode("//China")); //获取元素的信息
MSXML2::IXMLDOMNamedNodeMapPtr pAttrs = NULL;
MSXML2::IXMLDOMNodeListPtr nodeList = NULL;
MSXML2::IXMLDOMNodePtr pAttrItem = NULL;
pElemNode->get_childNodes(&nodeList); //获取子节点
long nCount, iCount,index=0;
MSXML2::IXMLDOMElementPtr pCurNode,pChildCurNode;
nodeList->get_length(&iCount);
for(int i = 0; i < iCount; i++ ) //根据需要可以添加数据到ListControl中
{
pCurNode = nodeList->nextNode();
MSXML2::IXMLDOMNodeListPtr ChildnodeList = NULL;
pCurNode->get_childNodes(&ChildnodeList);
ChildnodeList->get_length(&nCount);
for(int j=0; j < nCount; j++ )
{
pChildCurNode = ChildnodeList->nextNode();
CString strPoupula = pChildCurNode->getAttribute("population");
CString strArea= pChildCurNode->getAttribute("area");
CString strElemText = (char*)(_bstr_t)pChildCurNode->Gettext(); //获取Element标签之间的Text文本,Puttext(LPCSTR)为设置Text文本
m_list.InsertItem(index,strElemText); //1:行索引 2:待添加的字串
m_list.SetItemText(index,1,strPoupula);
m_list.SetItemText(index,2,strArea);
index++;
}
}
::CoUninitialize(); //卸载COM
}
补充说明:
项目中导入msxml3.dll或是msxml6.dll经过编译后会项目目录下生成两个文件msxml3.tlh和msxml3.tli(msxml6.tlh和msxml6.tli),绝大部分操作xml文件的函数都定义在msxml3.tli中,可在工程中选中函数名称右键查看其定义便会一目了然。
不足之处:
目前还没在Unicode字符集下成功的读取过,只要xml文件中包含Unicode字符,加载函数load(“test.xml”)就会返回加载失败的值。目前还没有找到原因。留此待已解决,Mark20131228.
问题解决了,在xml文件中少写了文件头“ <?xml version=”1.0″ encoding=”gb2312″?> ”造成上面的load函数加载失败。Mark:20131231
更新:
20140311更 — 解决每次写入信息到xml文件都是全覆盖模式,如此xml文件头<?xml version=”1.0″ encoding=”gb2312″?>也会被覆盖掉,这样会引起“不足之处”里面提到的编码问题。找了很久没有找专门供写入xml文件头<?xml version=”1.0″ encoding=”gb2312″?>的函数,于是自己动手写了一函数解决这个问题。
解决方法是:先将xml文件中原有的信息(此时不包括xml文件头)读取出来保存到一个字符串变量中,接着将<?xml version=”1.0″ encoding=”gb2312″?>和字符串变量中的信息串接起来,然后再写入到xml文件中。代码如下
BOOL AddXMLHeadString()
{
//由于必须从文件最开头添加字符会覆盖掉原来的字符,所以采用下面的方法解决这个问题
//先把原始文件读取出来,然后加上xml的文件头字符串,再写回去。
//char readBuf[]
CString fileName(_T(".\\test.xml") );
CStdioFile myfile;
CFileException fileExcp;
BOOL bRet = myfile.Open(fileName,CFile::typeText|CFile::modeReadWrite,&fileExcp);
if( bRet )
{
/*一个稀奇事:如果1 、2 部分调换顺序就会使myfile.Read读取文件内容异常,但是两者的顺序是无关紧要的*/
//1.读取原有文件的内容
UINT fileLen = myfile.GetLength();
char * readBuf = new char[fileLen];
myfile.Read(readBuf,fileLen);
//2.如果已经有了XML文件头就不添加
CString strXMLHeader;
myfile.ReadString(strXMLHeader);
CString xmlHeader = _T("<?xml version=\"1.0\" encoding=\"gb2312\"?>");
if( xmlHeader== strXMLHeader )
return TRUE;
myfile.Close();
//3.合成完整的xml文件
CStdioFile newFile;
BOOL bRetNewFile = newFile.Open(fileName,CFile::typeText|CFile::modeCreate|CFile::modeReadWrite,&fileExcp);
if( bRetNewFile )
{
newFile.Seek(0,CFile::end);
newFile.WriteString(_T("<?xml version=\"1.0\" encoding=\"gb2312\"?>\n"));
newFile.Seek(0,CFile::end);
newFile.Write(readBuf,fileLen);
newFile.Seek(-1,CFile::end); //在文件末尾莫名其妙的多了一个‘?’,所以用了‘\n’将这个问号覆盖了,不然读取XML时会出错
newFile.WriteString(_T("\n"));
}
}
char *errinfo = new char [255];
fileExcp.GetErrorMessage(errinfo,255);
delete[] errinfo;
return bRet;
}
2017.04.25 更新
主推C++语法实现的TinyXML。比起上面介绍的MSXML,TinyXML又简单又好用,而且接口文档/资料丰富。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/23991.html