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


<Root>
    <Card>
        <Cards>0X11Cards>
        <Cardd>
        	<Cardds>0X12Cardds>
        	<Cardds>0X16Cardds>
        	<Carddss>
        		<hhlo>
        			<Cardss1>wor1Cardss1>
        			<Cardss1>wor2Cardss1>
        			<Cardss1>wor3Cardss1>
        			<Cardss1>wor4Cardss1>
        		hhlo>
        	Carddss>
        Cardd>
        <Cards>0X13Cards>
        <Cards>0X14Cards>
        <Cards>0X15Cards>
    Card>
    <Card>
        <Cards>0X11,0X12,0X13,0X18Cards>
    Card>
Root>

在这里我要获取Cards中0x11,tinyxml2中你可以获得XMLNode,但是要获得文本0x11,需要XMLElement,所以你要判断是否是XMLElement,是的话获得文本,是XMLNode,找下一个,因为没有Type()函数来判断
为了区分这两种类型,我在较长的测试中和看源码对于GetText()注释发现,可以用element->ToElement()->GetText() == nullptr 来判断,上源码注释图
C++中使用tinyxml2解析xml文件_第1张图片
注意红色画圈的地方,意思是这样的xml也就是返回null,所以正好符合我目前的需求

xml解析方法:

记录自己会用的xml方法或可能用到的方法,遇到后在总结补充,防止再次思考和重写
ParseXml.h

#pragma once

#include 
#include 
#include "tinyxml2.h"
#include 
#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>&] [allTextResult] [节点内所有的text文本]

	@return [string] [] [查找的状态]

	@attention
*/
std::string ParserCardOperation(tinyxml2::XMLNode* root, const char* nodeName, std::size_t count, std::vector>& allTextResult);

/*
	@brief 按照顺序解析出xml中所有的text
	@description
			解析的状态: XML_SUCCESS   成功
						其它			 失败
	@param [const char*] [path] [xml的文件名字]
	@param [vector>&] [result] [得到所有text的集合]

	@return [int] [] [解析的状态]

	@attention
*/
int ParserXml(const char* fileName, std::vector& result);

/*
	@brief ParserXml实现的细节操作,根据头节点递归
	@description
			flag	true	找与这个节点同级别的节点
					false	这个节点下的第一个元素节点
	@param [XMLNode*] [node] [节点]
	@param [bool] [flag] [用来判断是找这个节点下的第一个元素节点 还是 找与这个节点同级别的节点]
	@param [vector>&] [result] [得到所有text的集合]

	@return [] [] []

	@attention
		通过判断最后是否回退到了root节点来结束递归,不然就死循环中
*/
void ParserXmlOperation(tinyxml2::XMLNode* node, bool flag, std::vector& result);

/*
	@brief 按照顺序解析出xml中所有的text
	@description
	解析的状态: XML_SUCCESS   成功
	其它			 失败
	@param [const char*] [path] [xml的文件名字]
	@param [map&] [result] [得到所有text的集合 和 对应的 node 节点值]

	@return [int] [] [解析的状态]

	@attention
*/
int ParserXmlWithNodeValue(const char* fileName, std::map& result);

/*
	@brief ParserXml实现的细节操作,根据头节点递归
	@description
		flag	true	找与这个节点同级别的节点
				false	这个节点下的第一个元素节点
	@param [XMLNode*] [node] [节点]
	@param [bool] [flag] [用来判断是找这个节点下的第一个元素节点 还是 找与这个节点同级别的节点]
	@param [map&] [result] [得到所有text的集合 和 对应的 node 节点值]

	@return [] [] []

	@attention
	通过判断最后是否回退到了root节点来结束递归,不然就死循环中
*/
void ParserXmlOperationWithNodeValue(tinyxml2::XMLNode* node, bool flag, std::map& 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>& 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 s;
		s.push_back(str);
		allTextResult.push_back(s);
		i++;
	} while (isFindAll || (!isFindAll && i < count));

	return "XML_SUCCESS";
}

int ParserXml(const char* fileName, vector& 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& 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& 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& 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::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 rsCards;
	int r = ParserXmlWithNodeValue(_str.c_str(), rsCards);
	if (r != XML_SUCCESS)
	{
		return false;
	}
	map::iterator rsCardsIter = rsCards.begin();
	vector parsedCards;
	vector parsedCounts;
	vector 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::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 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 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 rsCards;
	int r = ParserXml(_str.c_str(), rsCards);

	if (r != XML_SUCCESS)
	{
		return false;
	}

	map> cards;
	for (size_t i = 0;i < rsCards.size();i++)
	{
		vector parsedCards;
		ParserText(rsCards[i], ',', parsedCards);
		if (i == 0)
		{
			vector 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 _baiDaCardList, std::map>_cards);
	virtual ~Result();
public:
	std::vector baiDaCardList;			//百塔牌的值
	std::map> cards;			//根据xml排的顺序存放配的牌
	std::vector restCardsList;			//剩余的牌
	std::vector outCardsList;			//不用的牌
	std::vector countsList;					//每个玩家手牌数量,剩余牌数量
	string vesion;										//版本
public:
	void View();
	void Clear();
};

你可能感兴趣的:(c++,xml)