TinyXML快速入門(一)(二)(三)
Visual C++ TinyXml快速入門(一)
xml檔案本質就是小型的資料庫,換個角度來說就是,你對資料庫有什麼操作你對xml檔案就應能實現什麼操作。一般而言,對資料庫的操作包括以下幾種:新建資料庫、查詢資料庫、修改資料庫和刪除資料庫。那麼對應xml檔案就是新建xml檔案、查詢xml檔案的指定節點的值,修改xml檔案中節點的值和刪除xml檔案中節點的值。
首先我們認識一下xml檔案有哪幾種形式。下面我列出一些常用的xml檔案的形式:
example1.xml:
<?xml version="1.0" ?>
<Hello>World</Hello>
example2.xml:
<?xml version="1.0" ?>
<poetry>
<verse>
Alas
Great World
Alas (again)
</verse>
</poetry>
example3.xml:
<?xml version="1.0" ?>
<shapes>
<circle name="int-based" x="20" y="30" r="50" />
<point name="float-based" x="3.5" y="52.1" />
</shapes>
example4.xml:
<?xml version="1.0" ?>
<MyApp>
<Messages>
<Welcome>Welcome to MyApp</Welcome>
<Farewell>Thank you for using MyApp</Farewell>
</Messages>
<Windows>
<Window name="MainFrame" x="5" y="15" w="400" h="250" />
</Windows>
<Connection ip="192.168.0.1" timeout="123.456000" />
</MyApp>
上面的例子摘自《TinyXML Tutorial 中文指南》。上面有四個例子,你看到了xml檔案的幾種表現形式?我看到了本質來說不過是兩種表現形式:屬性值值在尖括號內,如<Window name="MainFrame" x="5" y="15" w="400" h="250" />和文字在尖括號外,如<Welcome>Welcome to MyApp</Welcome>。
鑑於example4.xml比較複雜,下面我將以此為例介紹tinyxml的使用。
Tinyxml使用了兩種編譯選擇:使用標準C的char *型別或者使用STL中的std::string,其中使用前處理器TIXML_USE_STL進行控制,即新增了TIXML_USE_STL為使用std::string的。鑑於STL的廣泛使用以及其強大功能,下面我以使用std::string的tinyxml說明。
首先使用VS 2010開啟tinyxmlSTL.dsp的工程檔案,將其編譯成一個靜態庫,debug版本為:tinyxmld_STL.lib,然後開始測試tinyxml庫。我的測試計劃是這樣的:首先使用tinyxml庫建立example4.xml,然後將其讀出來,然後查詢指定節點的屬性或文字,再修改example4.xml(修改其中的一些節點值和刪除其中一個節點,增加一個節點),然後再讀出來以判斷是否修改成功。具體是在VS 2010上新建一個控制檯工程:Test,注意使用多位元組字符集進行編譯,同時新增。首先是建立xml檔案的程式碼:
/*!
* /brief 建立xml檔案。
*
* /param XmlFile xml檔案全路徑。
* /return 是否成功。true為成功,false表示失敗。
*/
bool CreateXml(std::string XmlFile)
{
// 定義一個TiXmlDocument類指標
TiXmlDocument *pDoc = new TiXmlDocument;
if (NULL==pDoc)
{
return false;
}
TiXmlDeclaration *pDeclaration = new TiXmlDeclaration(_T("1.0"),_T(""),_T(""));
if (NULL==pDeclaration)
{
return false;
}
pDoc->LinkEndChild(pDeclaration);
// 生成一個根節點:MyApp
TiXmlElement *pRootEle = new TiXmlElement(_T("MyApp"));
if (NULL==pRootEle)
{
return false;
}
pDoc->LinkEndChild(pRootEle);
// 生成子節點:Messages
TiXmlElement *pMsg = new TiXmlElement(_T("Messages"));
if (NULL==pMsg)
{
return false;
}
pRootEle->LinkEndChild(pMsg);
// 生成子節點:Welcome
TiXmlElement *pWelcome = new TiXmlElement(_T("Welcome"));
if (NULL==pWelcome)
{
return false;
}
pMsg->LinkEndChild(pWelcome);
// 設定Welcome節點的值
std::string strValue = _T("Welcome to MyApp");
TiXmlText *pWelcomeValue = new TiXmlText(strValue);
pWelcome->LinkEndChild(pWelcomeValue);
// 生成子節點:Farewell
TiXmlElement *pFarewell = new TiXmlElement(_T("Farewell"));
if (NULL==pFarewell)
{
return false;
}
pMsg->LinkEndChild(pFarewell);
// 設定Farewell節點的值
strValue = _T("Thank you for using MyApp");
TiXmlText *pFarewellValue = new TiXmlText(strValue);
pFarewell->LinkEndChild(pFarewellValue);
// 生成子節點:Windows
TiXmlElement *pWindows = new TiXmlElement(_T("Windows"));
if (NULL==pWindows)
{
return false;
}
pRootEle->LinkEndChild(pWindows);
// 生成子節點:Window
TiXmlElement *pWindow = new TiXmlElement(_T("Window"));
if (NULL==pWindow)
{
return false;
}
pWindows->LinkEndChild(pWindow);
// 設定節點Window的值
pWindow->SetAttribute(_T("name"),_T("MainFrame"));
pWindow->SetAttribute(_T("x"),_T("5"));
pWindow->SetAttribute(_T("y"),_T("15"));
pWindow->SetAttribute(_T("w"),_T("400"));
pWindow->SetAttribute(_T("h"),_T("250"));
// 生成子節點:Window
TiXmlElement *pConnection = new TiXmlElement(_T("Connection"));
if (NULL==pConnection)
{
return false;
}
pRootEle->LinkEndChild(pConnection);
// 設定節點Connection的值
pConnection->SetAttribute(_T("ip"),_T("192.168.0.1"));
pConnection->SetAttribute(_T("timeout"),_T("123.456000"));
pDoc->SaveFile(XmlFile);
return true;
}
不知你注意到上面的規律沒有?首先父節點連線位元組點使用函式LinkEndChild,使用方法是:pParentNode-> LinkEndChild(pChild);其次設定類似這種結構<Window name="MainFrame" x="5" y="15" w="400" h="250" />採用SetAttribute函式,這個函式有兩個引數,前一個參數列示鍵,後一個參數列示鍵值,設定<Farewell>Thank you for using MyApp</Farewell>這種結構採用TiXmlText類,使用LinkEndChild函式進行連結。
上面是建立xml檔案的程式碼,下面介紹讀取xml檔案的程式碼。列印整個xml檔案的程式碼很簡單,程式碼如下:
/*!
* /brief 列印xml檔案。
*
* /param XmlFile xml檔案全路徑。
* /return 是否成功。true為成功,false表示失敗。
*/
bool PaintXml(std::string XmlFile)
{
// 定義一個TiXmlDocument類指標
TiXmlDocument *pDoc = new TiXmlDocument();
if (NULL==pDoc)
{
return false;
}
pDoc->LoadFile(XmlFile);
pDoc->Print();
return true;
}
下次介紹使用tinyxml庫對xml檔案進行查詢指定節點、刪除指定節點、修改指定節點和增加節點的用法。
Visual C++ TinyXml快速入門(二)
在 Visual C++ TinyXml快速入門(一)中,我介紹了使用TinyXml庫如何建立和列印xml檔案,下面我介紹使用tinyxml庫對xml檔案進行一系列的操作,包括獲取xml檔案宣告,查詢指定節點、刪除指定節點、修改指定節點和增加節點的用法。在《TinyXml快速入門(一)》中我們知道xml檔案中的一個節點元素實際包含兩種值:屬性和文字。其中屬性在我看來可以看作是STL中的map,一個屬性帶一個屬性值,map中也是一個鍵帶一個鍵值。因此查詢指定節點、刪除指定節點和增加節點必然是需要實現兩種方法,刪除指定節點只需要實現一種方法。鑑於內容較多,在本文中介紹獲取xml檔案宣告,查詢指定節點、刪除指定節點的做法,修改指定節點和增加節點的做法在後續的文章介紹。
首先是獲取xml檔案宣告。xml檔案宣告包括三方面的內容:Version、Standalone和Encoding。其原始碼如下:
/*!
* /brief 獲取xml檔案的宣告。
*
* /param XmlFile xml檔案全路徑。
* /param strVersion Version屬性值
* /param strStandalone Standalone屬性值
* /param strEncoding Encoding屬性值
* /return 是否成功。true為成功,false表示失敗。
*/
bool GetXmlDeclare(std::string XmlFile,
std::string &strVersion,
std::string &strStandalone,
std::string &strEncoding)
{
// 定義一個TiXmlDocument類指標
TiXmlDocument *pDoc = new TiXmlDocument();
if (NULL==pDoc)
{
return false;
}
pDoc->LoadFile(XmlFile);
TiXmlNode* pXmlFirst = pDoc->FirstChild();
if (NULL != pXmlFirst)
{
TiXmlDeclaration* pXmlDec = pXmlFirst->ToDeclaration();
if (NULL != pXmlDec)
{
strVersion = pXmlDec->Version();
strStandalone = pXmlDec->Standalone();
strEncoding = pXmlDec->Encoding();
}
}
return true;
}
我們發現無論查詢節點、刪除節點、修改節點和增加節點,其實都離不開一個函式,就是根據節點名獲取相關節點指標。那麼我們就先實現一個根據節點名獲取節點指標的函式:
/*!
* /brief 通過根節點和節點名獲取節點指標。
*
* /param pRootEle xml檔案的根節點。
* /param strNodeName 要查詢的節點名
* /param Node 需要查詢的節點指標
* /return 是否找到。true為找到相應節點指標,false表示沒有找到相應節點指標。
*/
bool GetNodePointerByName(TiXmlElement* pRootEle,std::string &strNodeName,TiXmlElement* &Node)
{
// 假如等於根節點名,就退出
if (strNodeName==pRootEle->Value())
{
Node = pRootEle;
return true;
}
TiXmlElement* pEle = pRootEle;
for (pEle = pRootEle->FirstChildElement(); pEle; pEle = pEle->NextSiblingElement())
{
//遞迴處理子節點,獲取節點指標
if(GetNodePointerByName(pEle,strNodeName,Node))
return true;
}
return false;
}
有了這個函式,我們就很容易實現查詢節點的相應文字或屬性值。
/*!
* /brief 通過節點查詢。
*
* /param XmlFile xml檔案全路徑。
* /param strNodeName 要查詢的節點名
* /param strText 要查詢的節點文字
* /return 是否成功。true為成功,false表示失敗。
*/
bool QueryNode_Text(std::string XmlFile,std::string strNodeName,std::string &strText)
{
// 定義一個TiXmlDocument類指標
TiXmlDocument *pDoc = new TiXmlDocument();
if (NULL==pDoc)
{
return false;
}
pDoc->LoadFile(XmlFile);
TiXmlElement *pRootEle = pDoc->RootElement();
if (NULL==pRootEle)
{
return false;
}
TiXmlElement *pNode = NULL;
GetNodePointerByName(pRootEle,strNodeName,pNode);
if (NULL!=pNode)
{
strText = pNode->GetText();
return true;
}
else
{
return false;
}
}
/*!
* /brief 通過節點查詢。
*
* /param XmlFile xml檔案全路徑。
* /param strNodeName 要查詢的節點名
* /param AttMap 要查詢的屬性值,這是一個map,前一個為屬性名,後一個為屬性值
* /return 是否成功。true為成功,false表示失敗。
*/
bool QueryNode_Attribute(std::string XmlFile,std::string strNodeName,std::map<std::string,std::string> &AttMap)
{
// 定義一個TiXmlDocument類指標
typedef std::pair <std::string,std::string> String_Pair;
TiXmlDocument *pDoc = new TiXmlDocument();
if (NULL==pDoc)
{
return false;
}
pDoc->LoadFile(XmlFile);
TiXmlElement *pRootEle = pDoc->RootElement();
if (NULL==pRootEle)
{
return false;
}
TiXmlElement *pNode = NULL;
GetNodePointerByName(pRootEle,strNodeName,pNode);
if (NULL!=pNode)
{
TiXmlAttribute* pAttr = NULL;
for (pAttr = pNode->FirstAttribute(); pAttr; pAttr = pAttr->Next())
{
std::string strAttName = pAttr->Name();
std::string strAttValue = pAttr->Value();
AttMap.insert(String_Pair(strAttName,strAttValue));
}
return true;
}
else
{
return false;
}
return true;
}
下面是刪除指定節點的函式,其中考慮了刪除根節點的情況:
/*!
* /brief 刪除指定節點的值。
*
* /param XmlFile xml檔案全路徑。
* /param strNodeName 指定的節點名。
* /return 是否成功。true為成功,false表示失敗。
*/
bool DelNode(std::string XmlFile,std::string strNodeName)
{
// 定義一個TiXmlDocument類指標
TiXmlDocument *pDoc = new TiXmlDocument();
if (NULL==pDoc)
{
return false;
}
pDoc->LoadFile(XmlFile);
TiXmlElement *pRootEle = pDoc->RootElement();
if (NULL==pRootEle)
{
return false;
}
TiXmlElement *pNode = NULL;
GetNodePointerByName(pRootEle,strNodeName,pNode);
// 假如是根節點
if (pRootEle==pNode)
{
if(pDoc->RemoveChild(pRootEle))
{
pDoc->SaveFile(XmlFile);
return true;
}
else
return false;
}
// 假如是其它節點
if (NULL!=pNode)
{
TiXmlNode *pParNode = pNode->Parent();
if (NULL==pParNode)
{
return false;
}
TiXmlElement* pParentEle = pParNode->ToElement();
if (NULL!=pParentEle)
{
if(pParentEle->RemoveChild(pNode))
pDoc->SaveFile(XmlFile);
else
return false;
}
}
else
{
return false;
}
return false;
}
Visual C++ TinyXml快速入門(三)
在Visual C++ TinyXml快速入門(二)中,介紹使用tinyxml庫獲取xml檔案宣告,查詢指定節點、刪除指定節點的做法。在本文中繼續介紹修改指定節點和增加節點的做法。修改節點其實和查詢指定節點的值有點類似,也分為兩個函式,一個實現修改文字。另一個負責修改屬性。
/*!
* /brief 修改指定節點的文字。
*
* /param XmlFile xml檔案全路徑。
* /param strNodeName 指定的節點名。
* /param strText 重新設定的文字的值
* /return 是否成功。true為成功,false表示失敗。
*/
bool ModifyNode_Text(std::string XmlFile,std::string strNodeName,std::string strText)
{
// 定義一個TiXmlDocument類指標
TiXmlDocument *pDoc = new TiXmlDocument();
if (NULL==pDoc)
{
return false;
}
pDoc->LoadFile(XmlFile);
TiXmlElement *pRootEle = pDoc->RootElement();
if (NULL==pRootEle)
{
return false;
}
TiXmlElement *pNode = NULL;
GetNodePointerByName(pRootEle,strNodeName,pNode);
if (NULL!=pNode)
{
pNode->Clear(); // 首先清除所有文字
// 然後插入文字,儲存檔案
TiXmlText *pValue = new TiXmlText(strText);
pNode->LinkEndChild(pValue);
pDoc->SaveFile(XmlFile);
return true;
}
else
return false;
}
/*!
* /brief 修改指定節點的屬性值。
*
* /param XmlFile xml檔案全路徑。
* /param strNodeName 指定的節點名。
* /param AttMap 重新設定的屬性值,這是一個map,前一個為屬性名,後一個為屬性值
* /return 是否成功。true為成功,false表示失敗。
*/
bool ModifyNode_Attribute(std::string XmlFile,std::string strNodeName,
std::map<std::string,std::string> &AttMap)
{
typedef std::pair <std::string,std::string> String_Pair;
// 定義一個TiXmlDocument類指標
TiXmlDocument *pDoc = new TiXmlDocument();
if (NULL==pDoc)
{
return false;
}
pDoc->LoadFile(XmlFile);
TiXmlElement *pRootEle = pDoc->RootElement();
if (NULL==pRootEle)
{
return false;
}
TiXmlElement *pNode = NULL;
GetNodePointerByName(pRootEle,strNodeName,pNode);
if (NULL!=pNode)
{
TiXmlAttribute* pAttr = NULL;
std::string strAttName = _T("");
std::string strAttValue = _T("");
for (pAttr = pNode->FirstAttribute(); pAttr; pAttr = pAttr->Next())
{
strAttName = pAttr->Name();
std::map<std::string,std::string>::iterator iter;
for (iter=AttMap.begin();iter!=AttMap.end();iter++)
{
if (strAttName==iter->first)
{
pAttr->SetValue(iter->second);
}
}
}
pDoc->SaveFile(XmlFile);
return true;
}
else
{
return false;
}
}
對於ModifyNode_Attribute函式,這裡稍微介紹一下如何使用,比如對於下面這樣一個xml檔案:
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<MyApp>
<Messages>
<Welcome>Welcome to MyApp</Welcome>
<Farewell>Thank you for using MyApp</Farewell>
</Messages>
<Windows>
<Window name="MainFrame" x="5" y="15" w="400" h="250" />
</Windows>
<Connection ip="192.168.0.1" timeout="123.456000" />
</MyApp>
我們如果要修改節點的Connection的ip為192.168.0.100,timeout為1000,我們可以這樣用:
std::string XmlFile = _T("E://TestTinyxml//example4.xml");
std::string strNodeName = _T("Connection");
typedef std::pair <std::string,std::string> String_Pair;
std::map<std::string,std::string> AttMap;
AttMap.insert(String_Pair(_T("ip"),_T("192.168.0.100")));
AttMap.insert(String_Pair(_T("timeout"),_T("1000")));
ModifyNode_Attribute(XmlFile,strNodeName,AttMap);
下面是增加節點的兩個函式:
/*!
* /brief 增加指定節點的文字。
*
* /param XmlFile xml檔案全路徑。
* /param strParNodeName 要增加的節點的父節點。
* /param strNodeName 指定的節點名。
* /param strText 要增加的文字
* /return 是否成功。true為成功,false表示失敗。
*/
bool AddNode_Text(std::string XmlFile,std::string strParNodeName,std::string strNodeName,std::string strText)
{
// 定義一個TiXmlDocument類指標
TiXmlDocument *pDoc = new TiXmlDocument();
if (NULL==pDoc)
{
return false;
}
pDoc->LoadFile(XmlFile);
TiXmlElement *pRootEle = pDoc->RootElement();
if (NULL==pRootEle)
{
return false;
}
TiXmlElement *pNode = NULL;
GetNodePointerByName(pRootEle,strParNodeName,pNode);
if (NULL!=pNode)
{
// 生成子節點:pNewNode
TiXmlElement *pNewNode = new TiXmlElement(strNodeName);
if (NULL==pNewNode)
{
return false;
}
// 設定節點文字,然後插入節點
TiXmlText *pNewValue = new TiXmlText(strText);
pNewNode->LinkEndChild(pNewValue);
pNode->InsertEndChild(*pNewNode);
pDoc->SaveFile(XmlFile);
return true;
}
else
return false;
}
/*!
* /brief 增加節點。
*
* /param XmlFile xml檔案全路徑。
* /param strParNodeName 要增加的節點的父節點。
* /param strNodeName 指定的節點名。
* /param AttMap 要增加的節點設定的屬性值,這是一個map,前一個為屬性名,後一個為屬性值
* /return 是否成功。true為成功,false表示失敗。
*/
bool AddNode_Attribute(std::string XmlFile,std::string strParNodeName,std::string strNodeName,std::map<std::string,std::string> &AttMap)
{
// 定義一個TiXmlDocument類指標
TiXmlDocument *pDoc = new TiXmlDocument();
if (NULL==pDoc)
{
return false;
}
pDoc->LoadFile(XmlFile);
TiXmlElement *pRootEle = pDoc->RootElement();
if (NULL==pRootEle)
{
return false;
}
TiXmlElement *pNode = NULL;
GetNodePointerByName(pRootEle,strParNodeName,pNode);
if (NULL!=pNode)
{
// 生成子節點:pNewNode
TiXmlElement *pNewNode = new TiXmlElement(strNodeName);
if (NULL==pNewNode)
{
return false;
}
// 設定節點的屬性值,然後插入節點
std::map<std::string,std::string>::iterator iter;
for (iter=AttMap.begin();iter!=AttMap.end();iter++)
{
pNewNode->SetAttribute(iter->first,iter->second);
}
pNode->InsertEndChild(*pNewNode);
pDoc->SaveFile(XmlFile);
return true;
}
else
return false;
}
相關文章
- Vue快速入門(二)Vue
- Go快速入門(二)Go
- CSS快速入門(三)CSS
- Flask二之快速入門Flask
- 前端快速入門(三)--CSS前端CSS
- ES6快速入門(二)
- ES6快速入門(三)
- JS快速入門(一)JS
- webservice快速入門-SOAP和WSDL(三)Web
- Flutter基礎(三)Dart快速入門FlutterDart
- Flutter 基礎(三)Dart 快速入門FlutterDart
- gRPC(三)基礎:gRPC快速入門RPC
- Spring Boot (一)快速入門Spring Boot
- RabbitMQ(一):RabbitMQ快速入門MQ
- AutoCAD快速入門(二):圖形視窗
- SpringBoot整合RabbitMQ(一)快速入門Spring BootMQ
- Solon詳解(一)- 快速入門
- 一文快速入門DockerDocker
- node.js快速入門(一)Node.js
- 快速排序快速入門排序
- Gradle核心思想(三)Groovy快速入門指南Gradle
- Metal入門教程(二)三維變換
- webpack 快速入門 系列 —— 實戰一Web
- Pytorch DistributedDataParallel(DDP)教程二:快速入門實踐篇PyTorchParallel
- Flutter小白教程系列(三) --- Dart語言快速入門FlutterDart
- Spring Data JPA之Spring Data JPA快速入門(三)Spring
- 三篇文章帶你快速入門Kotlin(上)Kotlin
- SQL快速入門 ( MySQL快速入門, MySQL參考, MySQL快速回顧 )MySql
- JavaScript快速入門JavaScript
- vim快速入門
- Webpack快速入門Web
- Lumen快速入門
- TypeScript 快速入門TypeScript
- phpunit 快速入門PHP
- React快速入門React
- WebSocket 快速入門Web
- Pipenv 快速入門
- MQTT 快速入門MQQT
- Zookeeper快速入門