5

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>

code:

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 is the id of an area (usually 1 now that I'm testing)

my purpose is to create a new animal and to add it to the proper area

but I have the problem that the istruction

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

won't work, because $area_element is undef, because findnodes always returns an empty nodelist (checked printing the size()).

I think that the problem is the xpath expression inside findnodes, but I can't understand what's wrong, I use the same expression with another library (XML::XPath) and it's working.

What's wrong?

qwertoyo
  • 1,332
  • 2
  • 15
  • 31

2 Answers2

4

The URI for the deafult namespace in your XML is http://www.zoo.com, so you must specify this in your XPath expressions for the nodes to be picked up.

The way to do this is to declare a XML::LibXML::XPathContext object that assigns a name to this namespace. The name can then be used in XPath expressions to access the nodes.

If you write

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

you now have a context in which the XML's default namespace is named zoo. Now you can write

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

and you will find the correct <area> element.

Borodin
  • 126,100
  • 9
  • 70
  • 144
  • I tried with your code, but I get this: ---------- Software error: XPathContext: lost current node at /Users/toyo/Sites/zoo/cgi-bin/_nuovo_animale.cgi line 76 --------- line 76 is: my $area_element = $xpc -> findnodes("//zoo:area[\@id=$area]")->get_node(1); – qwertoyo May 30 '12 at 19:19
  • @qwertoyo, This is a new problem, and there's really no space to discuss it here. Please ask a new question, and provide the minimum runnable code required to demonstrate the problem. – ikegami May 30 '12 at 19:30
  • @qwertoyo, Try the simpler: `my ($area_element) = $xpc->findnodes("//zoo:area[\@id=$area]", $doc);` – ikegami May 30 '12 at 19:33
  • saw your edit on the answer (added the ", $doc"), now it seems to work, i'm testing it – qwertoyo May 30 '12 at 19:40
-2

The namespace declaration is wrong, it should say <zoo xmlns:zoo="http://www.zoo.com" or the like.

daxim
  • 39,270
  • 4
  • 65
  • 132
  • `xmlns="http://www.zoo.com"` without a namespace ID merely binds the *default* namespace, i.e. the namespace for all elements that don't carry a prefix. If there is no definition of a default namespace then it is as if a declaration `xmlns=""` had been used. – Borodin May 30 '12 at 18:45
  • `` and `` are correct and equivalent (assuming the children mimic the lack/presence of the prefix). The namespace defined in `` is never used, so your advice is incorrect. – ikegami May 30 '12 at 19:29
  • Wrong answer. There is nothing wrong with the namespace declaration. Downvoting. – Michael Kay May 30 '12 at 19:39