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

如何使用HTML::Parser重写HTML的文本部分而不更改<script>和<head>部分?

  •  2
  • user181548  · 技术社区  · 15 年前

    以下代码是的简短版本 an example HTML::Parser

    #!/usr/bin/perl -w
    use strict;
    my $code = shift || usage();
    sub edit_print { local $_ = shift; tr/a-z/n-za-m/; print } 
    use HTML::Parser 3.05;
    my $p = HTML::Parser->new(unbroken_text => 1,
         default_h => [ sub { print @_; }, "text" ],
         text_h    => [ \&edit_print,      "text" ],
    );
    my $file = shift;
    $p->parse_file($file)
    

    这段代码工作得很好,但是它有一个缺点,那就是它也重写了里面的文本 <script> 而且 <head> 部分。我已经修改了上面的示例来做我想做的事情,但不幸的是还有一个bug,它重写了 <title> 我不想重写的标签。

    是否有人知道如何编写类似于上述内容的东西,但不破坏JavaScript, <书名; 还是其他部分?如果需要,我很乐意使用HTML::Parser之外的其他模块。

    2 回复  |  直到 15 年前
        1
  •  2
  •   Greg Bacon    15 年前

    向解析器中添加开始和结束处理程序,并让它们记录当前元素的祖先。当祖先包含 <head> <script> ,禁用重写。

    把你前面的事留着

    #! /usr/bin/perl
    
    use warnings;
    use strict;
    
    use HTML::Parser 3.05;
    
    sub edit_print { local $_ = shift; tr/a-z/n-za-m/; print }
    

    并使用以下Sub创建新的分析器:

    sub create_parser {
      my @tags;
      my $start = sub {
        my($text,$tagname) = @_;
        push @tags => $tagname;
        print $text;
      };
      my $end = sub {
        my($text,$tagname) = @_;
        die "$0: expected </$tags[-1]>, got </$tagname>"
          unless $tagname eq $tags[-1];
        pop @tags;
        print $text;
      };
      my $edit_print = sub {
        if (grep /^(head|script)$/, @tags) { print @_ }
        else                               { edit_print @_ }
      };
    
      HTML::Parser->new(
        unbroken_text => 1,
        default_h     => [ sub { print @_ }, "text" ],
        text_h        => [ $edit_print,      "text" ],
        start_h       => [ $start,           "text,tagname" ],
        end_h         => [ $end,             "text,tagname" ],
      );
    }
    

    在Sub中创建它的原因是处理程序回调是 closures that share private state 在里面 @tags . 这个实现允许您实例化多个解析器,而不必担心它们会互相踩踏对方的数据。

    my $p = create_parser;
    $p->parse_file(\*DATA);
    
    __DATA__
    foo
    <html>
    <head>
    <title>My Title</title>
    <style type="text/css">
      /* don't change me */
    </style>
    </head>
    <body>
    <script type="text/javascript">
      // or me
    </script>
    <h1>My Document</h1>
    <p>Yo.</p>
    </body>
    </html>
    

    输出:

    sbb
    <html>
    <head>
    <title>My Title</title>
    <style type="text/css">
      /* don't change me */
    </style>
    </head>
    <body>
    <script type="text/javascript">
      // or me
    </script>
    <h1>Ml Dbphzrag</h1>
    <p>Yb.</p>
    </body>
    </html>
    
        2
  •  0
  •   reinierpost    15 年前

    看看你现有的代码,我不知道你被困在哪里:

    1. 添加一堆布尔值

      my @do_edit = (0)
      
    2. 在edit_print中,如果$do_edit[0]为0,则不编辑

    3. 为某些元素名称添加start和end处理程序以移位/取消移位值