xml文件的解析

来源:互联网 发布:怎么阻止软件自动更新 编辑:程序博客网 时间:2024/04/29 14:56

分为两种解析方式:

方式一: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:
    staticXMLParser* parseWithFile(constchar*xmlFileName);
  
    staticXMLParser* parseWithString(constchar*content);
  
    XMLParser();
    virtual ~XMLParser();
 
    //从本地xml文件读取
    bool initWithFile(constchar*xmlFileName);
    //从字符中读取,可用于读取网络中的xml数据
    bool initWithString(constchar*content);
     
    //对应xml标签开始,如:<string name="app_name">
    virtualvoidstartElement(void*ctx,constchar*name, constchar**atts);
      
    //对应xml标签结束,如:</string>
    virtualvoidendElement(void*ctx,constchar*name);
  
    //对应xml标签文本
    virtualvoidtextHandler(void*ctx,constchar*s, intlen);
  
    cocos2d::CCString* getString(constchar*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(constchar*xmlFileName)
{
    XMLParser *pXMLParser =newXMLParser();
    if( pXMLParser->initWithFile(xmlFileName) )
    {
        pXMLParser->autorelease();  
        returnpXMLParser;
    }
    CC_SAFE_DELETE(pXMLParser);
    returnNULL;
}
 
bool XMLParser::initWithFile(constchar*xmlFileName)
{
    m_pDictionary =newCCDictionary();
    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(constchar*content)
{
    XMLParser *pXMLParser =newXMLParser();
    if( pXMLParser->initWithString(content) )
    {
        pXMLParser->autorelease();  
        returnpXMLParser;
    }
    CC_SAFE_DELETE(pXMLParser);
    returnNULL;
}
 
bool XMLParser::initWithString(constchar*content)
{
    m_pDictionary =newCCDictionary();
    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,constchar**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
 
            constchar*attsKey = *atts;   
            if(0== strcmp(attsKey,"name"))
            {
                ++ atts;
                constchar*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,intlen)
{
    string value((char*)s,0, len);
 
    //是否全是非正常字符
    bool noValue =true;
    for(inti =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(constchar*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文件,添加该库文件的搜索路径,然后就是解析函数的编写问题了。




0 0