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;
- }
http://blog.csdn.net/qq2399431200/article/details/17583171
http://z.download.csdn.net/detail/qq2399431200/7022299