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
благодаря ви, благодаря ви... това помага много!!!! Аз също ще стоя далеч от „find“ и съответно ще използвам „findvalue“ или „findnodes“. - person CraigP; 06.11.2013