Perl XML :: LibXML $node-> findnodes($xpath)查找不应该的
发布时间:2020-12-15 21:59:35 所属栏目:大数据 来源:网络整理
导读:这里有一些我有问题的代码,我处理一些 XML,在一个OO类中的方法中,我从文档中重复的几个节点中的每一个中提取一个元素.在每个节点的子树中只应该有一个这样的元素,但是我的代码就像整个文档一样运行所有的元素. 因为我只希望得到元素我只使用数组的第零个元素
这里有一些我有问题的代码,我处理一些
XML,在一个OO类中的方法中,我从文档中重复的几个节点中的每一个中提取一个元素.在每个节点的子树中只应该有一个这样的元素,但是我的代码就像整个文档一样运行所有的元素.
因为我只希望得到元素我只使用数组的第零个元素,这导致我的函数输出错误的值(它对文档中的所有项都是一样的) 这是一些简化的代码,说明了这个问题 $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 Responsen"; $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 ),'-' x 70,"n"; my @identifiers = $node->findnodes( '//Identifier' ); print "do() found ",scalar @identifiers," Identifiersn"; print "$id,",$identifiers[0]->textContent,"nn"; } 这是输出 $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
(强调我自己).所以你的电话 $node->findnodes( '//Identifier' ) 忽略上下文节点$node并在文档中的任何位置搜索所有标识符元素 要获取上下文节点的所有标识符后代,您必须添加一个点,像这样 $node->findnodes('.//Identifier'); 但是由于$node始终是Response元素,而Identifier是Response的直接子节点,您可以直接写入 $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: %sn",$item->findvalue('Id'); my @messages = $item->findnodes('Message'); for my $message (@messages) { my ($response) = $message->findnodes('Response'); printf "Response Identifier: %sn",$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 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |