我试图使用XML:Twig向XML中的节点添加子元素。我的XML是
<Install>
<version >
<number>6.0</number>
<build>1037124</build>
<path>path</path>
<kind>kind</kind>
</version>
<version >
<number>7.0</number>
<build>1037124</build>
<path>path</path>
<kind>kind</kind>
</version>
</Install>我想要的输出是:-
<Install>
<version >
<number>6.0</number>
<build>1037124</build>
<path>path/path>
<kind>kind</kind>
<patch>patch</patch>
<patchv>patchv</patchv>
</version>
<version >
<number>7.0</number>
<build>1037124</build>
<path>path</path>
<kind>kind</kind>
</version>
</Install>我想在父版本中添加两个新的子节点,其编号为6.0。
我试过这个代码
my $version = "6.0";
my $file_loc = "data.xml";
my $twig = XML::Twig->new( pretty_print => 'indented_a' )->parsefile( $file_loc );
for my $number ( $twig->findnodes('/Install/version/number') ) {
$number->parent->last_child->insert(
patch => { version =>'patch' },
patchversion => { version =>'patchv' },
) if $number->trimmed_text eq $version;
}但是我得到的输出不是我想要的。产出如下:
<Install>
<version>
<number>6.0</number>
<build>1037124</build>
<path>path</path>
<kind>
<patch version="patch">
<patchversion version="patchv">kind</patchversion>
</patch>
</kind>
</version>
<version >
<number>7.0</number>
<build>1037124</build>
<path>path</path>
<kind>kind</kind>
</version>
</Install>我也尝试过用其他方法使用粘贴,具体如下:
my $version = "6.0";
my $file_loc = "data.xml";
my $myXML = <<"XML";
<patch>
<build></build>
<version></version>
</patch>
XML
my $t = XML::Twig->new(
twig_handlers => {
Install => sub { add_version( $myXML, @_ ); }, }
)->parsefile( $file_loc ) or die $!;
$t->set_pretty_print('indented_c');
open my $xml_fh, '>', "$file_loc" or die $!;
$t->print($xml_fh);
sub add_version {
my ( $xml, $t, $install ) = @_;
my $new_elt = XML::Twig::Elt->parse($xml);
for my $number ( $t->findnodes('/Install/version/number') ) {
if($number->trimmed_text eq $version )
{
$new_elt->paste( $number->parent->last_child->paste => $install );
}
}
}在这里,我得到了以下错误
cannot paste an element that belongs to a tree at我是否可以只用insert来实现这个目标,还是必须使用粘贴??在这两种情况下怎样做??
发布于 2015-08-21 09:40:20
您的第一次尝试是正确的,但是您需要使用insert_new_element。insert将替换元素的内容,并将使用您选择的语法创建属性。
您可以将其放在一个非常简单的twig_handler中。获取所有<version>元素,检查它们的<number>文本节点,然后为修补程序和patchv值添加一个带有文本节点的新元素。
last_child => ''部件将新元素放在父元素的末尾。是paste。
use strict;
use warnings;
use XML::Twig;
my $twig = XML::Twig->new(
pretty_print => 'indented_a',
twig_handlers => {
'version' => sub {
if ( $_->first_child('number')->text() eq '6.0' ) {
$_->insert_new_elt( last_child => 'patch' )->set_text('patch');
$_->insert_new_elt( last_child => 'patchv' )->set_text('patchv');
}
}
}
)->parse( \*DATA );
$twig->print;输出:
<Install>
<version>
<number>6.0</number>
<build>1037124</build>
<path>path</path>
<kind>kind</kind>
<patch>patch</patch>
<patchv>patchv</patchv>
</version>
<version>
<number>7.0</number>
<build>1037124</build>
<path>path</path>
<kind>kind</kind>
</version>
</Install>您的第二次尝试不起作用至少有两个原因:
# this elem get's pasted (1)
# | on this positon (2)
# | | in that elem (3)
$new_elt->paste( $number->parent->last_child->paste => $install );在(2)中,它应该有一个位置,即字符串。就像first_child,last_child等等。paste。
因此,它将计算$number->parent->last_child->paste的返回值,并将其用作位置字符串。但是没有这样的返回值,所以这是行不通的。
,但它没有走那么远,。错误消息无法粘贴属于树的元素,该元素来自您在(2)中拥有的paste,因为您正在$number->parent->last_child上调用paste(),并且该元素已经在树中。这是不允许的如果删除该部分,代码将编译。
if ( $number->trimmed_text eq $version ) {
$new_elt->paste( $install );
}输出是(剪短的):
<Install>
<patch>
<build></build>
<version></version>
</patch>
<version>
<number>6.0</number>
<build>1037124</build>
<path>path</path>
<kind>kind</kind>
</version>这仍然不是我们想要的,因为<patch>最终在<Install>中结束,而不是在<version>中。但是我们已经有了循环中的$number。这就是<number>节点中的<version>节点,因此我们可以获取它的父节点并在我们的(3)中使用它。
$new_elt->paste( $number->parent );现在我们明白了:
<Install>
<version>
<patch>
<build></build>
<version></version>
</patch>
<number>6.0</number>
<build>1037124</build>
<path>path</path>
<kind>kind</kind>
</version>那好多了。在合适的地方。如果您添加的位置last_child,它结束在末尾。
$new_elt->paste( last_child => $number->parent );现在它在这里:
<Install>
<version>
<number>6.0</number>
<build>1037124</build>
<path>path</path>
<kind>kind</kind>
<patch>
<build></build>
<version></version>
</patch>
</version>现在它只是我们粘贴的错误的东西,因为我们想要两个元素<patch>和<patchv>,都带有文本。那是因为你在$myXML里有那些。
您不能在那里有两个顶级元素。这是无效的XML语法。
my $myXML = <<"XML";
<patch>patch</patch>
<patchv>patchv</patchv>
XML这将失败的垃圾后文档元素在第2行,第0列,字节21在.因此,您必须有两个变量并两次调用paste,或者包装它们并获取新根元素的子节点。
当然,这是非常复杂的。上面的第一种方法是非常干净的。
https://stackoverflow.com/questions/32132993
复制相似问题