Я думаю, что здесь есть две проблемы - во-первых, xpath
выражения находят узлы. Вы можете искать на основе наличия и содержимого атрибута, но findnodes
предоставит вам элемент, а не контент.
Во-вторых - вы не можете вложить пространства имен в XML. x:ns2:Address
недействителен. Вам действительно нужно зарегистрировать ваше пространство имен x
? Вам может и не понадобиться. (например, на основе небольшого фрагмента XML).
Могу ли я предложить альтернативный вариант? Поскольку вы работаете с perl
, вам действительно не нужно делать все с помощью выражения xpath.
я бы, возможно, думал findnodes
следуют grep
:
NB: Использование 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>[email protected]</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
.Основываясь на том, что вы предоставили в этом фрагменте кода, вы ушли слишком сложно, и может просто сделать:
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";
}
Или с немного оглавлению:
#!/usr/bin/env perl
use strict;
use warnings;
use XML::LibXML;
my $email = '[email protected]';
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 = '[email protected]';
my ($id1) = map { $_ -> getAttribute('id1') //() } $xpc->findnodes("/Incomings/Incoming/x:Address[text()='$email']/..");
print $id1,"\n";
(также работает, если я макете некоторые XML с несколькими узлами «Входящие», чтобы выбрать первое с правильным адресом электронной почты. Примечание //
имеет значение perl 5.10 и является условным значением «определено». Возможно, вы могли бы заменить его ||
на более старые версии, что является «истинным/ложным» - единственными местами, где существуют различия, являются пустые строки и нули)
Благодарим вас за подробные ответы и варианты. – est