Perl XML::LibXML: findnode, findvalue и find — в чем разница?

Я использую XML::LibXML, и мне просто нужно получить количество узлов, указанных XPath выражение.

Использование любой из первых двух строк кода ниже дает то, что я ищу. Я могу использовать функцию count XPath либо с findvalue, либо с find, но не с findnodes (да, я знаю, потому что она возвращает список).

my $node_cnt = $dom->findvalue("count($xpath_str)");  # WORKS!
my $node_cnt = $dom->find("count($xpath_str)");       # WORKS!
my @node_cnt = $dom->findnodes("count($xpath_str)");  # count doesn't work!

Что приводит меня к общему мучительному вопросу: в чем разница между тремя типами find? В документации сказано:

$string = $node->findvalue($xpath)
$result = $node->find($xpath)
@nodes  = $node->findnodes($xpath_expression)
  1. Есть ли разница между аргументом $xpath_expression и просто $xpath в документации?

  2. Какая разница для двух, возвращающих скаляр?

Я пытаюсь понять важность использования одного типа поиска над другим - спасибо!


person CraigP    schedule 06.11.2013    source источник


Ответы (1)


Разница заключается в типе значения, которое возвращают методы.

  • findnodes используется для возврата списка узлов. Если метод вызывается в контексте списка, он возвращает список объектов соответствующего типа, например XML::LibXML::Element, XML::LibXML::Text и т. д. Если он вызывается в скалярном контексте, он возвращает один объект XML::LibXML::NodeList, содержащий ту же информацию.

    Его нельзя использовать для возврата произвольного выражения, например, $dom->findnodes('42') ничего не вернет. Вы можете получить список узлов документа только из этого метода.

  • findvalue используется для возврата одного текстового или числового значения, т. е. не узла XML. Если вы передаете выражение XPath, результатом которого является список узлов, он преобразует этот список в текст, объединяя все текстовые узлы в любом из узлов в списке.

  • find может вернуть что угодно. Он вернет список узлов как объект XML::LibXML::NodeList, числовое значение как объект XML::LibXML::Number, строковый литерал как объект XML::LibXML::Literal и т. д. В отличие от findnodes, он всегда возвращает одно скалярное значение, даже если вызывается в контекст списка.

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

Например, вы, вероятно, захотите написать my $nrecs = $dom->findvalue('count(/root/record)'), чтобы получить количество записей в корневом элементе. $nrecs будет простым числовым значением perl.

С другой стороны, чтобы получить список этих записей, вы должны использовать my @records = $dom->findnodes('/root/record'). Теперь @records содержит несколько XML::LibXML::Element объектов.

В ваших примерах

my $node_cnt = $dom->findvalue("count($xpath_str)");  # WORKS!

это устанавливает $node_cnt в простое число Perl, в то время как это

my $node_cnt = $dom->find("count($xpath_str)");  # WORKS!

устанавливает $node_cnt в объект XML::LibXML::Number, который преобразуется в строку (когда вы его печатаете) так же, как и предыдущий оператор. Докажите это сами, напечатав print ref $node_cnt в обоих случаях.

потом

my @node_cnt = $dom->findnodes("count($xpath_str)");  # count doesn't work!

терпит неудачу, потому что XPath count оценивается как число, а не узел XML (он не является частью дерева XML). Невозможно преобразовать числа в узлы, поэтому результатом является пустой список. Если бы все было наоборот, и мы вызвали бы findvalue для выражения, которое оценивается как список узлов, то есть смутно разумный способ преобразования в текстовое значение, и findvalue делает все возможное и возвращает конкатенацию всех текстовых узлов. содержащиеся в узлах списка.

person Borodin    schedule 06.11.2013
comment
спасибо, спасибо... очень помогает!!!! Я тоже буду держаться подальше от «найти» и использовать либо «найти значение», либо «найти узлы» соответственно. - person CraigP; 06.11.2013