gpt4 book ai didi

xml - Perl XML::LibXML $node->findnodes($xpath) 找到它不应该找到的节点

转载 作者:数据小太阳 更新时间:2023-10-29 01:41:31 26 4
gpt4 key购买 nike

这是一些我遇到问题的代码,我处理了一些 XML,并在 OO 类的方法中从文档中重复的几个节点中的每一个节点中提取了一个元素。每个节点的子树中应该只有一个这样的元素,但我的代码获取所有元素,就好像它在整个文档上操作一样。

因为我只希望得到 oine 元素,所以我只使用数组的第 0 个元素,这导致我的函数输出错误的值(文档中的所有项都相同)

下面是一些说明问题的简化代码

$ cat t4.pl
#!/usr/bin/perl
use strict;
use warnings;
use XML::LibXML;

my $xml = <<EndXML;
<Envelope>
<Body>
<Reply>
<List>
<Item>
<Id>8b9a</Id>
<Message>
<Response>
<Identifier>55D</Identifier>
</Response>
</Message>
</Item>
<Item>
<Id>5350</Id>
<Message>
<Response>
<Identifier>56D</Identifier>
</Response>
</Message>
</Item>
</List>
</Reply>
</Body>
</Envelope>
EndXML

my $foo = Foo->new();

my $parser = XML::LibXML->new();
my $doc = $parser->parse_string( $xml );
my @list = $doc->getElementsByTagName( 'Item' );

for my $item ( @list ) {

my $id = get( $item, 'Id' );
my @messages = $item->getElementsByLocalName( 'Message' );

for my $message ( @messages ) {

my @children = $message->getChildNodes();

for my $child ( @children ) {

my $name = $child->nodeName;

if ( $name eq 'Response' ) {
print "child is a Response\n";
$foo->do( $child, $id );
}
elsif ( $name eq 'text' ) {

# ignore whitespace between elements
}
else {
print "child name is '$name'\n";
}
} # child
} # Message
} # Item

# ..............................................

sub get {
my ( $node, $name ) = @_;

my $value = "(Element $name not found)";
my @targets = $node->getElementsByTagName( $name );

if ( @targets ) {
my $target = $targets[0];
$value = $target->textContent;
}

return $value;
}

# ..............................................

package Foo;

sub new {
my $self = {};
bless $self;
return $self;
}

sub do {
my $self = shift;
my ( $node, $id ) = @_;

print '-' x 70, "\n", ' ' x 12, $node->toString( 1 ), "\n", '-' x 70, "\n";

my @identifiers = $node->findnodes( '//Identifier' );
print "do() found ", scalar @identifiers, " Identifiers\n";

print "$id, ", $identifiers[0]->textContent, "\n\n";
}

这是输出

$ perl t4.pl
child is a Response
----------------------------------------------------------------------
<Response>
<Identifier>55D</Identifier>
</Response>
----------------------------------------------------------------------
do() found 2 Identifiers
8b9a, 55D

child is a Response
----------------------------------------------------------------------
<Response>
<Identifier>56D</Identifier>
</Response>
----------------------------------------------------------------------
do() found 2 Identifiers
5350, 55D

我很期待

do() found 1 Identifiers

我期待最后一行是

5350, 56D

由于平台问题,我使用的是旧版本的 XML::LibXML。

问:是后续版本有问题还是我操作有误?

最佳答案

来自documentation of XPath 1.0

//para selects all the para descendants of the document root

(强调我自己)。所以你的电话

$node->findnodes( '//Identifier' )

正在忽略上下文节点 $node 并在文档中的任何位置搜索所有 Identifier 元素

要获取上下文节点的所有 Identifier 后代,您必须添加一个点,如下所示

$node->findnodes('.//Identifier');

但由于 $node 始终是 Response 元素,而 IdentifierResponse 的直接子元素,您可以随便写

$node->findnodes('Identifier');



您写这篇文章似乎有点忙不过来了。我知道您已将代码缩减为示例,但您真的需要单独的包吗?明智地应用 XPath 可以做很多事情。

最明显的变化是您无需遍历所有 个子项 - 您可以简单地挑选出您感兴趣的子项。

这段重构代码可能值得一读

use strict;
use warnings;

use XML::LibXML;

my $parser = XML::LibXML->new;
my $doc = $parser->parse_fh(*DATA);

for my $item ( $doc->findnodes('//Item') ) {

print "\n";

my ($id) = $item->findvalue('Id');
printf "Item Id: %s\n", $item->findvalue('Id');

my @messages = $item->findnodes('Message');

for my $message (@messages) {
my ($response) = $message->findnodes('Response');
printf "Response Identifier: %s\n", $response->findvalue('Identifier');
}
}

__DATA__
<Envelope>
<Body>
<Reply>
<List>
<Item>
<Id>8b9a</Id>
<Message>
<Response>
<Identifier>55D</Identifier>
</Response>
</Message>
</Item>
<Item>
<Id>5350</Id>
<Message>
<Response>
<Identifier>56D</Identifier>
</Response>
</Message>
</Item>
</List>
</Reply>
</Body>
</Envelope>

输出

Item Id: 8b9a
Response Identifier: 55D

Item Id: 5350
Response Identifier: 56D

关于xml - Perl XML::LibXML $node->findnodes($xpath) 找到它不应该找到的节点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11955052/

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