分析多个文件
下面讲一个实际的例子:一个学生的网页作业的自动评分程序。这个程序首先由一些html文件来构建一些树形结构,然后把他们存储在一个@trees数组中:
my @ trees ; foreach ( @ files ) { print " building tree for $_ .../n" if $ options { v} ; my $ tree = HTML: : TreeBuilder- > new; $ tree - > parse_file( $ _ ) ; push ( @ trees , $ tree ) ; }
doitem()子函数遍历@trees数组,并且请求一个代码块来在每棵树中寻找特定的html元素,并且存贮代码块返回的结果。它调用printd()函数显示发现的html元素和这些元素所在的文件名(当使用-v选项被设置的话):
sub doitem { my $ func = shift ; my $ num = 0; foreach my $ i ( 0 . . $ #files ) { my @ elements = $ func - > ( $ files [ $ i ] , $ trees [ $ i ] ) ; printd $ files [ $ i ] , @ elements ; $ num + = @ elements ; } return $ num ; }
上面提到的代码块是一个需要两个参数的子函数,两个参数一个是文件名另一个是该文件对应的html树,它返回书中找到元素的数组。下面的例子代码将返回所有网页中的斜体字,包括<i>标签元素(例如:<i>text</i>)和font-style属性为斜体的元素(例如:<span STYLE="font-style: italic">text</span>).
$ n = doitem sub { my ( $ file , $ tree ) = @ _ ; return ( $ tree - > find( "i" ) , $ tree - > look_down( "style" = > qr/ font- style * : * italic/ ) ) ; } ; marking "Italicized text (2 points): " . ( ( $ n > 0 ) ? "good. 2" : "no italic text. 0" ) ;
这样,在页面中的斜体字的两种方式都被检测了。marking函数报告检测的结果,并且在程序的最后进行测试,帮助计算总节点数。
其他的需求可以使用相同的方法,下面的代码看上去更加难理解,它使用了一个正则帮助我们选出网页中没定义颜色的元素。
my $ pattern = qr/ ( ^ | [ ^ - ] ) color * : * rgb/( * [ 0- 9] * , * [ 0- 9] * , * [ 0- 9] * / ) / ; return $ tree - > look_down( "style" = > $ pattern , sub { $ _ [ 0] - > as_trimmed_text ne "" } ) ;
nvu(一个可视化网页编辑器)使用rgb(R,G,B)形式的style属性设置文本的颜色(例如:<span STYLE="color: rgb(0, 0, 255);">text</span>)。上面这段代码比斜体字的代码稍微严格一些,因为它还过滤那些没有包含任何文字的元素。代码中的as_trimmed_text()方法返回cut掉开头和结尾部空白字符的文本内容。
下面这段代码使用了嵌套的look_down()函数来定位有边框并且有连接的图表。它可以找到任何被<a>包裹的有边框的<img>。
return $ tree - > look_down( "_tag" = > "a" , sub { $ _ [ 0] - > look_down( "_tag" = > "img" , sub { hasBorder( $ _ [ 0] ) } ) ; } ) ;
检查没有连接的图表更加有趣,它需要look_down()和look_up()两个函数,下面这段代码只找出没有被<a>包裹的<img>元素。
return $ tree - > look_down( "_tag" = > "img" , sub { ! $ _ [ 0] - > look_up( "_tag" = > "a" ) and hasBorder( $ _ [ 0] ) ; } ) ;
检测正当的内部连接需要使用look_down()函数里的代码块排除一般的外部连接,通过检查href的值是否有协议名。还要验证连接到的文件是否真正存在。
use File: : Basename; $ n = doitem sub { my ( $ file , $ tree ) = @ _ ; return $ tree - > look_down( "_tag" = > "a" , "href" = > qr/ / , sub { ! ( $ _ [ 0] - > attr( "href" ) = ~ / ^ * ( http: | https: | ftp: | mailto: ) / ) and - e dirname( $ file ) . "/" . decodeURL( $ _ [ 0] - > attr( "href" ) ) ; } ) ; } ;
nvu通过指定body标签中的style的颜色属性来改变页面的字体颜色,就像:<body style="color: rgb(0, 0, 255);">。下面代码使用一个正则去匹配style属性并且取回三个颜色的值,任何不为零的颜色值就表示页面不是默认的颜色。
my $ pattern = qr/ ( ? : ^ | [ ^ - ] ) color * : * rgb/( ( * [ 0- 9] * ) , ( * [ 0- 9] * ) , ( * [ 0- 9] * ) / ) / ; return $ tree - > look_down( "_tag" = > "body" , "style" = > qr/ / , sub { $ _ [ 0] - > attr( "style" ) = ~ $ pattern and ( $ 1 ! = 0 or $ 2 ! = 0 or $ 3 ! = 0 ) ; } ) ;
合理的使用look_down(),look_up(),as_trimmed_text()等函数,我们的代码可以定位和标记出很html元素(图片,内部链接,背景图片等等)的存在。
<script type="text/javascript">
</script> <script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script>