题记:
看到c++中有解析xml,花了点时间学习了tinyxml2的使用(有些方法在tinyxml1中没有了,还好摸索出了野路子),并且写了比较通用方法方便以后再次使用,如果以后再遇到关于xml操作可以再补充方法或优化方法(就是一句话,有的懒得再写了)
参考:
tinyxml使用笔记与总结
C++:tinyxml的使用
tinyxml使用指导
使用tinyXML2 读写配置文件
TinyXml查找唯一节点及修改节点操作
tinyxml的设计结构分析
下载:
xml中包含中文
用wstring和string 相互转化
总结:
使用很简单,解压后把两个文件(tinyxml2.h 和tinyxml2.cpp) 放入工程文件中,还有个xmltest.cpp放着官方用例,需要命名空间 using namespace tinyxml2;
在tinyxml2 中XMLNode中没有Type方法,知道这个节点是什么类型,在全遍历的时候很是头疼,通过我要遍历的xml来解释下我为什么头疼,官方删除了一个方法判断类型的方法,不知道为啥在tinyxml2中要删除,难道替换了更好的?
Cards.xml
<?xml version="1.0" ?>
<Root>
<Card>
<Cards>0X11</Cards>
<Cardd>
<Cardds>0X12</Cardds>
<Cardds>0X16</Cardds>
<Carddss>
<hhlo>
<Cardss1>wor1</Cardss1>
<Cardss1>wor2</Cardss1>
<Cardss1>wor3</Cardss1>
<Cardss1>wor4</Cardss1>
</hhlo>
</Carddss>
</Cardd>
<Cards>0X13</Cards>
<Cards>0X14</Cards>
<Cards>0X15</Cards>
</Card>
<Card>
<Cards>0X11,0X12,0X13,0X18</Cards>
</Card>
</Root>
在这里我要获取Cards中0x11,tinyxml2中你可以获得XMLNode,但是要获得文本0x11,需要XMLElement,所以你要判断是否是XMLElement,是的话获得文本,是XMLNode,找下一个,因为没有Type()函数来判断
为了区分这两种类型,我在较长的测试中和看源码对于GetText()注释发现,可以用element->ToElement()->GetText() == nullptr 来判断,上源码注释图
注意红色画圈的地方,意思是这样的xml也就是返回null,所以正好符合我目前的需求
xml解析方法:
记录自己会用的xml方法或可能用到的方法,遇到后在总结补充,防止再次思考和重写
ParseXml.h
#pragma once
#include <iostream>
#include <vector>
#include "tinyxml2.h"
#include <map>
#include "Result.h"
#include "DealXmlText.h"
using namespace tinyxml2;
using namespace std;
/*
@brief 找到父节点root下名字为nodeName节点text
@description
count 为 -1时 获得所有的节点
count 为 正整数时 获得count个数前的所有节点
如果节点数小于count 相当于 输出所有节点
返回的状态: "XML_ERROR_PARSING_ROOT" 包含nodeName的节点不存在
"XML_ERROR_PARSING_ELEMENT" nodeName的节点不存在
"XML_SUCCESS" 成功找到需要的节点
@param [XMLNode*] [root] [包含nodeName的父节点]
@param [const char*] [nodeName] [需要找的节点名字]
@param [std::size_t] [count] [要前几个这样的节点]
@param [vector<vector<string>>&] [allTextResult] [节点内所有的text文本]
@return [string] [] [查找的状态]
@attention
*/
std::string ParserCardOperation(tinyxml2::XMLNode* root, const char* nodeName, std::size_t count, std::vector<std::vector<std::string>>& allTextResult);
/*
@brief 按照顺序解析出xml中所有的text
@description
解析的状态: XML_SUCCESS 成功
其它 失败
@param [const char*] [path] [xml的文件名字]
@param [vector<vector<string>>&] [result] [得到所有text的集合]
@return [int] [] [解析的状态]
@attention
*/
int ParserXml(const char* fileName, std::vector<std::string>& result);
/*
@brief ParserXml实现的细节操作,根据头节点递归
@description
flag true 找与这个节点同级别的节点
false 这个节点下的第一个元素节点
@param [XMLNode*] [node] [节点]
@param [bool] [flag] [用来判断是找这个节点下的第一个元素节点 还是 找与这个节点同级别的节点]
@param [vector<vector<string>>&] [result] [得到所有text的集合]
@return [] [] []
@attention
通过判断最后是否回退到了root节点来结束递归,不然就死循环中
*/
void ParserXmlOperation(tinyxml2::XMLNode* node, bool flag, std::vector<std::string>& result);
/*
@brief 按照顺序解析出xml中所有的text
@description
解析的状态: XML_SUCCESS 成功
其它 失败
@param [const char*] [path] [xml的文件名字]
@param [map<string, string>&] [result] [得到所有text的集合 和 对应的 node 节点值]
@return [int] [] [解析的状态]
@attention
*/
int ParserXmlWithNodeValue(const char* fileName, std::map<std::string,std::string>& result);
/*
@brief ParserXml实现的细节操作,根据头节点递归
@description
flag true 找与这个节点同级别的节点
false 这个节点下的第一个元素节点
@param [XMLNode*] [node] [节点]
@param [bool] [flag] [用来判断是找这个节点下的第一个元素节点 还是 找与这个节点同级别的节点]
@param [map<string, string>&] [result] [得到所有text的集合 和 对应的 node 节点值]
@return [] [] []
@attention
通过判断最后是否回退到了root节点来结束递归,不然就死循环中
*/
void ParserXmlOperationWithNodeValue(tinyxml2::XMLNode* node, bool flag, std::map<std::string, std::string>& result);
/*
@brief 按照顺序解析出xml中所有的text
@description
company
@param [string&] [_str] [xml的文件名字+地址]
@param [Result&] [_result] [得到cards所有结果]
@return [bool] [] [解析的状态]
@attention
*/
bool ParserXmlWithNodeValue(std::string& _str, Result& _result);
/*
@brief 按照顺序解析出xml中所有的text
@description
own
@param [string&] [_str] [xml的文件名字+地址]
@param [Result&] [_result] [得到cards所有结果]
@return [bool] [] [解析的状态]
@attention
*/
bool ParserXml(string& _str, Result& _result);
ParseXml.cpp
#include "ParseXml.h"
string ParserCardOperation(XMLNode* root, const char* nodeName, std::size_t count, vector<vector<string>>& allTextResult)
{
if (nullptr == root)
return "XML_ERROR_PARSING_ROOT";
XMLElement* node = nullptr;
std::size_t i = 0;
bool isFindAll = count == -1 ? true : false;
do
{
if (i == 0)
node = root->FirstChildElement(nodeName);
else
node = node->NextSiblingElement(nodeName); //返回当前元素同级的元素
if (nullptr == node)
return "XML_ERROR_PARSING_ELEMENT";
const char* text = node->ToElement()->GetText();
string str(text);
vector<string> s;
s.push_back(str);
allTextResult.push_back(s);
i++;
} while (isFindAll || (!isFindAll && i < count));
return "XML_SUCCESS";
}
int ParserXml(const char* fileName, vector<string>& result) {
XMLDocument xmlDoc;
XMLError tmpResult = xmlDoc.LoadFile(fileName);
if (tmpResult != XML_SUCCESS)
{
return tmpResult;
}
XMLNode* root = xmlDoc.RootElement();
ParserXmlOperation(root, false, result);
return XML_SUCCESS;
}
void ParserXmlOperation(XMLNode* node, bool flag, vector<string>& result)
{
XMLNode* element;
if (!flag)
{
element = node->FirstChildElement();
}
else
{
element = node->NextSiblingElement();
}
if (element != nullptr)
{
if (element->ToElement()->GetText() == nullptr)
{
ParserXmlOperation(element, false, result);
}
else
{
string text(element->ToElement()->GetText());
result.push_back(text);
ParserXmlOperation(element, true, result);
}
}
else
{
if (strcmp("Root", node->Value()) != 0) {
ParserXmlOperation(node->Parent(), true, result);
}
}
}
int ParserXmlWithNodeValue(const char* fileName, map<string,string>& result)
{
XMLDocument xmlDoc;
XMLError tmpResult = xmlDoc.LoadFile(fileName);
if (tmpResult != XML_SUCCESS)
{
return tmpResult;
}
XMLNode* root = xmlDoc.RootElement();
ParserXmlOperationWithNodeValue(root, false, result);
return XML_SUCCESS;
}
void ParserXmlOperationWithNodeValue(XMLNode* node, bool flag, map<string,string>& result)
{
XMLNode* element;
if (!flag)
{
element = node->FirstChildElement();
}
else
{
element = node->NextSiblingElement();
}
if (element != nullptr)
{
if (element->ToElement()->GetText() == nullptr)
{
ParserXmlOperationWithNodeValue(element, false, result);
}
else
{
string text(element->ToElement()->GetText());
string keyValue = element->ToElement()->Value();
result.insert(map<string, string>::value_type(keyValue, text));
ParserXmlOperationWithNodeValue(element, true, result);
}
}
else
{
if (strcmp("Root", node->Value()) != 0) {
ParserXmlOperationWithNodeValue(node->Parent(), true, result);
}
}
}
bool ParserXmlWithNodeValue(string& _str, Result& _result)
{
map<string, string> rsCards;
int r = ParserXmlWithNodeValue(_str.c_str(), rsCards);
if (r != XML_SUCCESS)
{
return false;
}
map<string, string>::iterator rsCardsIter = rsCards.begin();
vector<unsigned char> parsedCards;
vector<uint16_t> parsedCounts;
vector<unsigned char> parsedLeftCards;
for (;rsCardsIter != rsCards.end();rsCardsIter++)
{
string keyValue = (*rsCardsIter).first;
if (keyValue == "Vesion")
{
_result.vesion = (*rsCardsIter).second;
}
else if (keyValue == "Cards")
{
ParserText((*rsCardsIter).second, ',', parsedCards);
}
else if (keyValue == "Count")
{
ParserText((*rsCardsIter).second, ',', parsedCounts);
}
else if (keyValue == "LeftCards")
{
ParserText((*rsCardsIter).second, ',', parsedLeftCards);
}
}
if (!parsedCards.empty() && !parsedCounts.empty())
{
vector<uint16_t>::iterator countsIter = parsedCounts.begin();
for (;countsIter != parsedCounts.end();countsIter++)
{
_result.countsList.push_back((*countsIter));
}
if (parsedCounts.size() == 5)
{
uint16_t index = 0;
for (uint16_t i = 0;i < 4; i++)
{
vector<unsigned char> tmpParsedCards;
for (uint16_t j = 0;j < parsedCounts[i];j++)
{
index = j + i * parsedCounts[i];
tmpParsedCards.push_back(parsedCards[index]);
}
_result.cards[i] = tmpParsedCards;
}
vector<unsigned char> tmpRestedCards;
for (uint16_t z = index; z <= index + parsedCounts[4];z++)
{
tmpRestedCards.push_back(parsedCards[z]);
}
_result.restCardsList = tmpRestedCards;
}
}
if (!parsedLeftCards.empty())
{
_result.outCardsList = parsedLeftCards;
}
return true;
}
bool ParserXml(string& _str, Result& _result)
{
vector<string> rsCards;
int r = ParserXml(_str.c_str(), rsCards);
if (r != XML_SUCCESS)
{
return false;
}
map<int, vector<unsigned char>> cards;
for (size_t i = 0;i < rsCards.size();i++)
{
vector<unsigned char> parsedCards;
ParserText(rsCards[i], ',', parsedCards);
if (i == 0)
{
vector<unsigned char> baiDaCardList;
baiDaCardList.push_back(parsedCards[0]);
_result.baiDaCardList = baiDaCardList;
}
else if (i == rsCards.size()-1)
{
_result.outCardsList = parsedCards;
}
else
{
_result.cards[i-1] = parsedCards;
}
}
return true;
}
Result.h
#pragma once
#include "stdafx.h"
class Result
{
public:
Result();
Result(std::vector<unsigned char> _baiDaCardList, std::map<int, std::vector<unsigned char>>_cards);
virtual ~Result();
public:
std::vector<unsigned char> baiDaCardList; //百塔牌的值
std::map<int,vector<unsigned char>> cards; //根据xml排的顺序存放配的牌
std::vector<unsigned char> restCardsList; //剩余的牌
std::vector<unsigned char> outCardsList; //不用的牌
std::vector<uint16_t> countsList; //每个玩家手牌数量,剩余牌数量
string vesion; //版本
public:
void View();
void Clear();
};