XML::Twig - set_text 没有破坏结构
XML::Twig - set_text without clobbering structure
With XML::Twig
使用 set_text
方法 - 有一个警告:
set_text ($string)
Set the text for the element: if the element is a PCDATA, just set its text, otherwise cut all the children of the element and create a single PCDATA child for it, which holds the text.
所以如果我想做一些简单的事情,比如 - 比如说 - 改变我 XML::Document:
中所有文本的大小写
#!/usr/bin/perl
use strict;
use warnings;
use XML::Twig;
my $twig = XML::Twig->new(
'pretty_print' => 'indented_a',
'twig_handlers' => {
'_all_' => sub {
my $newtext = $_->text_only;
$newtext =~ tr/[a-z]/[A-Z]/;
$_->set_text($newtext);
}
}
);
$twig->parse( \*DATA );
$twig->print;
__DATA__
<root>
<some_content>fish
<a_subnode>morefish</a_subnode>
</some_content>
<some_more_content>cabbage</some_more_content>
</root>
这 - 因为 set_text
替换了 children - 被破坏成:
<root></root>
但如果我只关注一个(底层)节点(例如 a_subnode
),那么它工作正常。
有没有一种优雅的方法可以 replace/transform 元素中的文本而不破坏它下面的数据结构?我的意思是,我可以对 children 或类似内容的存在进行测试,但是......似乎应该有更好的方法来做到这一点。 (也许是不同的图书馆?)
(为了清楚起见 - 这是我音译文档中所有文本的示例,我的实际用例相当复杂,但仍然是 'about' 就地文本转换)。
我正在考虑可能采用节点 cut/and/paste 方法(剪切所有 children、替换文本、粘贴所有 children),但这似乎是一种低效的方法。
不要在 _all_
上使用处理程序,而是尝试仅在文本元素上使用它:#TEXT
,并将 text_only
更改为 text
。它应该工作。
更新:或者在创建树枝时使用char_handler
选项:char_handler => sub { uc shift },
而不是处理程序。
我目前的做法是:
- 迭代所有节点。
cut
所有 children.
- 修改正文。
paste
全部children。
这似乎效率低下,但它确实有效:
#!/usr/bin/perl
use strict;
use warnings;
use XML::Twig;
use Data::Dumper;
sub replace_text {
my ( $twig, $element ) = @_;
my $newtext = $element->text_only;
my @children;
foreach my $child ( $element->children ) {
if ( not $child->tag eq "#PCDATA" ) {
push( @children, $child->cut );
}
}
$newtext =~ tr/[a-z]/[A-Z]/;
$element->set_text($newtext);
$_->paste( 'last_child', $element ) for @children;
}
my $twig =
XML::Twig->new( 'twig_handlers' => { '_all_' => \&replace_text, } );
$twig->parse( \*DATA );
print "Result:\n";
$twig->print;
__DATA__
<root>
<some_content>fish
<a_subnode>morefish</a_subnode>
</some_content>
<some_more_content>cabbage</some_more_content>
</root>
这会将我的输出变成:
<root><some_content>FISH
<a_subnode>MOREFISH</a_subnode></some_content><some_more_content>CABBAGE</some_more_content></root>
因此,虽然它确实变换了节点,但出于某种原因,它也破坏了输出格式。
正在重新解析:
XML::Twig -> new ( 'pretty_print' => 'indented_a' ) -> parse ( $twig -> sprint ) -> print;
似乎可以解决问题。 (虽然双重解析只是为了重新格式化似乎更不优雅)
<root>
<some_content>FISH
<a_subnode>MOREFISH</a_subnode></some_content>
<some_more_content>CABBAGE</some_more_content>
</root>
With XML::Twig
使用 set_text
方法 - 有一个警告:
set_text ($string) Set the text for the element: if the element is a PCDATA, just set its text, otherwise cut all the children of the element and create a single PCDATA child for it, which holds the text.
所以如果我想做一些简单的事情,比如 - 比如说 - 改变我 XML::Document:
中所有文本的大小写#!/usr/bin/perl
use strict;
use warnings;
use XML::Twig;
my $twig = XML::Twig->new(
'pretty_print' => 'indented_a',
'twig_handlers' => {
'_all_' => sub {
my $newtext = $_->text_only;
$newtext =~ tr/[a-z]/[A-Z]/;
$_->set_text($newtext);
}
}
);
$twig->parse( \*DATA );
$twig->print;
__DATA__
<root>
<some_content>fish
<a_subnode>morefish</a_subnode>
</some_content>
<some_more_content>cabbage</some_more_content>
</root>
这 - 因为 set_text
替换了 children - 被破坏成:
<root></root>
但如果我只关注一个(底层)节点(例如 a_subnode
),那么它工作正常。
有没有一种优雅的方法可以 replace/transform 元素中的文本而不破坏它下面的数据结构?我的意思是,我可以对 children 或类似内容的存在进行测试,但是......似乎应该有更好的方法来做到这一点。 (也许是不同的图书馆?)
(为了清楚起见 - 这是我音译文档中所有文本的示例,我的实际用例相当复杂,但仍然是 'about' 就地文本转换)。
我正在考虑可能采用节点 cut/and/paste 方法(剪切所有 children、替换文本、粘贴所有 children),但这似乎是一种低效的方法。
不要在 _all_
上使用处理程序,而是尝试仅在文本元素上使用它:#TEXT
,并将 text_only
更改为 text
。它应该工作。
更新:或者在创建树枝时使用char_handler
选项:char_handler => sub { uc shift },
而不是处理程序。
我目前的做法是:
- 迭代所有节点。
cut
所有 children.- 修改正文。
paste
全部children。
这似乎效率低下,但它确实有效:
#!/usr/bin/perl
use strict;
use warnings;
use XML::Twig;
use Data::Dumper;
sub replace_text {
my ( $twig, $element ) = @_;
my $newtext = $element->text_only;
my @children;
foreach my $child ( $element->children ) {
if ( not $child->tag eq "#PCDATA" ) {
push( @children, $child->cut );
}
}
$newtext =~ tr/[a-z]/[A-Z]/;
$element->set_text($newtext);
$_->paste( 'last_child', $element ) for @children;
}
my $twig =
XML::Twig->new( 'twig_handlers' => { '_all_' => \&replace_text, } );
$twig->parse( \*DATA );
print "Result:\n";
$twig->print;
__DATA__
<root>
<some_content>fish
<a_subnode>morefish</a_subnode>
</some_content>
<some_more_content>cabbage</some_more_content>
</root>
这会将我的输出变成:
<root><some_content>FISH
<a_subnode>MOREFISH</a_subnode></some_content><some_more_content>CABBAGE</some_more_content></root>
因此,虽然它确实变换了节点,但出于某种原因,它也破坏了输出格式。
正在重新解析:
XML::Twig -> new ( 'pretty_print' => 'indented_a' ) -> parse ( $twig -> sprint ) -> print;
似乎可以解决问题。 (虽然双重解析只是为了重新格式化似乎更不优雅)
<root>
<some_content>FISH
<a_subnode>MOREFISH</a_subnode></some_content>
<some_more_content>CABBAGE</some_more_content>
</root>