您的位置:首页 > 其它

针对特定XML的解析器XMLParser

2015-10-10 15:01 267 查看
一、建立网页库和偏移文件

为文本搜索引擎建立网页库,首先要把所有的网页(这里是文章)格式化,并保存到指定的格式中。如以下格式:
|
| <doc>
| <docid>...</docid>
| <url>...</url>
| <title>...</title>
| <content>...</content>
| </doc>
| <doc>
| ...
| </doc>
| ...

其中<doc>……</doc>保存着一篇文章;<docid>...</docid> 保存文档id;<url>...</url>保存文本路径;<content>...</content> 保存文章内容。

如何生成这样的格式呢?对每一篇文章使用以下方法:

首先从文章中提取标题 title;以及获得文章的路径,然后用字符串拼接,拼接成上述格式。

std::ofstream ofs("pages.lib",std::ios::out);//打开网页库
std::ofstream out("offset.lib",std::ios::out); //打开偏移文件
string txt = "<doc><docid>" + docid + "</docid>" + "<url>" + url + ... + "</doc>";
ofs << txt;     //写到文件流
int offset = ofs.tellg();// offset 获得当前指针的位置 ,tellg()和tellp()是C++文件流操作中获得流指针的函数
int length = txt.size();//length
out<<docid<<" "<<offset<<""<<length<<endl;//将这片文章的起始位置和偏移量写到偏移文件中,便于后面从网页库中读出一篇网页


循环对所有文章执行上面的操作,就得到一个网页库和一个偏移文件。

二、解析网页

根据偏移文件,从网页库中读出一篇网页,接着对网页库中的docid,title,url进行解析。

以下是解析器的代码:

#ifndef _XMLPARSER_HPP
#define _XMLPARSER_HPP
#include <stdio.h>
#include <utility>
#include <string>
#include <stdlib.h>
using namespace std;
class XMLParser
{
public:
XMLParser(string & page)
:page_(page)
{}
string parser(string tag)
{
string ltag,rtag;
ltag = "<"+tag+">";        //拼接左标签
rtag = "</"+tag+">";    //拼接右标签
string str;
//pair<string,string> pr;
string::size_type bpos;
string::size_type epos;
string::size_type len;
//确定字符串范围
bpos = page_.find(ltag);//查找作标签下标
epos = page_.find(rtag);//查找右标签下标
bpos+=ltag.size();
len = epos - bpos;        //计算标签包含内容长度
if(bpos==page_.npos||epos==page_.npos)
{
printf("No such tag: %s \n",tag.c_str());
exit(-1);
}
if(bpos==epos)
{
printf("标签内容不存在\n");
exit(-1);
}

string content = page_.substr(bpos+1,len-2);//截取标签包含内容
#if 0
if(content[content.size()-1]=='\n')
content[content.size()-1]=='\0';
if(content[content.size()-2]=='\n')
content[content.size()-2]=='\0';
if(content[content.size()-3]=='\n')
content[content.size()-3]=='\0';
#endif
//pr.first = tag;
//pr.second = content;
//return pr;    //最好使用std::move,减少复制
return content;
}
private:
string &page_;    //使用引用,避免大复制
};
#endif


解析器每次只能传入一个标签,并且返回标签对应的内容,要对所有标签进行解析,那么就要多次调用parser()。当然,对于一篇文章,就对应一个解析器对象,parser()是对外的一个函数,接收标签,并从对象中解析出便签包含的内容。也就是说,创建一个对象可以对这个对象调用多次parser(string tag)对文章进行解析。

三、解析器的使用

首先要有一个加载偏移文件的工具,这里写了一个工具PageOffset.hpp

(代码折叠)代码如下:

#ifndef _PAGEOFFSET_HPP
#define _PAGEOFFSET_HPP

#include <fstream>
#include <sstream>
#include <vector>
#include <string>
#include <utility>
#include <stdlib.h>
#include <stdio.h>
using namespace std;

class PageOffset
{
public:
PageOffset(string &path)
{
ifstream ifs(path.c_str(),ios::in);
string line;
string str;
pair<int,int> p1;
pair<int ,pair<int ,int > > p2;
while(getline(ifs,line),!ifs.eof())
{
istringstream iss(line);
int pos = 0;
while(iss>>str)
{
if(pos == 0)
{
p2.first = atoi(str.c_str());
}
else if(pos == 1)
{
p1.first = atoi(str.c_str());
}
else if(pos == 2)
{
p1.second = atoi(str.c_str());
p2.second = p1;
}
pos++;
}
offset.insert(p2);
}
ifs.close();
}

pair<int ,int > &operator[](int docid)
{
return offset[docid];
}

size_t size() const
{
return offset.size();
}
private:
map<int,pair<int,int> > offset;
};
#endif


View Code
测试程序代码如下:

#include "XMLParser.hpp"
#include "PageOffset.hpp"
#include <fstream>
#include <cstring>
#include <string>
#include <utility>
using namespace std;
int main()
{
ifstream ifs("pages.lib",ios::in);
PageOffset pageoffset("offset.lib");
char *buf = new char[1024*1024];                //开缓存空间
pair<int,int> page =(pageOffset)[vec[i]];        //从偏移文件中提取文档相应的offset与size,读出一篇文章
ifs.seekg(page.first,ios::beg);                    //定位文件起始位置
memset(buf,0,1024*1024);
ifs.read(buf,page.second);                        //读取一篇文档
string str(buf);                                //C风格的字符串转化为C++风格的字符串
XMLParser xmlparser(str);                        //将文章加入解析器,初始化一个解析器对象
string title = xmlparser.parser("title");        //解析标题
string url = xmlparser.parser("url");            //解析url
string content = xmlparser.parser("content");    //解析内容
delete []buf;                                    //释放缓存空间,防止内存泄露
return 0;
}


以上是针对特定格式的文本库进行解析。因此不能给适用于多种场合。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: