in reply to XML::DOM - NOT_FOUND_ERR

What do you mean by incorrect? What did you get and what did you expect? If I may hazard a guess ... you want the modified <record> tag to have the children in the same order as the other ones, right? If so you have to create the subtags in the right order. And hashes do not keep any order. The order in which you specify the keys doesn't matter. At all.

Also, why do you write

$new = $xdoc->createElement("$key");
but
$new->appendChild($text);
? Why do you quote the variable in one case and do not quote in the other?

And if instead of the output being incorrect you actually get an error according the subject, then most likely you should use just

$xitem->getElementsByTagName('institute')->getNodeValue;
instead of
$xitem->getElementsByTagName('institute')->item(0)->getFirstChild->get +NodeValue;

Replies are listed 'Best First'.
Re^2: XML::DOM - NOT_FOUND_ERR
by sureerat (Acolyte) on Oct 23, 2008 at 11:43 UTC
    According to my script, I would like to search each "record" node if found "institute = Thammasat" I would like to replace the "record" node with new node "$ritem". But after running the script. The result is as following: 1. The found "record" in the first employee is removed instead of replace. 2. The found "record" in the second employee is replaced correctly. Is it strange? or maybe I do something wrong. Please help. Here is the incorrect output after running script:
    <?xml version="1.0" encoding="UTF-8"?> <company name="ABC" branch="bangkok"> <employee code="emp0001"> <info> <general> <name>Somchai Chaisom</name> <photo>/employee/photo/emp001.gif</photo> <position>Helpdesk Officer</position> <department>IT</department> </general> </info> <education> <record> <institute>Mahidol</institute> <year>2548-2550</year> <degree>Master</degree> <faculty>IT</faculty> <major>IT</major> <gpa>2.6</gpa> </record> </education> </employee> <employee code="emp0002"> <info> <general> <name>Manee Meena</name> <photo>/employee/photo/emp002.gif</photo> <position>Programmer</position> <department>IT</department> </general> </info> <education> <record> <institute>Siam University</institute> <year>2538-2542</year> <degree>Bachelor</degree> <faculty>Engineer</faculty> <major>Software Engineering</major> <gpa>3.3</gpa> </record> <record><institute>test</institute><degree>test</degree><g +pa>test</gpa><faculty>test</faculty><major>test</major><year>test</ye +ar></record> </education> </employee> </company>
    For your question about quote and not quote the variable, I have adjust the code into the same direction as following:
    #!/usr/bin/perl use warnings; use XML::DOM; $link = "Thammasat"; %rlinks = ( "institute" => "test", "year" => "test", "degree" => "test", "faculty" => "test", "major" => "test", "gpa" => "test", ); my $rfile = "employee.xml"; my $xparser = XML::DOM::Parser->new(); my $xdoc = $xparser->parsefile($rfile); $ritem = $xdoc->createElement("record"); foreach $key (keys %rlinks) { $new = $xdoc->createElement($key); $text = $xdoc->createTextNode($rlinks{$key}); $new->appendChild($text); $ritem->appendChild($new); } foreach my $xitem ($xdoc->getElementsByTagName("record")) { $durl = $xitem->getElementsByTagName("institute")->item(0)->getFir +stChild->getNodeValue; if($durl eq $link) { $p = $xitem->getParentNode(); $p->replaceChild($ritem,$xitem); #this return incorrect resu +lt #$xdoc->getDocumentElement()->replaceChild($ritem,$xitem); #t +his return NOT_FOUND_ERR } } $xdoc->printToFile($rfile);
    For your comment about:
    $xitem->getElementsByTagName('institute')->item(0)->getFirstChild->get +NodeValue;
    It returns error after I change to: error = Can't locate object method "getNodeValue" via package "XML::DOM::NodeList"
    $xitem->getElementsByTagName('institute')->getNodeValue;

      The problem is that XML::DOM is a maze of objects. And each node object can only have one parent. So you first stick the <record> object in place of the first Thammasat and then MOVE the object in place of the second. You'd have to create a brand new $ritem each time you want to replace the original.

      To tell the truth, you'd most likely do better if you dumped the module and used a different. I'm surprised mirod did not already suggest his XML::Twig, anyway I'll suggest my XML::Rules:

      use strict; use XML::Rules; my $link = "Thammasat"; my $rlinks = { "institute" => ["test"], "year" => ["test"], "degree" => ["test"], "faculty" => ["test"], "major" => ["test"], "gpa" => ["test"], }; my $parser = XML::Rules->new( style => 'filter', ident => ' ', rules => { _default => 'raw extended', record => sub { return $_[0] => $_[1] unless $_[1]->{':institute'}{_conten +t} eq $link; return $_[0] => $rlinks; } }, ); $parser->filterfile('employee.xml', 'employee-filtered.xml');

      The additional advantage is that this scripts doesn't load the whole file into memory, it parses the file, copies everything outside the <record> tag and only ever remembers that single tag with contents.

        Thank you Jenda for your guideline. I can fix the problem now using XML::DOM. I'm being interested in XML::Twig and your XML::Rules, I will study both and decide again what is the best for my project. You help me a lot. Thanks again ^_^