C++中使用tinyxml2解析xml文件

##题记:##
看到c++中有解析xml,花了点时间学习了tinyxml2的使用(有些方法在tinyxml1中没有了,还好摸索出了野路子),并且写了比较通用方法方便以后再次使用,如果以后再遇到关于xml操作可以再补充方法或优化方法(就是一句话,有的懒得再写了)

##参考:##
tinyxml使用笔记与总结
C++:tinyxml的使用
tinyxml使用指导
使用tinyXML2 读写配置文件
TinyXml查找唯一节点及修改节点操作
tinyxml的设计结构分析

##下载:##
tinyxml2 下载地址
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();
};

猜你喜欢

转载自blog.csdn.net/zbbzb/article/details/80084242
今日推荐