Выражение xpath в findnodes(), возвращающее пустой список узлов

XML:

<zoo xmlns="http://www.zoo.com" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:schemaLocation="http://www.zoo.com employee.xsd">

<area id="1" posizione="nord" nome="scimmie">
    <animale>
        <nome>Gigi</nome>
        <sesso>Male</sesso>
        <eta>3</eta>
    </animale>

    <animale>
        <nome>Gigia</nome>
        <sesso>Female</sesso>
        <eta>2</eta>
    </animale>
</area>

<area id="2" posizione="nord" nome="giraffe">
    <animale>
        <nome>Giro</nome>
        <sesso>Male</sesso>
        <eta>6</eta>
    </animale>

    <animale>
        <nome>Gira</nome>
        <sesso>Female</sesso>
        <eta>5</eta>
    </animale>
</area>
</zoo>

код:

my $parser = XML::LibXML->new;
my $doc = $parser->parse_file("../xml/animals.xml");
my $root = $doc->getDocumentElement();

my $new_animal = $doc->createElement("animale");

my $name_element = $doc->createElement("nome");
$name_element->appendTextNode($name);

my $gender_element = $doc->createElement("sesso");
$gender_element->appendTextNode($gender);

my $age_element = $doc->createElement("eta");
$age_element->appendTextNode($age);

$new_animal->appendChild($name_element);
$new_animal->appendChild($gender_element);
$new_animal->appendChild($age_element);

my $area_element = $root -> findnodes("//area[\@id=$area]")->get_node(1);

$area_element->appendChild($new_animal);

$area - это идентификатор области (обычно 1, когда я тестирую)

моя цель - создать новое животное и добавить его в нужную область

но у меня проблема в том, что инструкция

    my $area_element = $root -> findnodes("//area[\@id=$area]")->get_node(1);

не будет работать, потому что $area_element имеет значение undef, потому что findnodes всегда возвращает пустой список узлов (проверено, что печатается size()).

Я думаю, что проблема в выражении xpath внутри findnodes, но я не могу понять, что не так, я использую то же выражение с другой библиотекой (XML::XPath), и оно работает.

Что случилось?


person qwertoyo    schedule 30.05.2012    source источник


Ответы (2)


URI для пространства имен по умолчанию в вашем XML — http://www.zoo.com, поэтому вы должны указать это в своих выражениях XPath для узлов, которые будут выбраны.

Способ сделать это — объявить объект XML::LibXML::XPathContext, который присваивает имя этому пространству имен. Затем это имя можно использовать в выражениях XPath для доступа к узлам.

Если вы пишете

my $xpc = XML::LibXML::XPathContext->new;
$xpc->registerNs('zoo', 'http://www.zoo.com');

теперь у вас есть контекст, в котором пространство имен XML по умолчанию называется zoo. Теперь вы можете написать

my $area_element = $xpc->findnodes("//zoo:area[\@id=$area]", $doc)->get_node(1);

и вы найдете правильный элемент <area>.

person Borodin    schedule 30.05.2012
comment
Я пытался использовать ваш код, но получаю следующее: ---------- Программная ошибка: XPathContext: потерян текущий узел в /Users/toyo/Sites/zoo/cgi-bin/_nuovo_animale.cgi, строка 76 -- ------- строка 76: my $area_element = $xpc -> findnodes(//zoo:area[\@id=$area])->get_node(1); - person qwertoyo; 30.05.2012
comment
@qwertoyo, это новая проблема, и здесь действительно нет места для ее обсуждения. Задайте новый вопрос и предоставьте минимальный исполняемый код, необходимый для демонстрации проблемы. - person ikegami; 30.05.2012
comment
@qwertoyo, попробуй проще: my ($area_element) = $xpc->findnodes("//zoo:area[\@id=$area]", $doc); - person ikegami; 30.05.2012
comment
увидел ваше редактирование в ответе (добавлено, $ doc), теперь это работает, я тестирую его - person qwertoyo; 30.05.2012

Неверное объявление пространства имен, должно быть указано <zoo xmlns:zoo="http://www.zoo.com" или подобное.

person daxim    schedule 30.05.2012
comment
xmlns="http://www.zoo.com" без идентификатора пространства имен просто связывает пространство имен default, то есть пространство имен для всех элементов, не имеющих префикса. Если нет определения пространства имен по умолчанию, это как если бы использовалось объявление xmlns="". - person Borodin; 30.05.2012
comment
<foo xmlns="..."> и <bar:foo xmlns:bar="..."> верны и эквивалентны (при условии, что дети имитируют отсутствие/наличие префикса). Пространство имен, определенное в <foo xmlns:bar="...">, никогда не используется, поэтому ваш совет неверен. - person ikegami; 30.05.2012
comment
Неправильный ответ. В объявлении пространства имен нет ничего плохого. Понижение. - person Michael Kay; 30.05.2012