您好我正在使用HTML::TreeBuilder
/ HTML::Element
来清理由Microsoft Word等程序生成的一些不良HTML。
鉴于示例中的错误HTML片段,我需要在mosh="start"
和mosh="stop"
之间提取文本。请注意,这是代码中其他位置设置的任意属性。
另请注意,这只是一个示例:唯一的保证是mosh开始和停止的div
。这些也可以是表格或<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
然后,我需要将$MoshText
上的m/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可以模式匹配”的表格不应该在表格中,而应该是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>
希望更有意义
答案 0 :(得分: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
答案 1 :(得分: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版本的一部分。
答案 2 :(得分: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)}
}
列表($吨);