代码之家  ›  专栏  ›  技术社区  ›  NateDSaint

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

  •  4
  • NateDSaint  · 技术社区  · 17 年前

    真实快速背景:

    到目前为止,我的尝试揭示了我对反向引用以及如何在Perl正则表达式期间正确利用它们的有限理解。我可以获取一个输入文件并将其转换为输出文件,但它每行只捕获一个“样式”,并且只替换该css中的一个名称/值对。

    我可能用了错误的方法来实现这一点,但我无法找到一种更快或更智能的方法在Perl中实现这一点。任何帮助都将不胜感激!

    注意:我试图为这个特定脚本更改的唯一属性是“高度”、“宽度”和“边框”,因为我们的客户机使用了一个工具,可以自动将样式应用于元素,这些元素通过WYSIWYG样式编辑器拖动。显然,使用正则表达式从很多地方去除这些属性效果相当好,因为您只需根据其内容调整表格单元格的大小,这看起来还可以,但我认为解决此问题的更快方法是将这三个属性替换为“宽度”、“高度”和“边框”属性,它们的行为与css的对应项基本相同(除了css允许您实际自定义边框的宽度、颜色和样式,但它们所使用的都是实心1px,因此我可以添加一个条件,将“实心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转换器中正常工作。

    使现代化

    #!/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 回复  |  直到 17 年前
        1
  •  5
  •   Adam Bellaire    17 年前

    由于以下几个原因,您将面临非常困难的时间:

    • 大多数可以用CSS完成的事情不能用HTML属性完成。为了解决这个问题,你要么忽略,要么试图补偿一些东西,比如边距和填充,等等。。。
    • HTML属性和CSS之间对应的许多东西的行为实际上略有不同,您需要对此做出解释。要解决这个问题,您必须为每个差异编写特定的代码。。。
    • 由于CSS规则的应用方式,您基本上需要使用完整的CSS引擎来解析和应用所有规则,然后才能知道在元素/属性级别需要做什么。为了解决这个问题,你可以忽略任何东西,除了内联样式,但是。。。

    这项工作几乎和为浏览器编写渲染引擎一样复杂。你也许能够处理一些特定的案例,但即使在那里,你的成功率也只是偶然的。

    编辑: 考虑到您非常具体的功能集,我可以给您一些关于实现的建议:

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

    $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 ,等等,但我试图将我的建议限制在能够立即推动解决方案的内容上。

        2
  •  3
  •   AndyG    9 年前

    看看 CPAN 对于HTML解析模块,如 HTML::TreeBuilder , HTML::DOM XML::LibXML .

    下面是使用HTML::TreeBuilder的快速示例,其中添加了 属性设置为具有 边境 内容:

    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;
    

    border=“1” 刚刚添加到 跨度 标签

    与这些模块一致,您还可以查看 CSS 和 CSS::DOM

        3
  •  2
  •   Adam Flott    17 年前

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