參考:http://blog.csdn.net/zww0815/article/details/8083550
// 讀者對象:對TinyXml有一定了解的人。本文是對TinyXml工具的一些知識點的理解。 // 1 TinyXml中對TiXmlNode進行了分類,是用一個枚舉進行描述的。 // enum NodeType // { // DOCUMENT, 文檔節點 // ELEMENT, 元素節點 // COMMENT, 還沒弄清楚 // UNKNOWN, 未知節點 // TEXT, 文本節點 // DECLARATION, 聲明節點 // TYPECOUNT 還沒弄清楚 // }; // TiXmlNode * pNode->Type() 函數可以返回節點的類型。 // 枚舉的比較方法:TiXmlText::TEXT == pNode->Type(); // // 這幾個類型非常重要,尤其是在遍歷xml時或者查找一個節點時 // 我對節點和元素的理解如下:為了說明問題,我使用下面的xml文檔來舉例說明 // <?xml version="1.0" encoding="gb2312"?> // <Persons> // <person Id="200" Shengao=34 ClassName="計本0508"> // <name>vertor</name> // <age>20</age> // <address encode="utf-8"> // <country>中國</country> // <province>山西</province> // <village>王大庄</village> // </address> // </person> // </Persons> // // 2.1 節點:一種對文檔結構的描述對象 // 2.2 元素:對文檔某一個數據塊的描述 // 2.3 文本是指沒有孩子的節點 // 例如<village>大王庄</village> 文本節點是:"大王庄" // 然而判斷一個節點是否是文本節點時並不是根據pNode->NoChildren()來判斷,而是根據節點的類型來判斷 // 因為如果一個節點形如:<village></village>它也是沒有孩子節點的。 // 2.4 節點類可以轉換成元素對象。 // 例如 TiXmlElement * pElement = pNode->ToElement(); // 那什么時候需要轉換成元素呢? // 當你需要元素的一些屬性值是就需要轉換了。 // 2.5 元素跟節點都有關於訪問孩子的函數, // 元素訪問孩子的函數: // FirstChildElement() 返回當前元素的孩子元素 // NextSiblingElement() 返回當前元素的同級元素 // 節點訪問節點孩子的函數: // FirstChild() 返回當前節點的孩子節點 // NextSibing() 返回當前節點的同級下一個節點 // 個人覺得 元素訪問和節點訪問在一般的訪問下沒有區別,兩者都可以訪問的孩子 // 對於一些特殊的情況下才需要區分。比如你要訪問屬性時,就需要用元素來找到第一個屬性值。 // 2.6 對於遍歷一個xml文檔時,思路一般是這樣的: // 1 載入一個xml // 2 獲得根元素(不是根節點) // 3 循環訪問每一個根元素的子元素 // 4 對每一個子元素進行解析。 // 4.1 獲取子元素的類型Type // 4.2 switch(Type) // case TEXT: // 輸出文本節點的值pNode->value() // case ELEMENT: // 獲取元素的value(這里的value指的是元素的名字,例如:person元素) // 循環獲取元素的每一個屬性 // a 得到元素的第一個屬性 // b do——while循環獲取每一個屬性和值。 // case COMMENT: 暫時不用管 // case UNKNOWN: 暫時不用管 // case DECLARATION: // 獲取元素的版本,編碼方式等等 // 4.3 循環遍歷子元素的下一級元素(即孫子元素) 在這里也可以遍歷孫子節點。 // 遞歸調用第四步。 // 基本思路就是這樣,具體代碼見后面 // 2.7 如果定位一個節點 // 唯一確定一個節點的方法是根據節點名,屬性名,屬性值 // 1 根據xml的遍歷思想找到與給定節點名一樣的節點 // 2 如果這個節點有屬性並且屬性名和值與給定的一致,說明找到了。 // 3 如果沒有一致的,說明解析失敗。 // 4 如果沒有給定屬性名和值,則可以默認只查找與節點名一致的節點。 // 2.8 編碼問題 // 用TinyXml加載一個xml文檔時,根據文檔的編碼方式來加載,在操作過程中需要進行編碼轉換 // 如果encoding=utf-8 則在遍歷時,需要進行編碼轉換,具體轉換還沒找到方法。 // // 2.9 指針的 new和釋放。 // TinyXml已經幫我們把指針分配的內存進行了管理,在析構函數中進行了處理,我們不需要處理new出來的指針 // 如果我們顯示的delete時,有可能影響程序運行。 // 3.0 對於添加一個節點,刪除一個節點,更新一個節點時,都需要在最后SaveFile,我就好幾次忘了SaveFile,所以調了老半天。 // 3.1 總的來說,Tinyxml還是不錯的,以后繼續學習。 // 部分功能代碼 // 3.2 對於插入一個節點,首先獲取要插入節點的父節點,然后進行插入,最需要注意的是在查詢父節點的是時候,必須對應同一個文本對象來操作。有可能在兩個函數中同時打開了同一個xml文檔,雖然名字一樣,但是不是同一個xmldocument對象,所以操作會失敗。 // 最后要保存。 #include "XmlTest.h" #define MAX_NUM 256 /************************************************************************/ /* 創建一個xml文檔 */ /************************************************************************/ void createXml(const char * ccXmlName) { //創建一個XML的文檔對象。 TiXmlDocument *myDocument = new TiXmlDocument(); TiXmlDeclaration* decl = new TiXmlDeclaration("1.0","gb2312","yes"); myDocument->LinkEndChild(decl); //創建一個根元素並連接。 TiXmlElement *RootElement = new TiXmlElement("Persons"); myDocument->LinkEndChild(RootElement); for(int i=0; i<10;i++) { //創建一個Person元素並連接。 TiXmlElement *PersonElement = new TiXmlElement("Person"); RootElement->LinkEndChild(PersonElement); //設置Person元素的屬性。 PersonElement->SetAttribute("ID", i); //創建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("20"); NameElement->LinkEndChild(NameContent); AgeElement->LinkEndChild(AgeContent); } //保存到文件 myDocument->SaveFile(ccXmlName); } /************************************************************************/ /* 遍歷一個xml文檔 */ /************************************************************************/ void readXml(const char * ccXmlName) { //創建一個XML的文檔對象。 TiXmlDocument *myDocument = new TiXmlDocument(ccXmlName); myDocument->LoadFile(); //獲得xml的頭,即聲明部分 TiXmlDeclaration* decl = myDocument->FirstChild()->ToDeclaration(); cout << "xml文件的版本是:" << decl->Version() << endl; cout << "xml的編碼格式是:" << decl->Encoding() << endl; //獲得根元素 TiXmlElement *RootElement = myDocument->RootElement(); //輸出根元素名稱 cout << RootElement->Value() << endl; TiXmlNode* pNode = NULL; string msg = ""; for(pNode=RootElement->FirstChildElement();pNode;pNode=pNode->NextSiblingElement()) { msg += dumpNode(pNode,0); } cout << msg << endl; } /************************************************************************/ /*描述:遍歷一個元素 時間:2012-9-18 參數說明:pNode節點,flag 節點嵌套層數 /************************************************************************/ string dumpNode(TiXmlNode * pNode,int flag) { string msg = ""; if(pNode == NULL) { return ""; } TiXmlText * pText = NULL; TiXmlNode * pChildNode = NULL; int t = pNode->Type(); switch(t) { //節點類型是text節點 case TiXmlText::TINYXML_TEXT: { pText = pNode->ToText(); string text = pText->Value(); if(!text.empty()) { msg = msg + "="+ text; } break; } //節點類型是Element case TiXmlText::TINYXML_ELEMENT: { msg = msg + "\r\n"; int num = flag; while(num >= 1) { msg = msg + " "; num--; } msg = msg + pNode->Value(); //輸出屬性 TiXmlElement * pElement = pNode->ToElement(); TiXmlAttribute * pAttr = pElement->FirstAttribute(); TiXmlAttribute * pNextAttr =NULL; string tmpAttrMsg = "["; //if(pAttr != NULL && !(string(pAttr->Name())).compare("name") && !(string(pAttr->Value())).compare("IDH_CFG_USB")) if(pAttr != NULL ) { string tmpAttrVal = ""; string tmpAttrName = ""; do { tmpAttrVal = pAttr->Value(); tmpAttrName = pAttr->Name(); tmpAttrMsg += tmpAttrName + "=" +tmpAttrVal + ","; //各個屬性之間用逗號分隔 }while(pAttr = pAttr->Next()); /* 去掉最后的',' */ tmpAttrMsg = tmpAttrMsg.erase(tmpAttrMsg.find_last_of(",")); //同上 tmpAttrMsg = tmpAttrMsg.substr(0,tmpAttrMsg.find_last_of(",")); } tmpAttrMsg += "]"; msg += tmpAttrMsg; break; } case TiXmlText::TINYXML_DOCUMENT: case TiXmlText::TINYXML_COMMENT: case TiXmlText::TINYXML_UNKNOWN: case TiXmlText::TINYXML_DECLARATION: case TiXmlText::TINYXML_TYPECOUNT: { ;//Nothing to do } } //循環訪問它的每一個元素 for(pChildNode=pNode->FirstChild();pChildNode!=0;pChildNode = pChildNode->NextSibling()) { msg = msg + dumpNode(pChildNode,flag+1); } return msg; } /************************************************************************/ /* 查詢出唯一節點 */ /* 參數說明: string nodeName 節點名 string nodeAttrName 節點的屬性 string nodeAttrValue 節點屬性的值 /************************************************************************/ TiXmlNode * SelectSingleNode(const char * cXmlName,string nodeName,string nodeAttrName,string nodeAttrValue) { //加載一個XML的文檔對象。 TiXmlDocument *xmlDoc = new TiXmlDocument(cXmlName); if(!xmlDoc->LoadFile()) //是tinyXml會自動處理文檔的BOM { return NULL; } if(xmlDoc == NULL) { return NULL; } //獲得根元素 TiXmlElement *RootElement = xmlDoc->RootElement(); if(RootElement == NULL) { cout << "解析錯誤,無法獲取根元素" << endl; return NULL; } TiXmlNode * pNode = NULL; TiXmlNode * pSelectNode = NULL; string msg = ""; for(pNode=RootElement->FirstChildElement();pNode;pNode=pNode->NextSiblingElement()) { pSelectNode = selectChildNode(pNode,nodeName,nodeAttrName,nodeAttrValue); if(pSelectNode) { break; } } if(pSelectNode) { cout << "解析成功" << endl; cout << "[節點名]=" << pSelectNode->Value() << endl; return pSelectNode; } else { cout << "解析錯誤,無法獲取節點" << endl; return NULL; } } TiXmlNode * SelectSingleNodeByRootEle(TiXmlElement* RootElement,string nodeName,string nodeAttrName,string nodeAttrValue) { //加載一個XML的文檔對象。 // TiXmlDocument *xmlDoc = new TiXmlDocument(cXmlName); // if(!xmlDoc->LoadFile()) //是tinyXml會自動處理文檔的BOM // { // return NULL; // } // // // if(xmlDoc == NULL) // { // return NULL; // } //獲得根元素 //TiXmlElement *RootElement = xmlDoc->RootElement(); if(RootElement == NULL) { cout << "解析錯誤,無法獲取根元素" << endl; return NULL; } TiXmlNode * pNode = NULL; TiXmlNode * pSelectNode = NULL; string msg = ""; for(pNode=RootElement->FirstChildElement();pNode;pNode=pNode->NextSiblingElement()) { pSelectNode = selectChildNode(pNode,nodeName,nodeAttrName,nodeAttrValue); if(pSelectNode) { break; } } if(pSelectNode) { //cout << "解析成功" << endl; //cout << pSelectNode->Value() << endl; return pSelectNode; } else { cout << "解析錯誤,無法獲取節點" << endl; return NULL; } } /************************************************************************/ /* 根據父節點循環遍歷查找子節點 參數說明 noteName 節點名 noteAttrName 屬性名 noteAttrValue 屬性值 /************************************************************************/ TiXmlNode * selectChildNode(TiXmlNode * pNode,string nodeName,string nodeAttrName,string nodeAttrValue) { if(pNode == NULL) { return NULL; } TiXmlNode * pSelectedNode = NULL; TiXmlNode * pChildNode = NULL; int t = pNode->Type(); switch (t) { case TiXmlText::TINYXML_DOCUMENT: case TiXmlText::TINYXML_DECLARATION: case TiXmlText::TINYXML_TEXT: case TiXmlText::TINYXML_UNKNOWN: case TiXmlText::TINYXML_COMMENT: break; case TiXmlText::TINYXML_ELEMENT: if(pNode->Value() == nodeName) { //cout << pNode->Value() << endl; if(!nodeAttrName.empty() && !nodeAttrValue.empty()) { TiXmlElement * pElement = pNode->ToElement(); TiXmlAttribute * pAttr = pElement->FirstAttribute(); TiXmlAttribute * pNextAttr =NULL; if(pAttr != NULL) { do { if(pAttr->Name()==nodeAttrName&&pAttr->Value()== nodeAttrValue) { //cout << pAttr->Value() << endl; return pNode; } }while(pAttr = pAttr->Next()); } } else { return pNode; } } else { //循環訪問它的每一個元素 for(pChildNode=pNode->FirstChild(); pChildNode!=0; pChildNode = pChildNode->NextSibling()) { pSelectedNode = selectChildNode( pChildNode, nodeName, nodeAttrName, nodeAttrValue); if(pSelectedNode) { return pSelectedNode; } } } default:break; } return NULL; } /************************************************************************/ /* 普通插入一個節點,還不完善。 */ /************************************************************************/ bool insert(const char * ccXmlName) { //加載一個XML的文檔對象。 TiXmlDocument *myDocument = new TiXmlDocument(ccXmlName); myDocument->LoadFile(); if(myDocument == NULL) { return false; } //獲得xml的頭,即聲明部分 TiXmlDeclaration* decl = myDocument->FirstChild()->ToDeclaration(); if(decl != NULL) { cout << "xml文件的版本是:" << decl->Version() << endl; cout << "xml的編碼格式是:" << decl->Encoding() << endl; } //獲得根元素 TiXmlElement *RootElement = myDocument->RootElement(); if(RootElement != NULL) { //創建一個Person元素並連接。 TiXmlElement *PersonElement = new TiXmlElement("Person"); PersonElement->SetAttribute("Id",1); RootElement->LinkEndChild(PersonElement); TiXmlText *textElement = new TiXmlText("Jam"); PersonElement->LinkEndChild(textElement); //增加一個team元素 TiXmlElement *TeamElement = new TiXmlElement("team"); TeamElement->SetAttribute("TID","001"); RootElement->LinkEndChild(TeamElement); //增加team的子節點name TiXmlElement *teamName = new TiXmlElement("name"); TiXmlText *nameText = new TiXmlText("workgroup"); teamName->LinkEndChild(nameText); TeamElement->LinkEndChild(teamName); //增加team的子節點type TiXmlElement *teamType = new TiXmlElement("type"); TiXmlText *typeText = new TiXmlText("SI"); teamType->LinkEndChild(typeText); TeamElement->LinkEndChild(teamType); myDocument->SaveFile("Person.xml"); //輸出根元素名稱 cout << RootElement->Value() << endl; return true; } return false; } /************************************************************************/ /* 獲取一個節點的屬性 */ /************************************************************************/ string getAttribute(TiXmlNode * pNode) { if(pNode == NULL) return ""; //輸出屬性 string msg = ""; TiXmlElement * pElement = pNode->ToElement(); TiXmlAttribute * pAttr = pElement->FirstAttribute(); TiXmlAttribute * pNextAttr =NULL; string tmpAttrMsg = ""; if(pAttr != NULL) { string tmpAttrVal = ""; string tmpAttrName = ""; do { tmpAttrVal = pAttr->Value(); tmpAttrName = pAttr->Name(); tmpAttrMsg += "[" + tmpAttrName + "]=" + tmpAttrVal+"\n"; //各個屬性之間用逗號分隔 }while(pAttr = pAttr->Next()); //tmpAttrMsg = tmpAttrMsg.erase(tmpAttrMsg.find_last_of(",")); } //tmpAttrMsg += "]"; msg += tmpAttrMsg; return msg; } /************************************************************************/ /* 在指定位置插入一個元素 */ /************************************************************************/ bool insertAElement(const char * cXmlName, TiXmlElement * pElement) { //加載一個XML的文檔對象。 TiXmlDocument *xmlDoc = new TiXmlDocument(cXmlName); xmlDoc->LoadFile(); if(xmlDoc == NULL) { return false; } //獲得xml的頭,即聲明部分 TiXmlDeclaration* decl = xmlDoc->FirstChild()->ToDeclaration(); if(decl != NULL) { cout << "xml文件的版本是:" << decl->Version() << endl; cout << "xml的編碼格式是:" << decl->Encoding() << endl; } //獲得根元素 TiXmlElement *RootElement = xmlDoc->RootElement(); if(RootElement != NULL) { TiXmlNode * pNode = SelectSingleNode(cXmlName,"name","length","100"); if(pNode == NULL) { return false; } //創建一個Person元素並連接。 TiXmlElement *pNewElement = new TiXmlElement("Person"); if(pNewElement == NULL) { return false; } pNewElement->SetAttribute("Id","1"); TiXmlText *textElement = new TiXmlText("gbnn"); if(textElement == NULL) { return false; } pNewElement->LinkEndChild(textElement); TiXmlNode * pRet = pNode->InsertBeforeChild(pNode->LastChild(),*pNewElement); //TiXmlNode * pRet = pNode->LinkEndChild(pNewElement); xmlDoc->Print(); bool b = xmlDoc->SaveFile(); if(b) { cout << "添加成功" << endl; return b; } else { cout << "添加失敗" << endl; return false; } } else { return false; } } //const char * cXmlName,string strNodeName,string strNodeAttrName,string strNdeAttrValue,string strPath /*! * \Function: 修改一個唯一節點中第二、三屬性的值為一子符串 * * \param cXmlName xml文件名 * \param strNodeName 指定的節點名。 * \param strNodeAttrName 指定的節點名所在節點中第一屬性名。 * \param strNdeAttrValue 指定的節點名所在節點中第一屬性值。 * \param strPath 字符串。為當前路徑名的上一級目錄的字符串 * \return 是否成功。true為成功,false表示失敗。 */ bool ModifySingleNode(const char * cXmlName,string strNodeName,string strNodeAttrName,string strNdeAttrValue,string strPath) { if (strNodeName.empty() || strNodeAttrName.empty() || strNdeAttrValue.empty() ||strPath.empty()) { return false; } // 定義一個TiXmlDocument類指針 TiXmlDocument *pDoc = new TiXmlDocument(); if (NULL==pDoc) { return false; } pDoc->LoadFile(cXmlName); TiXmlElement* pRootElement = pDoc->RootElement(); TiXmlNode * pNode = SelectSingleNodeByRootEle(pRootElement,strNodeName,strNodeAttrName,strNdeAttrValue); if (NULL == pNode) { return false; } //輸出屬性 TiXmlElement * pElement = pNode->ToElement(); TiXmlAttribute * pAttr = pElement->FirstAttribute(); TiXmlAttribute * pNextAttr =NULL; if(pAttr != NULL) { string tmpAttrVal = ""; string tmpAttrName = ""; do { tmpAttrVal = pAttr->Value(); tmpAttrName = pAttr->Name(); //節點中第一個屬性對跳過 if (tmpAttrName == strNodeAttrName && tmpAttrVal == strNdeAttrValue) { continue; } //修改第二和第三個屬性對 if ("href" == tmpAttrName) { pAttr->SetValue(strPath.c_str()); } if ("test" == tmpAttrName) { pAttr->SetValue(strPath.c_str()); } }while(pAttr = pAttr->Next()); } pDoc->SaveFile("hhhhhhhhhhhhh.xml"); return true; } void ShowSingleNode(const char * cXmlName,string strNodeName,string strNodeAttrName,string strNdeAttrValue) { TiXmlNode * pNode = SelectSingleNode(cXmlName,strNodeName,strNodeAttrName,strNdeAttrValue); if (NULL == pNode) { return; } string strTem = getAttribute(pNode); cout << strTem.c_str() << endl; } string PathOpt() { char cStr[MAX_NUM]; GetCurrentDirectory(MAX_NUM,cStr); string str = cStr; //取當前路徑的上一目錄所在路徑 size_t pos = str.find_last_of("\\"); str.erase(str.begin()+pos,str.end()); return str; } int main() { const char * cXmlName = "files.xml"; string strPath; //createXml(ccXmlName); //readXml(cXmlName); //insert(ccXmlName); //readXml(ccXmlName); ShowSingleNode(cXmlName,"Document","title","About VMware Player Help"); strPath = PathOpt(); bool ret = ModifySingleNode(cXmlName,"Document","title","About VMware Player Help",strPath); if (ret) { cout << "OK" << endl; } else { cout << "false" << endl; } ShowSingleNode("hhhhhhhhhhhhh.xml","Document","title","About VMware Player Help"); return 0; }
自己改寫的代碼
TiXmlElement* m_pCurElement; ///< 當前元素
/** @brief 設置當前位置到特定的節點 */
bool SetToSelectNode(TiXmlNode * pNode, const std::string& szName, const std::string& szAttribute, const std::string& szValue) { if(pNode == NULL) { return false; } if(pNode->Value() == szName) { //找到了相同的節點名稱 if(!szAttribute.empty() && !szValue.empty()) { // 循環獲取元素的每一個屬性 // a 得到元素的第一個屬性 // b do——while循環獲取每一個屬性和值。 TiXmlElement * pElement = pNode->ToElement(); TiXmlAttribute * pAttr = pElement->FirstAttribute(); TiXmlAttribute * pNextAttr =NULL; if(pAttr != NULL) { do { if(pAttr->Name()==szAttribute&&pAttr->Value()== szValue) { m_pCurElement = pElement; return true; } }while(pAttr = pAttr->Next()); } } else { //如果 nodeAttrName 或者 nodeAttrValue 不需要找,則直接選取此點。 m_pCurElement = pNode->ToElement(); return true; } } else { //循環訪問它的每一個元素 for(TiXmlNode *pChildNode =pNode->FirstChild(); pChildNode!=0; pChildNode = pChildNode->NextSibling()) { if(SetToSelectNode(pChildNode,szName, szAttribute,szValue)) { return true; } } } return false; }
