我认为这里有两个问题 - 首先,xpath 表达式找到节点。您可以根据属性的存在和内容进行搜索,但findnodes 会为您提供元素,而不是内容。
其次 - 您不能在 XML 中嵌套命名空间。 x:ns2:Address 无效。你真的需要在那里注册你的x 命名空间吗?你可能根本不需要。 (例如,基于您的小型 XML sn-p)。
我可以提供其他选择吗?因为您使用的是perl,所以您实际上并不一定需要通过 xpath 表达式执行所有操作。
我可能会想findnodes,然后是grep:
注意:使用 XML::Twig 进行说明 - 可以肯定,在 XML::LibXML 中有一些非常相似的工作。
#!/usr/bin/env perl
use strict;
use warnings;
use XML::Twig;
my $twig = XML::Twig->new( 'pretty_print' => 'indented_a' )->parse( \*DATA );
my @elt_list = grep { $_->trimmed_text =~ m{fubar\@test.com} }
( $twig->findnodes('//ns2:Address') );
foreach my $elt (@elt_list) {
print $elt -> parent -> att('id1');
}
__DATA__
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Incomings xmlns:ns2="http://testme.org/foo/schema">
<Incoming id1="6bbaec22" id2="928c2081">
<ns2:Address>fubar@test.com</ns2:Address>
</Incoming>
</Incomings>
我还要注意 - 您的 xpath 可以让您找到一个元素 - 而不是一个属性 - 所以您可以选择具有 id1 属性的元素,如下所示:
my @elt_list = ( $twig->findnodes("//ns2:Address[string()='$email']/../.[\@id1]") );
foreach my $elt (@elt_list) {
print $elt -> att('id1');
}
取决于您希望对findnodes 搜索的具体程度。根据您在该 sn-p 中提供的内容,您已经过于复杂,可以简单地执行以下操作:
use XML::Twig;
my $twig = XML::Twig->parsefile('your_file.xml');
print $twig -> findnodes('//Incoming',0)->att('id1'),"\n";
或者:
#!/usr/bin/env perl
use strict;
use warnings;
use XML::LibXML;
my $xml = XML::LibXML->new->parse_file( 'sample2.xml' );
foreach my $node ( $xml -> findnodes( '//Incoming' ) ) {
print $node ->getAttribute('id1'), "\n";
}
或者用一点grepping:
#!/usr/bin/env perl
use strict;
use warnings;
use XML::LibXML;
my $email = 'fubar@test.com';
my $xml = XML::LibXML->new->parse_file( 'sample2.xml' );
foreach my $node ( grep { $_ -> textContent =~ m{$email} } $xml -> findnodes( '//Incoming' ) ) {
print $node ->getAttribute('id1'), "\n";
}
如果您特别想使用 x 命名空间 - 这是可行的:
#!/usr/bin/env perl
use strict;
use warnings;
use XML::LibXML;
my $xml = XML::LibXML->new->parse_file('sample2.xml');
my $xpc = XML::LibXML::XPathContext->new( $xml->documentElement );
$xpc->registerNs( 'x', 'http://testme.org/foo/schema' );
my $email = 'fubar@test.com';
my ( $id1 ) = map { $_ -> getAttribute('id1') // () } $xpc->findnodes("/Incomings/Incoming/x:Address[text()='$email']/..");
print $id1,"\n";
(如果我使用多个“传入”节点模拟一些 XML 以选择具有正确电子邮件地址的第一个节点,也可以使用。注意 // 是 perl 5.10 及更高版本,并且是“已定义”的条件。您可能会替换在旧版本上使用||,即“真/假”——唯一不同的地方是空字符串和零)