真正的快速背景:我们有一个将html转换为pdf的PDFMaker(HTMLDoc)。 HTMLDoc并不总是从客户端提供给我们的html中获取我们需要的样式。因此我试图转换诸如style =“width:80px; height:90px;”之类的东西。到高度= 80宽度= 90。
到目前为止,我的尝试揭示了我对后向引用的有限理解以及如何在Perl Regex中正确使用它们。我可以将输入文件转换为输出文件,但每行只捕获一个“样式”,并且只替换该css中的一个名称/值对。
我可能以错误的方式接近这个但我无法找到更快或更聪明的方法在Perl中执行此操作。任何帮助将不胜感激!
注意:我正在尝试为这个特定脚本更改的唯一属性是“高度”,“宽度”和“边框”,因为我们的客户端使用的工具会自动将样式应用于他们使用WYSIWYG拖动的元素风格的编辑。显然,使用正则表达式从很多地方剥离它们的效果相当不错,因为你只是让表格单元格按其内容调整大小,看起来没问题,但我认为更快的方法来处理这个问题只是为了用“width”“height”和“border”属性替换这三个属性,这些属性的行为与它们的css对应物大致相同(除了CSS允许你实际自定义边框的宽度,颜色和样式,但它们都是使用是固定的1px,所以我可以添加一个条件来将“solid 1px”替换为“border = 1”。我意识到这些并不完全等效,但对于这个应用程序来说这将是一个步骤。
这是我到目前为止所得到的:
#!/usr/bin/perl
if (!@ARGV[0] || !@ARGV[1])
{
print "Usage: converter.pl [input file] [output file] \n";
exit;
}
open FILE, "<", @ARGV[0] or die $!;
open OUTFILE, ">", @ARGV[1] or die $!;
my $line;
my $guts;
while ( <FILE> ) {
$line = $_ ;
$line =~ /style=\"(.+)\"/;
$guts = $1;
$guts =~ /([a-zA-Z]+)\:([a-zA-Z0-9]+)\;/;
$name = $1;
$value = $2;
$guts = $name."=".$value;
$line =~ s/style=\"(.+)\"/$guts/g;
print OUTFILE $line ;
}
exit;
注意:这不是家庭作业,不,我不是要求你为我做我的工作,这最终会成为一个内部工具,只是加快格式化我们传入的HTML以便在pdf中正常工作的过程转换器我们有。
更新
对于那些感兴趣的人,我得到了一个初步的工作版本。这个只替换宽度和高度,我们现在正在废弃的border属性。但如果有人想看看我们是怎么做的,那就去看看......
#!/usr/bin/perl
## NOTES ##
# This script was made to simply replace style attributes with their name/value pair equivalents as attributes.
# It was designed to replace width and height attributes on a metric buttload of table elements from client data we got.
# As such, it's not really designed to handle more than that, and only strips the unit "PX" from the values.
# All of these can be modified in the second foreach loop, which checks for height and width.
if (!@ARGV[0] || !@ARGV[1])
{
print "Usage: quickvert.pl [input file] [output file] \n";
exit;
}
open FILE, "<", @ARGV[0] or die $!;
open OUTFILE, ">", @ARGV[1] or die $!;
my $line;
my $guts;
my $count = 1;
while ( <FILE> ) {
$line = $_ ;
my (@match) = $line =~ /style=\"(.+?)\"/g;
my $guts;
my $newguts;
foreach (@match) {
#print $_ ."\n";
$guts = $_;
$guts =~ /([a-zA-Z]+)\:([a-zA-Z0-9]+)\;/;
$newguts = "";
foreach my $style (split(/;/,$guts)) {
my ($name, $value) = split(/:/,$style);
$value =~ s/px//g;
if ( $name =~ m/height/g || $name =~ m/width/g ) {
$newguts .= "$name='$value' ";
} else {
$newguts .= "";
}
}
#print "replacing $guts with $newguts on line $count \n";
$line =~ s/style=\"$guts\"/$newguts/i;
}
#print $newguts;
print OUTFILE $line ;
$count++;
}
exit;
答案 0 :(得分:5)
由于以下几个原因,你将度过非常艰难的时期:
这项工作几乎与为浏览器编写渲染引擎一样复杂。你可能能够处理一些特定的案例,但即便如此,你的成功率最多也是偶然的。
编辑:鉴于您的特定功能集,我可以就您的实施提供一些建议:
您希望不区分大小写,并在查找样式属性的值时使用非贪婪的匹配,即:
$line =~ /style=\"(.+?)\"/i;
因此,您只能查找到下一个双引号的内容,而不是直到最后双引号的整行内容。此外,如果未找到匹配项,您可能希望跳过该行,因此:
next unless ($line =~ /style=\"(.+?)\"/i);
为了解析胆量,我使用split
而不是正则表达式:
my $newguts;
foreach my $style (split(/;/,$guts)) {
my ($name, $value) = split(/:/,$style);
$newguts .= "$name='$value' ";
}
$line =~ s/style=\"$guts\"/$newguts/i;
当然,这是Perl有标准的咒语,例如总是使用严格和警告,尝试使用命名匹配而不是$1
,$2
等,但我试图限制我建议的东西可以立即推动你的解决方案。
答案 1 :(得分:3)
在CPAN上查看HTML解析模块,例如HTML::TreeBuilder,HTML::DOM甚至是XML::LibXML等XML模块。
以下是使用HTML :: TreeBuilder的快速示例,该示例将 border =“1”属性添加到具有 style 属性 border 的任何标记含量:
use strict;
use warnings;
use HTML::TreeBuilder;
my $data =q{
<html>
<head>
</head>
<body>
<h1>blah</h1>
<p style="color: red;">Red</p>
<span style="width:80px;height:90px;border: 1px solid #000000">Some text</span>
</body>
</html>
};
my $tree = HTML::TreeBuilder->new;
$tree->parse_content( $data );
for my $style ( $tree->look_down( sub { $_[0]->attr('style') } ) ) {
my $prop = $style->attr( 'style' );
$style->attr( 'border', 1 ) if $prop =~ m/border/;
}
say $tree->as_HTML;
哪个会重现HTML,但 border =“1”只添加到 span 标记。
答案 2 :(得分:2)
我不知道您对专有软件的立场,但PrinceXML是最好的HTML到PDF转换器。