gpt4 book ai didi

xml - 如何在 Perl 中修改复杂的 XML 文档以向文本节点添加额外的标记?

转载 作者:数据小太阳 更新时间:2023-10-29 02:32:12 25 4
gpt4 key购买 nike

我有一个这样的 XML 文档:

<article>
<author>Smith</author>
<date>2011-10-10</date>
<description>Article about <b>frobnitz</b>, crulps and furtikurty's. Mainly frobnitz</description>
</article>

我需要在 Perl 中解析它,然后在一些单词或短语周围添加新标签(例如链接到定义)。我只想标记目标词的第一个实例,并将搜索范围缩小到给定标签中的内容(例如,仅描述标签)。

我可以用 XML::Twig 解析并为描述标签设置一个“twig_handler”。但是,当我调用 $node->text 时,我得到的是删除了中间标签的文本。我真正想做的是向下遍历(非常小的)树,以便保留现有标签而不破坏它。因此,最终的 XML 输出应如下所示:

<article>
<author>Smith</author>
<date>2011-10-10</date>
<description>Article about <b><a href="dictionary.html#frobnitz">frobnitz</a></b>, <a href="dictionary.html#crulps">crulps</a> and <a href="dictionary.html#furtikurty">furtikurty</a>'s. Mainly frobnitz</description>
</article>

我还有XML::LibXML在目标环境中可用,但我不确定如何从那里开始...

到目前为止,这是我的最小测试用例。感谢任何帮助!

#!/usr/bin/perl
use strict;
use warnings;

use XML::Twig;

my %dictionary = (
frobnitz => 'dictionary.html#frobnitz',
crulps => 'dictionary.html#crulps',
furtykurty => 'dictionary.html#furtykurty',
);

sub markup_plain_text {
my ( $text ) = @_;

foreach my $k ( keys %dictionary ) {
$text =~ s/(^|\W)($k)(\W|$)}/$1<a href="$dictionary{$k}">$2<\/a>$3/si;
}

return $text;
}

sub convert {
my( $t, $node ) = @_;
warn "convert: TEXT=[" . $node->text . "]\n";
$node->set_text( markup_plain_text($node->text) );
return 1;
}

sub markup {
my ( $text ) = @_;

my $t = XML::Twig->new(
twig_handlers => { description => \&convert },
pretty_print => 'indented',
);
$t->parse( $text );

return $t->flush;
}


my $orig = <<END_XML;
<article>
<author>Smith</author>
<date>2011-10-10</date>
<description>Article about <b>frobnitz</b>, crulps and furtikurty's. Mainly frobnitz's</description>
</article>
END_XML
;

markup($orig);

最佳答案

这是一个有点棘手的问题,但 XML::Twig 是为这种处理而设计的(我经常使用它)。所以有一个名为 mark 的特定方法,它采用正则表达式并标记匹配项。

在这种情况下,正则表达式可能会非常大。我使用 Regexp::Assempble 来构建它,因此它得到了优化。然后另一个问题是 mark 不允许你使用匹配的文本来设置属性(我可能会在模块的下一个版本中处理这个,那会很有用),所以我必须先标记,然后返回并在第二遍中设置 href 属性(在任何情况下都需要第二遍来“取消链接”已经链接的单词)。

最后一句话:我差点放弃编写解决方案,因为您的示例数据有一些拼写错误。没有什么比正确编写代码更糟糕的了,只是看到测试仍然失败,因为您在代码中使用了“字典”,在数据中使用了“定义”,或者在应该全部使用的地方使用了“furtykurtle”、“furtikurty”和“furtijurty”是同一个词。因此,请在发布之前确保您的数据正确无误。值得庆幸的是,我正在编写代码作为测试。

#!/usr/bin/perl 

use strict;
use warnings;

use XML::Twig;
use Regexp::Assemble;

use Test::More tests => 1;
use autodie qw(open);

my %dictionary = (
frobnitz => 'definitions.html#frobnitz',
crulps => 'definitions.html#crulps',
furtikurty => 'definitions.html#furtikurty',
);

my $match_defs= Regexp::Assemble->new()
->add( keys %dictionary)
->anchor_word
->as_string;
# I am not familiar enough with Regexp::Assemble to know a cleaner
# way to get get the capturing braces in the regexp
$match_defs= qr/($match_defs)/;

my $in = data_para();
my $expected = data_para();
my $out;
open( my $out_fh, '>', \$out);


XML::Twig->new( twig_roots => { 'description' => sub { tag_defs( @_, $out_fh, $match_defs, \%dictionary); } },
twig_print_outside_roots => $out_fh,
)
->parse( $in);

is( $out, $expected, 'base test');
exit;

sub tag_defs
{ my( $t, $description, $out_fh, $match_defs, $dictionary)= @_;

my @a= $description->mark( $match_defs, 'a' );

# word => 1 when already used in this description
# this might need to have a different scope if you need to tag
# only the first time the word appears in a section or whatever
my $tagged_in_description;

foreach my $a (@a)
{ my $word= $a->text;
warn "checking a: ", $a->sprint, "\n";

if( $tagged_in_description->{$word})
{ $a->erase; } # we did not need to tag it after all
else
{ $a->set_att( href => $dictionary->{$word}); }
$tagged_in_description->{$word}++;
}

$t->flush( $out_fh); }


sub def_href
{ my( $word)= @_;
return $dictionary{word};
}

sub data_para
{ local $/="\n\n";
my $para= <DATA>;
return $para;
}

__DATA__
<article>
<author>Smith</author>
<date>2011-10-10</date>
<description>Article about <b>frobnitz</b>, crulps and furtikurty's. Mainly frobnitz</description>
</article>

<article>
<author>Smith</author>
<date>2011-10-10</date>
<description>Article about <b><a href="definitions.html#frobnitz">frobnitz</a></b>, <a href="definitions.html#crulps">crulps</a> and <a href="definitions.html#furtikurty">furtikurty</a>'s. Mainly frobnitz</description>
</article>

关于xml - 如何在 Perl 中修改复杂的 XML 文档以向文本节点添加额外的标记?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5972732/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com