PERL/LEX/YACC技术实现文本解析--XML解析
继周六的p_enum.pl后,再来一篇说说我用perl做的lex,yacc工具。之前说了,我学习lex和yacc的最初动机是为了做个C语言解释器的SHELL;但后来工作中的实际需要也是制作perl版lex和yacc的一个动机。Perl库里有lex和yacc,我没研究过,想来应该比我做的强大,不过对新手来说,未必能容易入手。
我的第一个应用场景是做一个xml配置文件的排序。XML是标签标记语言,同一级下,TAG顺序本身是无所谓的;但对于测试工作来说,经常要通过文本比较工作来确定两个配置文件差别。如果没有办法将配置文件内容正确排序,对比一个几十K的配置文件,就会耗费个把钟头。对于有频繁对比内容的测试需要来说,这绝对是无法忍受。
那期间,我正在研究编译原理,以及lex和yacc,自然萌生了做个xml解析器的想法。有了xml解析器,就能将xml内容按hash、array组合方式在perl里表达成对应的数据结构,而排序也就自然不再是个问题。
工具及xml示例下载地址:
http://files.cnblogs.com/files/hhao020/perl_zlib_re0.001.rar
要做xml的解析,首先需要定义lex词法文件xml.lex:
%%prioritized from top to bottom
<!--.*--> := comment
<\?.*?> := version
</.*?> := end
<.*?/ > := sigton
<.*> := begin
:= value
接着,需要定义yacc的语法文件xml.yacc:
%yacc%
%%prioritized from bottom to top
xml := version EOF { Xml_Version }
| version pair EOF { Xml_VersionPair }
pair := pair pair { Pair_PairPair }
pair := begin end { Pair_BeginEnd }
| begin value end { Pair_BeginValueEnd }
| begin pair end { Pair_BeginPairEnd }
| begin value pairs end { Pair_BeginValuePairEnd }
| sigton { Pair_Sigton }
| comment { Pair_Comment } %code%
package xml;
use strict;
use warnings; sub _XmlAlarmMock
{
print @_;
}
sub _XmlDebugMock
{
my $debugInfo = shift;
#print "$debugInfo\n"; sub _printMock{print @_;};
#&zDebug::DataDump(\&_printMock, \@_);
} sub _XmlCheckNode
{
my $refNode = shift; if($refNode->{BEGIN})
{
my $begin = $refNode->{BEGIN}->{TEXT};
my $end = $refNode->{END}->{TEXT}; printf("##### check node $begin, $end.\n"); $begin =~ /^<([a-zA-Z_0-]+)/;
my $a = $;
$end =~ /^<\/([a-zA-Z_0-]+)/;
my $b = $; if($a ne $b)
{
&zDebug::DataDump(\&_XmlAlarmMock, $refNode);
&zDebug::DataDump(\&_XmlAlarmMock, $refNode->{BEGIN});
&zDebug::DataDump(\&_XmlAlarmMock, $refNode->{END});
my $line = $refNode->{BEGIN}->{LINE};
print "\nBEGIN <$a> at LINE [$line] missing END!!!\n";
exit();
}
}
=pod
if($refNode->{VALUE})
{
my $value = $refNode->{VALUE}->{TEXT}; if($value =~ /[<>]/)
{
&zDebug::DataDump(\&_XmlAlarmMock, $refNode);
&zDebug::DataDump(\&_XmlAlarmMock, $refNode->{VALUE}); print "\nVALUE contains <>!!!\n";
exit();
}
}
=cut
} sub _XmlCheckValue
{
my $refNode = shift; } sub Xml_Version
{
my @params = @_;
&_XmlDebugMock(&zError::FunName().' ['.&zError::FileLine().']', \@_); my @pair;
my %xml = (VERSION=>$params[], PAIR=>\@pair); return \%xml;
} sub Xml_VersionPair
{
my @params = @_;
&_XmlDebugMock(&zError::FunName().' ['.&zError::FileLine().']', \@_); my %xml = (VERSION=>$params[], PAIR=>$params[]);
return $params[];
} sub Pair_BeginEnd
{
my @params = @_;
&_XmlDebugMock(&zError::FunName().' ['.&zError::FileLine().']', \@_); my %node;
$node{BEGIN} = $params[];
$node{END} = $params[]; &_XmlCheckNode(\%node); my @pair = (\%node,);
return \@pair;
} sub Pair_BeginValueEnd
{
my @params = @_;
&_XmlDebugMock(&zError::FunName().' ['.&zError::FileLine().']', \@_); my %node;
$node{BEGIN} = $params[];
$node{VALUE} = $params[];
$node{END} = $params[]; &_XmlCheckNode(\%node); my @pair = (\%node,);
return \@pair;
} sub Pair_Sigton
{
my @params = @_;
&_XmlDebugMock(&zError::FunName().' ['.&zError::FileLine().']', \@_); my %node;
$node{SIGTON} = $params[]; my @pair = ($params[],);
return \@pair;
} sub Pair_Comment
{
my @params = @_;
&_XmlDebugMock(&zError::FunName().' ['.&zError::FileLine().']', \@_); my %node;
$node{COMMENT} = $params[]; my @pair = (\%node,);
return \@pair;
} sub Pair_BeginPairEnd
{
my @params = @_;
&_XmlDebugMock(&zError::FunName().' ['.&zError::FileLine().']', \@_); my %node;
$node{BEGIN} = $params[];
$node{PAIR} = $params[];
$node{END} = $params[]; &_XmlCheckNode(\%node); my @pair = (\%node,);
return \@pair;
} sub Pair_BeginValuePairEnd
{
my @params = @_;
&_XmlDebugMock(&zError::FunName().' ['.&zError::FileLine().']', \@_); my %node;
$node{BEGIN} = $params[];
$node{VALUE} = $params[];
$node{PAIR} = $params[];
$node{END} = $params[]; &_XmlCheckNode(\%node); my @pair = (\%node,);
return \@pair;
} sub Pair_PairPair
{
my @params = @_;
&_XmlDebugMock(&zError::FunName().' ['.&zError::FileLine().']', \@_); push @{$params[]}, @{$params[]}; return $params[];
}
最后是应用程序部分p_xml.pl:
#/usr/bin/perl
use strict;
use warnings; use zFile;
use zTrace; use zError;
use zDebug;
use zLex; use zLex;
use zYacc; sub main
{
my $lex = zLex->New(@ARGV);
$lex->SetupFile('xml.lex');
#$lex->PrintDocLex(); my $yacc = zYacc->New(@ARGV);
$yacc->SetupFile('xml.yacc'); $yacc->SaveCode('xml.pm');
#$yacc->ImportCode('xml', 'xml'); $yacc->PrintGrammarTree();
$yacc->PrintConflictTree(); my $text = $lex->ParserFile('sample0.xml');
&DataDump(\&TraceDebug, $text); my @re = $yacc->Compile($text); &DataDump(undef, \@re);
} &main();
样例只做了xml到内存数据结构的解析。
测试用xml文件sample0.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!--Settings for MSP--> <Config>
<tag1> value1 </tag1>
< Single Node / >
</Config>
很可惜,当时做的最终版本丢了,只有这个中间版本,对某些细节处理不是很好。YACC在不能做reduce操作时,应该进行shift操作。这个版本当时大概为了解决大文本文件信息摘录问题,新加了冲突预测优化,导致某些时候错误的拒绝shift操作。等过些天有空了,将这个问题修正后再更新。比如,下面这个文件处理会因此失败:
<?xml version="1.0" encoding="UTF-8"?>
<!--Settings for MSP--> <Config> abc
<tag1> value1 </tag1>
< Single Node / >
</Config>
运行perl p_xml.pl -dstack -dcompile可以看到shift,reduce过程。
Lex相对比较简单。Yacc在设计时,常常会被移进和归约规则困挠。基本原理很简单,就是不能归约时,即移进。但现实情况下,不同的问题需要的处理过程差别还是蛮大。这也是的我做的Lex和Yacc多次改动,也就带来了bug,待有机会好好整理下。
PERL/LEX/YACC技术实现文本解析--XML解析的更多相关文章
- UI进阶 解析XML 解析JSON
1.数据解析 解析的基本概念 所谓“解析”:从事先规定好的格式中提取数据 解析的前提:提前约定好格式,数据提供方按照格式提供数据.数据获取方则按照格式获取数据 iOS开发常见的解析:XML解析.JSO ...
- iOS-数据解析XML解析的多种平台介绍
在iPhone开发中,XML的解析有很多选择,iOS SDK提供了NSXMLParser和libxml2两个类库,另外还有很多第三方类库可选,例如TBXML.TouchXML.KissXML.Tiny ...
- xml解析技术
本文总结Dom,sax解析, 使用Java作为工具解析xml文档. 1 Dom 综述:Dom解析xml通常也称为xmlDom (和htmlDom技术差不多),将xml文档封装成树,好处就是xml中的 ...
- Lex+YACC详解
1. 简介 只要你在Unix环境中写过程序,你必定会邂逅神秘的Lex&YACC,就如GNU/Linux用户所熟知的Flex&Bison,这里的Flex就是由Vern Paxon实现的一 ...
- JAVA基础学习之XMLCDATA区、XML处理指令、XML约束概述、JavaBean、XML解析(8)
1.CDATA区在编写XML文件时,有些内容可能不想让解析引擎解析执行,而是当作原始内容处理.遇到此种情况,可以把这些内容放在CDATA区里,对于CDATA区域内的内容,XML解析程序不会处理,而是直 ...
- XML详解:第三部分 XML解析
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
- xml解析总结-常用需掌握
Xml文档的解析 XML解析方式分为两种:DOM方式和SAX方式 DOM:Document Object Model, 文档对象模型.这种方式是W3C推荐的处理XML的一种方式. SAX:Simple ...
- XML概念定义以及如何定义xml文件编写约束条件java解析xml DTD XML Schema JAXP java xml解析 dom4j 解析 xpath dom sax
本文主要涉及:xml概念描述,xml的约束文件,dtd,xsd文件的定义使用,如何在xml中引用xsd文件,如何使用java解析xml,解析xml方式dom sax,dom4j解析xml文件 XML来 ...
- XML解析器之JAXP与DOM4J
XML是一种数据格式,那么需要对XML文件进行操作就需要用到XML解析器---------针对dom方式和sax方式提供了不同的解析技术-----需要不同的XML解析器 dom方式:会把文档中所有元素 ...
随机推荐
- jquery选择器 之 获取父级元素、同级元素、子元素
jquery选择器 之 获取父级元素.同级元素.子元素 一.获取父级元素 1. parent([expr]): 获取指定元素的所有父级元素 <div id="par_div" ...
- DB2 runstats、reorgchk、reorg 命令
runstats.reorgchk.reorg 1.runstats runsats可以搜集表的信息,也可以搜集索引信息.作为runstats本身没有优化的功能,但是它更新了统计信息以后,可以让DB2 ...
- 使用Maven自动部署Java Web应用到Tomcat服务器
学习如何使用Maven,我推荐一本工具书,<maven the definitive guide>.在这本工具书手中,详细介绍了maven的使用思想,并且提供了从基本到复杂的具体项目应用. ...
- 转载 --ios 模型-setValuesForKeysWithDictionary
应用场景:app请求后端数据,返回的数据是JSON形式,如: { "is_favor" = 0; "is_follow" = 0; "is_prais ...
- Java基础知识系列——String
最近晚上没有什么事(主要是不加班有单身),就复习了一下Java的基础知识.我复习Java基础知识主要是依据Java API和The Java™ Tutorials. 今天是第一篇,复习了一下Strin ...
- Xcode导航栏不显示模拟器选择框ToolBar
不显示ToolBar的小伙伴可能就是下面的样子: 全屏后就可以看到ToolBar,像下面这样: 刚开始还以为是模拟器没装,还傻不拉几的去下载模拟器,后来才发现,只要下面的操作即可显示 点击" ...
- VS2010+C#+在新建类或接口时在文件开头自动生成作者和日期等备注
今天在公司项目准备开始,为达到项目的规范管理,要求每个文件的标准日期,作者等信息,搜集了百度的资料,新建文件时效果如下: 其实原理很简单,只要修改VS,IDE文件下的类(或接口)模版代码 文件路径:C ...
- jquery each遍历节点使用
---恢复内容开始--- $("#aaa :input[type='text']").each(function(i){ alert(this.value); this.v ...
- Form表单(回车)提交问题
我们有时候希望回车键敲在文本框(input element)里来提交表单(form),但有时候又不希望如此.比如搜索行为,希望输入完关键词之后直接按回车键立即提交表单,而有些复杂表单,可能要避免回车键 ...
- Web工作原理
第一步:寻找域名服务器,将域名(www.nice.com)的主机解析成服务器的ip的地址. 第二步:使用http协议连接Apache网页服务器,请求到服务器对应的目录下的文件,例如:index.php ...