读取和设置xml配置文件是最常用的操作,试用了几个C++的XML解析器,个人感觉TinyXML是使用起来最舒服的,因为它的API接口和Java的十分类似,面向对象性很好。
TinyXML是一个开源的解析XML的解析库,能够用于C++,能够在Windows或Linux中编译。这个解析库的模型通过解析XML文件,然后在内存中生成DOM模型,从而让我们很方便的遍历这棵XML树。
DOM模型即文档对象模型,是将整个文档分成多个元素(如书、章、节、段等),并利用树型结构表示这些元素之间的顺序关系以及嵌套包含关系。
如下是一个XML片段:
file:///C:/Users/MHAPDR~1/AppData/Local/Temp/enhtmlclip/Image.gif <Persons>
<Person ID="1">
<name>周星星</name>
<age>20</age>
</Person>
<Person ID="2">
<name>白晶晶</name>
<age>18</age>
</Person>
</Persons>
在TinyXML中,根据XML的各种元素来定义了一些类:
TiXmlBase:整个TinyXML模型的基类。
TiXmlAttribute:对应于XML中的元素的属性。
TiXmlNode:对应于DOM结构中的节点。
TiXmlComment:对应于XML中的注释
TiXmlDeclaration:对应于XML中的申明部分,即<?versiong="1.0" ?>。
TiXmlDocument:对应于XML的整个文档。
TiXmlElement:对应于XML的元素。
TiXmlText:对应于XML的文字部分
TiXmlUnknown:对应于XML的未知部分。
TiXmlHandler:定义了针对XML的一些操作。
TinyXML是个解析库,主要由DOM模型类(TiXmlBase、TiXmlNode、TiXmlAttribute、TiXmlComment、TiXmlDeclaration、TiXmlElement、TiXmlText、TiXmlUnknown)和操作类(TiXmlHandler)构成。它由两个头文件(.h文件)和四个CPP文件(.cpp文件)构成,用的时候,只要将(tinyxml.h、tinystr.h、tinystr.cpp、tinyxml.cpp、tinyxmlerror.cpp、tinyxmlparser.cpp)导入工程就可以用它的东西了。如果需要,可以将它做成自己的DLL来调用。举个例子就可以说明一切。。。
对应的XML文件:
<Persons>
<Person ID="1">
<name>phinecos</name>
<age>22</age>
</Person>
</Persons>
读写XML文件的程序代码:
#include <iostream>
#include "tinyxml.h"
#include "tinystr.h"
#include <string>
#include <windows.h>
#include <atlstr.h>
using namespace std;
CString GetAppPath()
file:///C:/Users/MHAPDR~1/AppData/Local/Temp/enhtmlclip/Image(1).gif{//获取应用程序根目录
file:///C:/Users/MHAPDR~1/AppData/Local/Temp/enhtmlclip/Image(2).gif TCHAR modulePath[MAX_PATH];
GetModuleFileName(NULL, modulePath, MAX_PATH);
CString strModulePath(modulePath);
strModulePath = strModulePath.Left(strModulePath.ReverseFind(_T('\\')));
return strModulePath;
file:///C:/Users/MHAPDR~1/AppData/Local/Temp/enhtmlclip/Image(3).gif}
bool CreateXmlFile(string& szFileName)
{//创建xml文件,szFilePath为文件保存的路径,若创建成功返回true,否则false
try
file:///C:/Users/MHAPDR~1/AppData/Local/Temp/enhtmlclip/Image(4).gif {
//创建一个XML的文档对象。
TiXmlDocument *myDocument = new TiXmlDocument();
//创建一个根元素并连接。
TiXmlElement *RootElement = new TiXmlElement("Persons");
myDocument->LinkEndChild(RootElement);
//创建一个Person元素并连接。
TiXmlElement *PersonElement = new TiXmlElement("Person");
RootElement->LinkEndChild(PersonElement);
//设置Person元素的属性。
PersonElement->SetAttribute("ID", "1");
//创建name元素、age元素并连接。
TiXmlElement *NameElement = new TiXmlElement("name");
TiXmlElement *AgeElement = new TiXmlElement("age");
PersonElement->LinkEndChild(NameElement);
PersonElement->LinkEndChild(AgeElement);
//设置name元素和age元素的内容并连接。
TiXmlText *NameContent = new TiXmlText("周星星");
TiXmlText *AgeContent = new TiXmlText("22");
NameElement->LinkEndChild(NameContent);
AgeElement->LinkEndChild(AgeContent);
CString appPath = GetAppPath();
string seperator = "\\";
string fullPath = appPath.GetBuffer(0) +seperator+szFileName;
myDocument->SaveFile(fullPath.c_str());//保存到文件
file:///C:/Users/MHAPDR~1/AppData/Local/Temp/enhtmlclip/Image(5).gif }
catch (string& e)
{
return false;
}
return true;
}
bool ReadXmlFile(string& szFileName)
{//读取Xml文件,并遍历
try
{
CString appPath = GetAppPath();
string seperator = "\\";
string fullPath = appPath.GetBuffer(0) +seperator+szFileName;
//创建一个XML的文档对象。
TiXmlDocument *myDocument = new TiXmlDocument(fullPath.c_str());
myDocument->LoadFile();
//获得根元素,即Persons。
TiXmlElement *RootElement = myDocument->RootElement();
//输出根元素名称,即输出Persons。
cout << RootElement->Value() << endl;
//获得第一个Person节点。
TiXmlElement *FirstPerson = RootElement->FirstChildElement();
//获得第一个Person的name节点和age节点和ID属性。
TiXmlElement *NameElement = FirstPerson->FirstChildElement();
TiXmlElement *AgeElement = NameElement->NextSiblingElement();
TiXmlAttribute *IDAttribute = FirstPerson->FirstAttribute();
//输出第一个Person的name内容,即周星星;age内容,即;ID属性,即。
cout << NameElement->FirstChild()->Value() << endl;
cout << AgeElement->FirstChild()->Value() << endl;
cout << IDAttribute->Value()<< endl;
}
catch (string& e)
{
return false;
}
return true;
}
int main()
{
string fileName = "info.xml";
CreateXmlFile(fileName);
ReadXmlFile(fileName);
}
写本文的目的是为了方便大家了解C++ MSXML操作方法。
当然,C++中对MSXML的调用有多种,本文采用的方法是完全参照MSXML SDK提供的文档进行操作。
如果有什么错误,欢迎指正。
代码框架是基于vs2008 MFC 对话框程序(UNICODE)。对话框程序需要读者自己创建。
[cpp] view plain copy
- #include <msxml6.h>
- #include <comutil.h>
- #pragma comment(lib, "comsuppwd.lib")
- void CXmlSampleDlg::OnBnClickedButton1()//按钮事件
- {
- CoInitialize(NULL);
- CComPtr<IXMLDOMDocument> spXmldoc;
- HRESULT hr = spXmldoc.CoCreateInstance(L"MSXML2.DOMDocument.6.0");
-
- if(SUCCEEDED(hr))
- {
- VARIANT_BOOL isSuccessFul;
- CComVariant varXmlFile(L"a.xml");
-
- spXmldoc->put_async(VARIANT_FALSE);
- HRESULT hr= spXmldoc->load(varXmlFile, &isSuccessFul);
-
- if(isSuccessFul==VARIANT_TRUE)
- {
- CComBSTR bstrXml;
- CComPtr<IXMLDOMElement> spRoot=NULL;
- CComPtr<IXMLDOMElement> spTheBook=NULL;
- CComPtr<IXMLDOMElement> spTheElem=NULL;
- CComPtr<IXMLDOMNode> spNewNode=NULL;
-
- hr = spXmldoc->get_documentElement(&spRoot);
- spRoot->get_xml(&bstrXml);
- AfxMessageBox(L"1, 原始的XML");
- AfxMessageBox(bstrXml);
-
-
- spXmldoc->createElement(L"book", &spTheBook);
- spXmldoc->createElement(L"name", &spTheElem);
- spTheElem->put_text(L"新书");
- spTheBook->appendChild(spTheElem, &spNewNode);
- spTheElem.Release();
- spNewNode.Release();
-
- spXmldoc->createElement(L"price", &spTheElem);
- spTheElem->put_text(L"20");
- spTheBook->appendChild(spTheElem, &spNewNode);
- spTheElem.Release();
- spNewNode.Release();
-
- spXmldoc->createElement(L"memo", &spTheElem);
- spTheElem->put_text(L"新书的更好看。");
- spTheBook->appendChild(spTheElem, &spNewNode);
- spNewNode.Release();
- spTheElem.Release();
-
- spRoot->appendChild(spTheBook, &spNewNode);
- spNewNode.Release();
- spTheBook.Release();
-
- spRoot->get_xml(&bstrXml);
- AfxMessageBox(L"2, 新建一本书完成");
- AfxMessageBox(bstrXml);
- ////--- 新建一本书完成 ----
-
-
- ////--- 下面对《哈里波特》做一些修改。 ----
- ////--- 查询找《哈里波特》----
- CComPtr<IXMLDOMNode> spTheNode=NULL;
- spRoot->selectSingleNode(L"/books/book[name='哈里波特']", &spTheNode);
- hr=spTheNode.QueryInterface(&spTheBook);
- spTheNode.Release();
-
- spTheBook->get_xml(&bstrXml);
- AfxMessageBox(L"3,《哈里波特》的XML");
- AfxMessageBox(bstrXml);
-
- ////--- 此时修改这本书的价格 -----
- CComPtr<IXMLDOMNodeList> spNodeList=NULL;
- CComPtr<IXMLDOMNode> spListItem=NULL;
- spTheBook->get_childNodes(&spNodeList);
- spNodeList->get_item(1, &spListItem);
- spNodeList.Release();
- spListItem->put_text(L"15");
-
- ////--- 另外还想加一个属性id,值为B01 ----
- CComVariant varId(L"B01");
- spTheBook->setAttribute(L"id", varId);
- varId.Clear();
-
- spTheBook->get_xml(&bstrXml);
- spTheBook.Release();
- AfxMessageBox(L"4, 对《哈里波特》修改完成。");
- AfxMessageBox(bstrXml);
- ////--- 对《哈里波特》修改完成。 ----
-
-
- ////--- 要用id属性删除《三国演义》这本书 ----
- spRoot->selectSingleNode(L"/books/book[@id='B02']", &spTheNode);
- hr=spTheNode.QueryInterface(&spTheBook);
- spTheNode.Release();
-
- spTheBook->get_xml(&bstrXml);
- AfxMessageBox(L"5, 《三国演义》的XML");
- AfxMessageBox(bstrXml);
-
- CComPtr<IXMLDOMNode> spParentNode=NULL;
- spTheBook->get_parentNode(&spParentNode);
- spParentNode->removeChild(spTheBook, &spTheNode);
- spTheNode.Release();
- spParentNode.Release();
- spTheBook.Release();
-
- spRoot->get_xml(&bstrXml);
- AfxMessageBox(L"6, 删除《三国演义》后的XML");
- AfxMessageBox(bstrXml);
-
-
- ////--- 再将所有价格低于10的书删除 ----
- spRoot->selectNodes(L"/books/book[price<10]", &spNodeList);
- CComQIPtr<IXMLDOMSelection> spSomeBooks=spNodeList;
- spNodeList.Release();
-
- spSomeBooks->removeAll();
- spSomeBooks.Release();
-
- spXmldoc->get_xml(&bstrXml);
- AfxMessageBox(L"7, 已经删除价格低于10的书");
- AfxMessageBox(bstrXml);
-
- spRoot.Release();
- bstrXml.Empty();
-
- //spXmldoc->save(varXmlFile); //保存xml。
- }
- varXmlFile.ClearToZero();
- }
-
- spXmldoc.Release();
-
- CoUninitialize();
- }
a.xml
[xhtml] view plain copy
- <?xml version="1.0" encoding="UTF-8"?>
- <books>
- <book>
- <name>哈里波特</name>
- <price>10</price>
- <memo>这是一本很好看的书。</memo>
- </book>
- <book id="B02">
- <name>三国演义</name>
- <price>10</price>
- <memo>四大名著之一。</memo>
- </book>
- <book id="B03">
- <name>水浒</name>
- <price>6</price>
- <memo>四大名著之一。</memo>
- </book>
- <book id="B04">
- <name>红楼</name>
- <price>5</price>
- <memo>四大名著之一。</memo>
- </book>
- </books>
最近使用TinyXML进行C++ XML解析,感觉使用起来比较简单,很容易上手,本文给出一个使用TinyXML进行XML解析的简单例子,很多复杂的应用都可以基于本例子的方法来完成。以后的文章里会讲解使用Xerces进行C++ XML解析的例子,希望大家一起交流。
TinyXML是一个开源的解析XML的解析库,能够用于C++,能够在Windows或Linux中编译。这个解析库的模型通过解析XML文件,然后在内存中生成DOM模型,从而让我们很方便的遍历这棵XML树。
DOM模型即文档对象模型,是将整个文档分成多个元素(如书、章、节、段等),并利用树型结构表示这些元素之间的顺序关系以及嵌套包含关系。
首先从网上下载TinyXML的库,文件夹的名字是TinyXpath,在工程里做如下配置:
在附加包含路径里添加:你的tinyxpath路径/tinyxpath/include
在附加库路径里添加:你的tinyxpath路径/tinyxpath/lib
在对象/库路径里添加:tinyxpathd.lib,如果使用release版本,则是tinyxpath.lib。
另外,由于我开发的项目是多线程的,所以设置了多线程的环境,因此使用TinyXML没有出现问题。本人将TinyXML写在一个单独的C++工程进行测试,发现如果不设置多线程的环境,会出现链接错误。我觉得原因可能是TinyXML使用了多线程环境,因此需要设置多线程的环境。在工程/设置下的C/C++选项卡中,选择Code Generation,在Use run-time library中选择Debug MultiThreaed DLL即可。
本例的XML文件Students.xml如下:
<Class name="计算机软件班">
<Students>
<student name="张三" studentNo="13031001" sex="男" age="22">
<phone>88208888</phone>
<address>西安市太白南路二号</address>
</student>
<student name="李四" studentNo="13031002" sex="男" age="20">
<phone>88206666</phone>
<address>西安市光华路</address>
</student>
</Students>
</Class>
程序代码XmlParseExample.cpp如下所示:
#include <iostream>
#include <string>
#include <tinyxml.h>
using std::string;
int main()
{
TiXmlDocument* myDocument = new TiXmlDocument();
myDocument->LoadFile("Students.xml");
TiXmlElement* rootElement = myDocument->RootElement(); //Class
TiXmlElement* studentsElement = rootElement->FirstChildElement(); //Students
TiXmlElement* studentElement = studentsElement->FirstChildElement(); //Students
while ( studentElement ) {
TiXmlAttribute* attributeOfStudent = studentElement->FirstAttribute(); //获得student的name属性
while ( attributeOfStudent ) {
std::cout 《 attributeOfStudent->Name() 《 " : " 《 attributeOfStudent->Value() 《 std::endl;
attributeOfStudent = attributeOfStudent->Next();
}
TiXmlElement* phoneElement = studentElement->FirstChildElement();//获得student的phone元素
std::cout 《 "phone" 《 " : " 《 phoneElement->GetText() 《 std::endl;
TiXmlElement* addressElement = phoneElement->NextSiblingElement();
std::cout 《 "address" 《 " : " 《 phoneElement->GetText() 《 std::endl;
studentElement = studentElement->NextSiblingElement();
}
return 0;
}
程序运行结果如下:
name : 张三
studentNo : 13031001
sex : 男
age : 22
phone : 88208888
address : 88208888
name : 李四
studentNo : 13031002
sex : 男
age : 20
phone : 88206666
address : 88206666
本例中使用的是对xml文件进行解析,很容易掌握,但是很多开发人员不知道如何对xml 字符流(非xml文件)进行解析,我看了TinyXML提供的源代码,里面可以使用如下方法对xml流解析。对应于上例,代码如下:
string xmlString =
"<Class name=\"计算机软件班\">
<Students>
<student name=\"张三\" studentNo=\"13031001\" sex=\"男\" age=\"22\">
<phone>88208888</phone>
<address>西安市太白南路二号</address>
</student>
<student name=\"李四\" studentNo=\"13031002\" sex=\"男\" age=\"20\">
<phone>88206666</phone>
<address>西安市光华路</address>
</student>
</Students>
</Class>";
TiXmlDocument* myDocument = new TiXmlDocument();
myDocument->Parse(xmlString.c_str());
使用Parse函数就可以解析XML字符流了,这是很多开发者不太熟悉的情况。
如果开发者开发特定应用,就可以使用上述类似方法,可能不需要完全处理每一个属性,比如可以对属性名进行判断,只处理自己需要的属性,或者自己需要的xml元素。还可以使用TinyXML的方法创建xml元素和xml属性,或者设置xml元素和属性对应的值,等等,如果读者想要类似的例子,可以留言写出。
下面介绍TinyXML的一些类。在TinyXML中,根据XML的各种元素来定义了一些类:
TiXmlBase:整个TinyXML模型的基类。
TiXmlAttribute:对应于XML中的元素的属性。
TiXmlNode:对应于DOM结构中的节点。
TiXmlComment:对应于XML中的注释
TiXmlDeclaration:对应于XML中的申明部分,<?versiong="1.0" ?>。
TiXmlDocument:对应于XML的整个文档。
TiXmlElement:对应于XML的元素。
TiXmlText:对应于XML的文字部分
TiXmlUnknown:对应于XML的未知部分。
TiXmlHandler:定义了针对XML的一些操作。