XML: найти конкретный узел в XML с помощью LibXML

У меня есть файл XML, в котором есть только один узел с именем import. Я хочу найти атрибут импорта href. Я попытался использовать findnodes(), но это возвращает список, который мне придется искать дальше, поэтому я надеялся, что есть способ найти конкретный узел, который имеет только одно вхождение. Я пробовал getChildrenByTagName, но это дает ошибку

Can't locate object method "getChildrenByTagName" via package "XML::LibXML::Document"

Я также пробовал grep, который дает аналогичную ошибку

Can't locate object method "grep" via package "XML::LibXML::Document"

Мой XML-файл:

<?xml version="1.0" encoding="UTF-8"?>
<resource name="data" type="application/dictionary+xml">
<schema>
    <import href="tobefound.xml"/>
</schema>
</resource>

Мой код до сих пор

#!/usr/bin/perl
use warnings;
use strict;
use XML::LibXML;

my $name = $ARGV[1];
my $dom = XML::LibXML->load_xml(location => $name);
my @node= $dom->findnodes('//import');
print "List: @node\n";

Пожалуйста, дайте мне знать, есть ли способ найти только один конкретный узел, не просматривая весь дом и не сохраняя его в виде списка. Спасибо.


person user1677804    schedule 04.12.2018    source источник
comment
Если вы знаете, что это только один узел, то просто возьмите первый элемент @node?   -  person tinita    schedule 04.12.2018
comment
@tinita, не будет ли это излишне использовать список? Могу ли я каким-то образом найти первое вхождение import?   -  person user1677804    schedule 04.12.2018


Ответы (2)


XML не гарантирует уникальности, поэтому любой поиск вернет список результатов. Этот список может иметь длину 0 или 1, как и grep.

Но простой ответ — просто взять первый результат:

my ($node) = $dom -> findnodes('//import');

в противном случае - укажите в своем xpath:

my ( $node ) = $dom -> findnodes ( '(//import)[1]' ); 

Боюсь, я не знаю, действительно ли этот последний выручит, когда будет выбрано «достаточное количество» узлов.

person Sobrique    schedule 04.12.2018
comment
Итак, это было в основном приведение типа node к скаляру? Извините, новичок в Perl. Но спасибо, сработало как надо. - person user1677804; 04.12.2018
comment
Он назначает результат списка из «findnodes» списку с левой стороны. Но список в LHS состоит из одного элемента, поэтому любые другие назначения будут отброшены. Вы могли бы написать: my ( $first_match, @rest_of_matches) = ... и тогда, возможно, станет понятнее, что происходит — мы просто отбрасываем @rest_of_matches. - person Sobrique; 04.12.2018

getChildrenByTagName — это метод узлов Element, а не узлов Document.

my $doc = XML::LibXML->load_xml(location => $name);
my $root_ele = $doc->documentElement();
my ($import_ele) = $root_ele->getChildrenByTagName('import');

Вы также можете использовать XPath, хотя эквивалентным XPath будет import (ищет потомков), а не //import (ищет потомков).

my $doc = XML::LibXML->load_xml(location => $name);
my ($import_ele) = $doc->findnodes('import');

Это возвращает все узлы import и сохраняет первый. Но может сказать поиску прекратить поиск после нахождения первого следующим образом:

my $doc = XML::LibXML->load_xml(location => $name);
my ($import_ele) = $doc->findnodes('import[1]');  # Short for 'import[position()=1]'
person ikegami    schedule 05.12.2018