woaidongmao

文章均收录自他人博客,但不喜标题前加-[转贴],因其丑陋,见谅!~
随笔 - 1469, 文章 - 0, 评论 - 661, 引用 - 0
数据加载中……

用YACC提高XML在C++中的解析性能

在C++中,解析XML文件通常需要使用XML的解析类或库,如DOM(DOCUMENT OBJECT MODEL)或SAX(SIMPLE API FOR XML),来解析XML文件,从而得到所需的数据。虽然比较方便,但是这种方法的效率不是很高,而把XML解析为C++的类,不但能提高解析的效率,而且还能提供给用户面向对象的所有优点。

一. 通常用DOMSAX解析XML文件所带来的问题

C++的程序在处理XML文件时常常会碰到解析的问题,有时需要根据一定的规则自己写一个解析的类或包。因此,使用DOM或SAX来解析XML文件就显得相对比较简单。但是解析XML文件,一个非常重要的问题,即对于一些不同的语言,如JAVA,C++,XML没有一个固定的标签(如关键字),因此,开发一个适合于多种语言的通用解析器就显得非常由必要。

为了解决这个问题,开发出的这个解析器要能动态的列出标签和解析XML文件的规则。即对于一个DOM的解析器要确定一个XML的模式文件,从而可以对XML文件中的内容进行有效性的确认。

如果一个应用程序需要对XML文件进行不同的读写操作,DOM这个解析模式是非常合适的。因为它对于不同的XM文件,它的源代码都不需要改变。但是,引用程序对XML文件的操作由可能进行的比较少,在这种情况下,如果使用DOM解析器解析XML文件,就加重程序的负担。因此,根据不同的情况来选择不同的解析器,使非常有必要的。而且有时还需自己开发出一个合适的解析器。

二. XML模式(SCHEMAS)中派生出的静态类

和在某些情况下可以从XML模式中派生出C++类,对XML文件进行写操作,提高程

序的效率一样,也可以从XML模式中派生出C++类,对XML文件进行解析,即读操作。

在C++中,为了生成某个语言的解析类,通常需要如下的步骤:首先需要编写LEX规则或YACC语法的代码,然后在根据特定的XML输入文件生成LEXER和解析类。如下图一所示:

clip_image001[3]

但是,这个过程非常繁琐,而且对于每个不同的XML文件形式,都需要重复进行如下的步上的步骤。一个更有效的做法是先编写一个用作翻译的程序,把XML模式文件转化为相对应的LEX规则或YACC语法,如下图二所示:

clip_image002[3]

下面的程序(程序一)说明了对于一个XML的DTD文件ACMEPC.DTD所生成的语法。

acmepcxml::XMLImporter importer;

// Call the acmepcxml::Initialize() function to register the create functions

// for the acmepcxml classes

acmepcxml::Initialize();

try {

importer.ImportFromFile(sInputFileName, fPreprocess);

}

catch (eXactML::XException & e)

{

std::cerr << e.GetMsg() << std::endl;

std::cerr << "in " << e.GetSourceFile() << " at line number " <<

e.GetSourceLine() << std::endl;

return 1;

}

cout << "Read in XML file with no errors." << std::endl;

acmepc *acmepc = dynamic_cast (importer.GetXObject());

cout << "Successfully cast XML importer root to acmepcxml::acmepc" << std::endl;

// validate the data in the classes, throws an exception if bad.

try {

acmepc->IsValid();

}

catch (eXactML::XException & e) {

cout << "Exception in validating XML" << std::endl;

cout << e.GetMsg() << std::endl;

eXactML::XMLImporterBase::DeleteImportedXObject(acmepc);

return 1;

}

cout << "Validated acmepcxml::acmepc object" << std::endl;

// generate the XML

try {

acmepc->EmitXML(cout);

}

catch (eXactML::XException e) {

cout << "Exception in generating XML" << std::endl;

cout << e.GetMsg() << std::endl;

eXactML::XMLImporterBase::DeleteImportedXObject(acmepc);

return 1;

}

cout << "Emitted XML to file worked fine." << std::endl;

eXactML::XMLImporterBase::DeleteImportedXObject(acmepc);

return 0;

程序一

type CDATA #REQUIRED

speed CDATA #REQUIRED>

type (IDE|EIDE|SCSI) "IDE"

size CDATA #REQUIRED

units (GB|TB) "GB">

n CDATA #REQUIRED

units CDATA #REQUIRED>

n CDATA #REQUIRED

units CDATA #REQUIRED>

ACMEPC.DTD文件

在ACMEPCXML_PARSER.Y中生成的YACC输入和在ACMEPCXML_LEXER.L中生成的LEX输入。所有的这些类和解析器都包含在C++中的ACMEPCXML的名字空间中。

使用这个生成的通用解析器非常简单,只需生成类ACMEPCXML::XMLIMPORTER的一个实例,然后调用类中的Initiliaze()这个初始化的成员函数,在把XML文件传给ImportFromFile()这个程序函数。这个引入的类通过GetXObject()来发布这个树形的根结点。这个基本的类在动态的返回给在ACMEPC.DTD文件中定义的XML上下文的ACMPEPC类。

三. 生成的通用解析类的优点

同一些其它的标准解析器或类相比,如DOM,SAX,自己生成的通用解析类主要由如下的几个特点和优点。

1. 最根本也是最重要的─解析的速度快。经过测试,根据XML模式生成的通用解析器,要比最快的DOM解析器速度要快三倍以上,而且内存的占用也很少。这主要是因为对于XML文件的输入不需要经过有效性的检查和判断。这个工作早在由输入文件生成YACC时,就已经做好和强制性的检查。

2. 生成的通用解析器能和其它的派生类非常好的结合在一起。而且不用象使用DOM一样,生成一个DOM的数形结构,然后在对这些数据进行操作。通用解析器能直接的生成XML模式的派生类,这样就省去了中间的步骤。当然,该解析类也能很好的和STL或MFC的类库结合在一起

3. 你能得到链接到你应用程序组件的所用源代码。只要严格遵循符合GNU规范的FLEX和BISON工具的使用,生成的代码就能够在任何的操作系统上运行,从而很好的解决了跨平台的问题。

4. 最后也是最令人激动的一个优点是使用LEX和YACC可以方便的来操作和处理XML文件中的实体元素(ENTITY)。你可以在输入文件中自动扩展实体的数量。XML中的实体也可以如C程序中的宏定义一样,是C编译器提前预处理。当你要处理大量的实体元素是,将非常有效。

四. 总结

由XML模式(SCHEMA)生成C++的类,作为解析器来解析XML的输入文件是件非常令人激动的事,它不但能减少重复的编码,更能提高你的效率。在不久的将来该项技术将会由长足的发展。

五. 附该程序的所有源代码(包括C++的类和DTD文件,XML文件

xmlparser.zip

posted on 2008-11-22 14:27 肥仔 阅读(1213) 评论(1)  编辑 收藏 引用 所属分类: XMLLEX & YACC

评论

# re: 用YACC提高XML在C++中的解析性能  回复  更多评论   

少文件呢??
2009-02-05 15:11 | ww

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理