0

您好,我正在使用HTML::TreeBuilder/HTML::Element来清理一些由 Microsoft Word 等程序生成的不良 HTML。

鉴于示例中的错误 HTML 片段,我需要提取 和 之间的mosh="start"文本mosh="stop"。请注意,这是代码中其他地方设置的任意属性。

另请注意,这只是一个示例:唯一的保证是divmosh 开始和停止的位置。这些也可以是表格或<p><b>.

下面的代码实现了这一点,但每一行都被多次提取,因为每个孩子也有孩子。

$MoshText应该

Good Text can be pattern matched Wanted Text More Wanted TextYet More Wanted Text

但是上桌后

$MoshText

Good Text can be pattern matched Good Text can be pattern matched Good Text can be pattern matched Good Text can be pattern matched

然后我需要拆分成两个字符串并删除原始文本所在的任何对象$MoshTextm/matched/

如何修改下面的代码来实现这一点?

#!/usr/bin/perl
use HTML::TreeBuilder;
use HTML::Element;

my $body =qq(
<body>
  <div mosh="start">Div where mosh set to start</div
  <div>
<table>
  <tr>
    <td></td><td</td>
    <th>Good Text can be pattern matched</th>
    <td></td><td</td>
  </tr> 
</table
</div>
<p>

   <p>
      <b>Wanted Text</b>
   <br>
      <p><b>More Wanted Text</b></p>
   <div>
      <p><b>Yet More Wanted Text</b></p>
   </div>
  </p>
<div mosh="stop">Div where mosh set to stop bellow here is not needed</div>
);

my ($MoshText, $Flag);

my @kids = $body->content_list();
while (@kids) {
    my $child = shift @kids;
    if (ref $child) {
        my $Mosh = child->attr("mosh");
        if ($Mosh eq "start") {
            $Flag = 1;
        }
        if ($Mosh eq "stop") {
            $Flag = 0;
            last;
        }
        if ($Flag == 1) {
            my $T = $child->as_trimmed_text;
            $MoshText = $MoshText . " " . $T;
        }
        unshift @kids, $child->content_list;
    }
}
print $MoshText . "\n";

编辑

澄清我的意思是 删除原始文本所在的任何对象

包含“Good Text can be pattern matching”的表格不应该在表格中,而应该在 div 中

我很有趣是一个对象,所以我会用一个新的 div 对象替换这个对象,比如

my $new = HTML::Element->new('tag','div');
$new->attr('class', 'MyClass');
$new->push_content('Good Text can be pattern matched');

但是我现在如何找到表删除并插入 $new

清洁输出

    <div>
      Div where mosh set to start
    </div> 
    <div class ='MyClass'>
      Good Text can be pattern matched
    </div>
    <div class ='AnotherClass' >
      Wanted Text More Wanted Text Yet More Wanted Text
    </div>
    <div mosh="stop">Div where mosh set to stop bellow here is not needed</div>

希望这更有意义

4

3 回答 3

2

我想你明白为什么你的代码不工作了。您正在打印 HTML 中所有元素的文本值,并且因为一个元素的文本值包括其所有后代的文本节点,所以多段文本出现了不止一次。

您需要递归处理 HTML 树,检查mosh每个元素的属性值并相应地保留一个标志(就像您已经做的那样),并且只有在设置了标志时才在遇到它们时打印文本节点。

这个程序演示。我已经展示了在 上拆分字符串matched,但我不清楚删除原始文本所在的任何对象是什么意思。

use strict;
use warnings;

use HTML::TreeBuilder;
use HTML::Element;

my $tree = HTML::TreeBuilder->new->parse_file(*DATA);

my $wanted;
my @mosh_text;
my @nodes = ($tree);

while (@nodes) {

  my $node = shift @nodes;

  if (not ref $node) {
    push @mosh_text, $node if $wanted;
  }
  else {

    my $mosh = lc($node->attr('mosh') // '');
    if ( $mosh eq 'start' or $mosh eq 'stop' ) {
      $wanted = $mosh eq 'start';
    }

    unshift @nodes, $node->content_list;
  }
}

my $mosh_text = "@mosh_text";
print "$_\n" for split/\s*matched\s*/, $mosh_text;

__DATA__
<body>
  <div mosh="start">Div where mosh set to start</div
  <div>
<table>
  <tr>
    <td></td><td</td>
    <th>Good Text can be pattern matched</th>
    <td></td><td</td>
  </tr> 
</table
</div>
<p>

   <p>
      <b>Wanted Text</b>
   <br>
      <p><b>More Wanted Text</b></p>
   <div>
      <p><b>Yet More Wanted Text</b></p>
   </div>
  </p>
<div mosh="stop">Div where mosh set to stop bellow here is not needed</div>

输出

Div where mosh set to start Good Text can be pattern
Wanted Text More Wanted Text Yet More Wanted Text
于 2012-11-27T18:36:17.003 回答
0

使用 HTML::TreeBuilder 解析 HTML 页面,然后使用 HTML::Element 的 look_down()/look_up()/right()/left() 方法来查找您的 mosh 属性边界。

给定您的边界,您可以使用 look_up/look_down 方法(在边界元素上,而不是树根上)来查找包含要更改的文本的元素。更改元素中的文本,然后您可以使用树根或任何其他元素中的 as_HTML 方法生成 HTML。

所以在伪代码中:

$tree = HTML::TreeBuilder->parse($something)
$mstart = $tree->look_down(
                            _tag => "div",
                            class  => "mosh_start"
                           )
###
# 1. now use HTML::Element traversal methods to find the element that contains the text to match

# 2. use the content manipulation methods to change the content

# 3. rewrite the file
$tree->as_HTML().

另请参阅HTML::Element,它与HTML::TreeBuilder一起是CPAN 上HTML::Tree版本的一部分。

于 2012-11-27T22:17:57.603 回答
0
use HTML::TreeBuilder;
my $t = HTML::TreeBuilder->new->parse_file("China.data");

sub list
 {my ($t, $d) = @_;
  $d //= 0;
  if (ref($t))
   {say "  "x$d, $t->tag;
    for($t->content_list)
    {list($_, $d+1);
    }
  }
 else {say "  "x$d, dump($t)}
}

列表($t);

于 2013-08-30T11:33:59.243 回答