Я пытаюсь выбрать узел с помощью запроса XPath, и я не понимаю, почему XML :: LibXML не находит узел, когда он имеет атрибут xmlns. Вот скрипт для демонстрации вопрос:Почему XML :: LibXML не находит узлов для этого запроса xpath при использовании пространства имен
#!/usr/bin/perl
use XML::LibXML; # 1.70 on libxml2 from libxml2-dev 2.6.16-7sarge1 (don't ask)
use XML::XPath; # 1.13
use strict;
use warnings;
use v5.8.4; # don't ask
my ($xpath, $libxml, $use_namespace) = @ARGV;
my $xml = sprintf(<<'END_XML', ($use_namespace ? 'xmlns="http://www.w3.org/2000/xmlns/"' : q{}));
<?xml version="1.0" encoding="iso-8859-1"?>
<RootElement>
<MyContainer %s>
<MyField>
<Name>ID</Name>
<Value>12345</Value>
</MyField>
<MyField>
<Name>Name</Name>
<Value>Ben</Value>
</MyField>
</MyContainer>
</RootElement>
END_XML
my $xml_parser
= $libxml ? XML::LibXML->load_xml(string => $xml, keep_blanks => 1)
: XML::XPath->new(xml => $xml);
my $nodecount = 0;
foreach my $node ($xml_parser->findnodes($xpath)) {
$nodecount ++;
print "--NODE $nodecount--\n"; #would use say on newer perl
print $node->toString($libxml && 1), "\n";
}
unless ($nodecount) {
print "NO NODES FOUND\n";
}
Этот сценарий позволяет выбирать между XML :: Libxml парсер и XML :: XPath парсера. Он также позволяет вам определить атрибут xmlns в элементе MyContainer или опустить его в зависимости от переданных аргументов.
Я использую выражение xpath, которое я использую: RootElement/MyContainer. При запуске запроса с использованием XML :: Libxml анализатора без имен он находит узел без проблем:
[email protected]:~$ ROC/ECG/libxml_xpath.pl 'RootElement/MyContainer' libxml
--NODE 1--
<MyContainer>
<MyField>
<Name>ID</Name>
<Value>12345</Value>
</MyField>
<MyField>
<Name>Name</Name>
<Value>Ben</Value>
</MyField>
</MyContainer>
Однако, когда я запускаю его с пространством имен в месте, которое он не находит узлов:
[email protected]:~$ ROC/ECG/libxml_xpath.pl 'RootElement/MyContainer' libxml use_namespace
NO NODES FOUND
Contrast это с выходом при использовании в XMLL :: XPath-парсер:
[email protected]:~$ ROC/ECG/libxml_xpath.pl 'RootElement/MyContainer' 0 # no namespace
--NODE 1--
<MyContainer>
<MyField>
<Name>ID</Name>
<Value>12345</Value>
</MyField>
<MyField>
<Name>Name</Name>
<Value>Ben</Value>
</MyField>
</MyContainer>
[email protected]:~$ ROC/ECG/libxml_xpath.pl 'RootElement/MyContainer' 0 1 # with namespace
--NODE 1--
<MyContainer xmlns="http://www.w3.org/2000/xmlns/">
<MyField>
<Name>ID</Name>
<Value>12345</Value>
</MyField>
<MyField>
<Name>Name</Name>
<Value>Ben</Value>
</MyField>
</MyContainer>
Какой из этих реализаций парсера делает это «правильно»? Почему XML :: LibXML относится к нему по-разному, когда я использую пространство имен? Что я могу сделать, чтобы получить узел, когда пространство имен находится на месте?
Хороший вопрос, +1. См. Мой ответ для объяснения и двух возможных решений. –
@ikegami, поэтому должен быть полезен как для продвинутых, так и для начинающих пользователей. Им не следует отчаиваться, чтобы задавать вопросы. –