【问题标题】:Trouble Replacing Text in HTML fragment using Mojo::DOM使用 Mojo::DOM 替换 HTML 片段中的文本时遇到问题
【发布时间】:2013-06-23 20:35:05
【问题描述】:

我需要扫描 html 片段以查找文本中的某些字符串(不在元素属性中)并用 <span></span> 包装这些匹配的字符串。这是一个带有输出的示例尝试:

use v5.10;
use Mojo::DOM;

my $body = qq|
<div>
<p>Boring Text:</p>
<p>
Highlight Cool whenever we see it.
but not <a href="/Cool.html">here</a>.
<code>
    sub Cool {
        print "Foo\n";
    }
</code>
And here is more Cool.
</p>
</div>
|;
my $dom = Mojo::DOM->new($body);

foreach my $e ($dom->find('*')->each) {
    my $text = $e->text;
    say "e text is:  $text ";
    if ($text =~ /Cool/) {
        (my $newtext = $text ) =~ s/Cool/<span class="fun">Cool<\/span>/g;
        $e->replace_content($newtext);
    }
}

say $dom->root;

输出:

e text is:   
e text is:  Boring Text: 
e text is:  Highlight Cool whenever we see it. but not. And here is more Cool. 
e text is:  here 
e text is:  sub Cool { print "Foo "; } 

<div>
<p>Boring Text:</p>
<p>Highlight <span class="fun">Cool</span> whenever we see it. but not. And here is more <span class="fun">Cool</span>.</p>
</div>

关闭,但我真正想看到的是以下内容:

<div>
<p>Boring Text:</p>
<p>Highlight <span class="fun">Cool</span> whenever we see it. but not <a href="/Cool.html">here</a>. 
<code>
sub <span class="fun">Cool<span> { 
    print "Foo\n"; 
}
</code>  
And here is more <span class="fun">Cool</span>.</p>
</div>

任何帮助/指针将不胜感激。 谢谢, 托德

【问题讨论】:

  • 由于 Mojo::DOM 对 CSS 选择器的限制,很难做到这一点。您是否仅限于使用此模块,还是可以转到XML::Twig 或其他允许 XPath 访问数据的模块?
  • 没有限制,我将开始研究 XML::Twig。谢谢。

标签: perl mojolicious


【解决方案1】:

查看了XML::Twig 我不太确定它是不是正确的工具。令人惊讶的是,如此简单的任务竟然如此尴尬。

这是一个使用HTML::TreeBuilder 的工作程序。不幸的是,它不会产生格式化输出,所以我自己添加了一些空格。

use strict;
use warnings;

use HTML::TreeBuilder;

my $html = HTML::TreeBuilder->new_from_content(<<__HTML__);
<div>
<p>Boring Text:</p>
<p>
Highlight Cool whenever we see it.
but not <a href="/Cool.html">here</a>.
<code>
    sub Cool {
        print "Foo\n";
    }
</code>
And here is more Cool.
</p>
</div>
__HTML__

$html->objectify_text;

for my $text_node ($html->look_down(_tag => '~text')) {

  my $text = $text_node->attr('text');

  if (my @replacement = process_text($text)) {
    my $old_node = $text_node->replace_with(@replacement);
    $old_node->delete;
  }
}

$html->deobjectify_text;

print $html->guts->as_XML;

sub process_text {

  my @nodes = split /\bCool\b/, shift;
  return unless @nodes > 1;

  my $span = HTML::Element->new('span', class => 'fun');
  $span->push_content('Cool');

  for (my $i = 1; $i < @nodes; $i += 2) {
    splice @nodes, $i, 0, $span->clone;
  }

  $span->delete;

  @nodes;
}

输出

<div>
<p>Boring Text:</p>
<p>
Highlight <span class="fun">Cool</span> whenever we see it.
but not <a href="/Cool.html">here</a>.
<code> sub <span class="fun">Cool</span> { print &quot;Foo &quot;; } </code>
And here is more <span class="fun">Cool</span>.
</p>
</div>

【讨论】:

  • 乍一看似乎更难。例如,此脚本也不能正确处理 print 函数的换行符。
  • @Birei: "打印函数的换行符"?
  • &lt;code&gt; 标签内有一个print "Foo\n"; 在输出中被破坏。
  • @Birei:它使用实体对双引号进行编码。就这些。等价的文字是一样的。
  • 看了这两个,我想我更喜欢这个。我实际上将用几个正则表达式替换“Cool”,这在 HTML::TreeBuilder 中更直接。
【解决方案2】:

这是使用XML::Twig 的开始。一个问题是&lt;code&gt; 标签内的文字换行符。我猜解析器看不出它和普通解析器之间的区别。也许将其编码为&amp;#10 或使用CDATA 部分会有所帮助。不然不知道怎么处理:

script.pl的内容:

#!/usr/bin/env perl

use warnings;
use strict;
use XML::Twig;

my $body = qq| 
<div>
<p>Boring Text:</p>
<p>
Highlight Cool whenever we see it.
but not <a href="/Cool.html">here</a>.
<code>
    sub Cool {
        print "Foo\n";
    }
</code>
And here is more Cool.
</p>
</div>
|;

XML::Twig::Elt::set_replaced_ents(q{});
my $elt = XML::Twig::Elt->new( 'span' => { class => 'fun' }, 'Cool' );

my $twig = XML::Twig->new( pretty_print => 'nice' )->parse( $body );
$twig->subs_text( 'Cool', $elt->sprint );
$twig->print;

像这样运行它:

perl script.pl

它产生:

<div>
<p>Boring Text:</p>
<p>
Highlight <span class="fun">Cool</span>
 whenever we see it.
but not <a href="/Cool.html">here</a>.
<code>
    sub <span class="fun">Cool</span>
 {
        print "Foo
";
    }
</code>
And here is more <span class="fun">Cool</span>
.
</p>
</div>

【讨论】:

    猜你喜欢
    • 2014-07-26
    • 1970-01-01
    • 2019-03-08
    • 2011-10-06
    • 2017-10-23
    • 2018-09-01
    • 1970-01-01
    • 2015-08-18
    • 1970-01-01
    相关资源
    最近更新 更多