使用Perl将CSS样式属性转换为HTML属性

时间:2009-08-26 20:38:54

标签: html css perl

真正的快速背景:我们有一个将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;

3 个答案:

答案 0 :(得分:5)

由于以下几个原因,你将度过非常艰难的时期:

  • 使用CSS可以完成的大多数事情都无法使用HTML属性完成。要处理这个问题,你要么必须忽略或试图补偿边距和填充等内容......
  • HTML属性和CSS之间对应的许多内容实际上表现略有不同,您需要考虑到这一点。要解决这个问题,你必须为每个差异编写特定的代码......
  • 由于CSS规则的应用方式,您基本上需要使用完整的CSS引擎来解析并应用所有规则,然后才能知道在元素/属性级别需要完成哪些操作。要解决这个问题,您可以忽略除内联样式之外的任何内容,但是......

这项工作几乎与为浏览器编写渲染引擎一样复杂。你可能能够处理一些特定的案例,但即便如此,你的成功率最多也是偶然的。

编辑:鉴于您的特定功能集,我可以就您的实施提供一些建议:

您希望不区分大小写,并在查找样式属性的值时使用非贪婪的匹配,即:

$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::TreeBuilderHTML::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 标记。

与这些模块一致,您还可以查看CSSCSS::DOM来帮助解析CSS位。

答案 2 :(得分:2)

我不知道您对专有软件的立场,但PrinceXML是最好的HTML到PDF转换器。