xml文件的解析

分为两种解析方式:

方式一:sax方式解析

优点:逐行读取和解析,所以速度很快。

缺点:只能解析,不能往xml文件中写数据。


我们需要构建自己的xml解析类。这个类实现 抽象类 SaxDelegator,然后实现里面的3个纯虚函数。

——————————————————————————————————

yjh.xml文件内容:

<?xml version="1.0" encoding="UTF-8"?>
<All>
<Inform name="yjh" age="24" add="北京">
     <school>河南大学</school>
  <company>创思科技</company>
</Inform>
<Inform name="yy" age="25" add="上海">
     <school>北京大学</school>
  <company>清新科技园</company>
</Inform>
</All>

__________________________________________________________________

YjhParser.h

#ifndef YjhParser_h__
#define YjhParser_h__
#include "cocos2d.h"
using namespace cocos2d;
class YjhParser:public Ref,public SAXDelegator
{
public:
 //定义一个数组
 CC_SYNTHESIZE(ValueVector, list, List);
 std::string startElementName;//标签
 ValueMap row; //一行
public:
 //获取文件(这是两段式的写法,静态工厂设计模式)
 static YjhParser*  CreateWithXMLFile(std::string fileName);

 bool initWithXMLFile(std::string fileName);
 //实现代理的3个纯虚函数
 virtual void startElement(void *ctx, const char *name, const char **atts);

 virtual void endElement(void *ctx, const char *name);

 virtual void textHandler(void *ctx, const char *s, int len);

 
};

#endif // YjhParser_h__

________________________________________________________________ 

YjhParser.cpp

#include "YjhParser.h"

//获取解析xml文件的对象
YjhParser*  YjhParser::CreateWithXMLFile(std::string fileName)
{
 YjhParser *parse = new YjhParser;
 if (parse&&parse->initWithXMLFile(fileName)){
  
  parse->autorelease();
  return parse;
 }
 CC_SAFE_DELETE(parse);
 return nullptr;
}

//初始化函数

bool  YjhParser::initWithXMLFile(std::string fileName)
{
 SAXParser parser;
 parser.setDelegator(this);
 std::string filePath = FileUtils::getInstance()->fullPathForFilename(fileName);
 
 return parser.parse(filePath);
}


//实现代理的3个纯虚函数

//开始标签触发函数
void  YjhParser::startElement(void *ctx, const char *name, const char **atts){
 //忽略不用的字段
 CC_UNUSED_PARAM(ctx);
 startElementName = name;
 if (startElementName=="Inform")
 {
  row = ValueMap();
  for (int i = 0; atts[i];i+=2)
  {
   std::string key = (char*)atts[i];
   std::string value = (char*)atts[i+1];
   std::pair<std::string, Value> pair(key, Value(value));
   row.insert(pair);
  }
 }
}

//结束字段触发函数

void  YjhParser::endElement(void *ctx, const char *name){
 
 CC_UNUSED_PARAM(ctx);//不使用这个字段
 std::string endElementName = (char*)name;
 if (endElementName=="Inform")
 {
  //把一行的内容插入到数组中。
  list.push_back(Value(row));
 }

}

//文本内容触发函数

void  YjhParser::textHandler(void *ctx, const char *s, int len){
 CC_UNUSED_PARAM(ctx);//不使用这个字段

 //内容
 std::string content = std::string((char*)s, 0, len);
 std::pair<std::string, Value> pair(startElementName, Value(content));
 row.insert(pair);
}

__________________________________________________________________

YjhParserLayer.h

#ifndef YjhParserLayer_h__
#define YjhParserLayer_h__
#include "cocos2d.h"
#include "YjhParser.h" //自己实现的解析类
USING_NS_CC;
class YjhParserLayer:public Layer
{
public:
 static Scene* createScene();
 virtual bool init();
 CREATE_FUNC(YjhParserLayer);
public:
 //回调函数
 void callBack(Ref* pSender);
};

#endif // YjhParserLayer_h__

__________________________________________________________________

YjhParserLayer.cpp

#include "YjhParserLayer.h"
#include "MyUtility.h"

Scene* YjhParserLayer::createScene()
{
 auto scene = Scene::create();
 auto layer = YjhParserLayer::create();
 scene->addChild(layer);
 return scene;
}
bool YjhParserLayer::init()
{
 if (!Layer::init()){
  return false;
 }
 //创建一个按钮
 MenuItemImage *item = MenuItemImage::create("1.png", "2.png", CC_CALLBACK_1(YjhParserLayer::callBack,this));
 item->setPosition(Vec2(200, 200));
 Menu *menu = Menu::create(item, nullptr);
 menu->setAnchorPoint(Vec2::ZERO);
 menu->setPosition(Vec2::ZERO);
 this->addChild(menu);

 return true;
}

void YjhParserLayer::callBack(Ref* pSender)
{
 CCLOG("%s", MyUtility::gbk_2_utf8("Sax方式解析开始").c_str());
 //
  auto parser= YjhParser::CreateWithXMLFile("yjh.xml");
 ValueVector xmlVector= parser->getList();
 //遍历数组
 for (auto item:xmlVector){
  ValueMap row = item.asValueMap();
  //遍历字典
  for (auto dict:row)
  {
   log("%s=%s", dict.first.c_str(), dict.second.asString().c_str());
  }
 }

}

___________________

结果:

——————————————————————————————————————

网上的一些好的写法。


#pragma once
#include <string>
#include "cocos2d.h"
  
class XMLParser : public cocos2d::Ref, public cocos2d::SAXDelegator
{
public :
     static XMLParser* parseWithFile( const char *xmlFileName);
  
     static XMLParser* parseWithString( const char *content);
  
     XMLParser();
     virtual ~XMLParser();
 
     //从本地xml文件读取
     bool initWithFile( const char *xmlFileName);
     //从字符中读取,可用于读取网络中的xml数据
     bool initWithString( const char *content);
     
     //对应xml标签开始,如:<string name="app_name">
     virtual void startElement( void *ctx, const char *name, const char **atts);
      
     //对应xml标签结束,如:</string>
     virtual void endElement( void *ctx, const char *name);
  
     //对应xml标签文本
     virtual void textHandler( void *ctx, const char *s, int len);
  
     cocos2d::CCString* getString( const char *key);
  
private :
     cocos2d::CCDictionary *m_pDictionary;
     std::string m_key;
  
     std::string startXMLElement;
     std::string endXMLElement; 
  
};

#include "XMLParser.h"
 
using namespace std;
using namespace cocos2d;
 
//字符ascii码
// 空格
const static int SPACE = 32 ;
// 换行
const static int NEXTLINE = 10 ;
// tab 横向制表符
const static int TAB = 9 ;
 
XMLParser* XMLParser::parseWithFile( const char *xmlFileName)
{
     XMLParser *pXMLParser = new XMLParser();
     if ( pXMLParser->initWithFile(xmlFileName) )
     {
         pXMLParser->autorelease();  
         return pXMLParser;
     }
     CC_SAFE_DELETE(pXMLParser);
     return NULL;
}
 
bool XMLParser::initWithFile( const char *xmlFileName)
{
     m_pDictionary = new CCDictionary();
     SAXParser _parser;
     _parser.setDelegator( this );
     //获取文件全路径
     string fullPath = FileUtils::getInstance()->fullPathForFilename(xmlFileName);
     CCLog( "xml parser full path : %s" ,fullPath.c_str());
 
     return _parser.parse(fullPath);
}
 
XMLParser* XMLParser::parseWithString( const char *content)
{
     XMLParser *pXMLParser = new XMLParser();
     if ( pXMLParser->initWithString(content) )
     {
         pXMLParser->autorelease();  
         return pXMLParser;
     }
     CC_SAFE_DELETE(pXMLParser);
     return NULL;
}
 
bool XMLParser::initWithString( const char *content)
{
     m_pDictionary = new CCDictionary();
     SAXParser _parse;
     _parse.setDelegator( this );
     return _parse.parse(content, strlen(content) );
}
 
//开始一个节点
// 比如<string name="app_name">小黄人大作战</string>
//name    为     :string
//atts[0] 为属性   : name
//atts[1] 为值        : app_name
//atts[2] 以此类推
void XMLParser::startElement( void *ctx, const char *name, const char **atts)
{
     this ->startXMLElement = ( char *)name;
     CCLog( "start=%s" , startXMLElement.c_str()); //name
 
     if ( this ->startXMLElement == "string" )
     {
         while (atts && *atts)
         {
             CCLog( "attrs0=%s" , atts[ 0 ]);    //atts[0] : name
             CCLog( "attrs1=%s" , atts[ 1 ]);    //atts[1] : app_name
 
             const char *attsKey = *atts;   
             if ( 0 == strcmp(attsKey, "name" ))
             {
                 ++ atts;
                 const char *attsValue = *atts;
                 m_key = attsValue;          //key
                 break ;
             }
             ++ atts;
         }
 
     }
 
}
 
void XMLParser::endElement( void *ctx, const char *name)
{
     this ->endXMLElement = ( char *)name;
     CCLog( "end=%s" , endXMLElement.c_str());
}
 
void XMLParser::textHandler( void *ctx, const char *s, int len)
{
     string value(( char *)s, 0 , len);
 
     //是否全是非正常字符
     bool noValue = true ;
     for ( int i = 0 ; i < len; ++i)
     {
         if (s[i] != SPACE && s[i] != NEXTLINE && s[i] != TAB)
         {
             noValue = false ;   
             break ;
         }
     }
     if (noValue) return ;
     String *pString = String::create(value);
     CCLog( "key=%s value=%s" , m_key.c_str(), pString->getCString());
     this ->m_pDictionary->setObject(pString, this ->m_key);
}
 
String* XMLParser::getString( const char *key)
{
     string strKey(key);
     return (String *) this ->m_pDictionary->objectForKey(strKey);
}
 
XMLParser::XMLParser()
{
}
 
XMLParser::~XMLParser()
{
     CC_SAFE_DELETE( this ->m_pDictionary);
}



第二种解析方式:Dom解析方式

首先认识dom模型:

注意它有4类节点:

1.文档节点;

2.标记节点;

3.属性节点;

4.根节点;

通过文档节点获取根节点,通过根节点获得子节点,通过子节点获取子节点的属性节点。

层层递推的方式。

在这里有些需要注意的东西就是,实现方式的区别,Dom解析是将dom文档转换为字符串,保存到内存中,然后进行解析。

在做这个实验的时候,出错的地方很多。

但是最主要的是不要忘记引入tinyxml2.h文件,添加该库文件的搜索路径,然后就是解析函数的编写问题了。




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值