LibXML findnodes($query)
У меня возникли проблемы с этим кодом:
my $file= '../xml/news.xml';
my $parser= XML::LibXML->new();
my $doc = $parser->parse_file($file);
my $xpc = XML::LibXML::XPathContext->new($doc);
my $query = '/notizie/news[@id='.$newsId.']';
print $query;
my $node = $xpc->findnodes($query)->get_node(1);
print $node;
В частности, "print $ node" печатает пустую строку, даже если путь к XML-файлу указан правильно и запрос XPath должен вернуть узел.
Самое смешное, что если я использую:
my $query = '/*/*[@id='.$newsId.']';
я получил правильный результат.
Это файл news.xml:
<?xml version="1.0"?>
<notizie xmlns="http://www.9armonie.com/news"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.9armonie.com/news news.xsd">
<news id="3">
<data>2015-01-01</data>
<ora>12:00:00</ora>
<titolo>Title 3</titolo>
<descrizione> Description 3</descrizione>
</news>
<news id="2">
<data>2014-12-19</data>
<ora>12:00:00</ora>
<titolo>Title 2</titolo>
<descrizione> Description 2</descrizione>
</news>
<news id="1">
<data>2014-12-18</data>
<ora>12:00:00</ora>
<titolo>News 1</titolo>
<descrizione> Desc 1</descrizione>
</news>
<news id="0">
<data>2014-12-18</data>
<ora>12:00:00</ora>
<titolo> asdasd</titolo>
<descrizione> First! </descrizione>
</news>
</notizie>
1 ответ
Ваш входной XML-документ находится в пространстве имен по умолчанию:
<notizie xmlns="http://www.9armonie.com/news"/>
Этот элемент и все его потомки находятся в этом пространстве имен, и выражение как //notizie
никогда не будет успешным, потому что он ищет элемент без пространства имен.
С другой стороны, вот почему /*/*
возвращает элементы - потому что *
соответствует элементам в любом (или нет) пространстве имен. В этом нет ничего смешного.
Либо объявите это пространство имен в своем коде Perl (лучший вариант), либо игнорируйте пространства имен в выражении XPath.
Объявление пространства имен с помощью LibXML
Я считаю, что объявление пространств имен в LibXML выполняется с registerNs()
см. соответствующую страницу CPAN. Объявите URI пространства имен из входного XML вместе с префиксом (news:
(в этом примере), который затем можно использовать для определения имен элементов в выражении XPath.
my $xpc = XML::LibXML::XPathContext->new($doc);
$xpc->registerNs('news', 'http://www.9armonie.com/news');
my $query = '/news:notizie/news:news[@id='.$newsId.']';
my $node = $xpc->findnodes($query)->get_node(1);
Игнорирование пространств имен
Второй вариант означает изменение выражения XPath на
"/*[local-name() = 'notizie']/*[local-name() = 'news' and @id='.$newsId.']"
Вышеупомянутое выражение найдет notizie
элемент во всех следующих документах:
<!--No namespace-->
<notizie/>
<!--Namespace with prefix-->
<news:notizie xmlns:news="http://www.9armonie.com/news"/>
<!--Default namespace-->
<notizie xmlns="http://www.9armonie.com/news"/>