Beefy Boxes and Bandwidth Generously Provided by pair Networks httptech
P is for Practical
 
PerlMonks  

NOT_FOUND_ERR in insertAfter()

by kingsaint (Novice)
on Sep 25, 2013 at 04:30 UTC ( #1055603=perlquestion: print w/ replies, xml ) Need Help??
kingsaint has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to add a new <student> node with attibute id="1003" after the <student> element with id='1001'. Here is the xml structure:

<?xml version="1.0" encoding="utf-8" ?> <University> <students> <student id="1000"/> <student id="1001"/> <student id="1002"/> </students> </University>

I'm using XML::LibXML module and wrote the following snippet:

#!/usr/bin/perl use XML::LibXML; $parser = XML::LibXML->new(); $doc = $parser->parse_file('student.xml'); $query = '//student'; for my $ele ($doc->findnodes($query)){ my $attr_text=$ele->getAttribute('id'); if($attr_text eq '1001'){ $new_ele=$doc->createElement('student'); $new_ele->setAttribute('id','1003'); $doc->insertAfter($new_ele,$ele); last; } } open(TESTFILE,">result.xml"); print TESTFILE $doc->toString; close(TESTFILE);

But I'm getting the following run-time error:

NOT_FOUND_ERR

I'm still a novice in perl.Can you please explain the error message and tell me how to resolve it?

Comment on NOT_FOUND_ERR in insertAfter()
Select or Download Code
Re: NOT_FOUND_ERR in insertAfter()
by NetWallah (Monsignor) on Sep 25, 2013 at 05:09 UTC
    Change the "insert" line to :
    $ele->parentNode->insertAfter($new_ele,$ele);
    and it works.

    "insertAfter" is a method for a NODE, not a doc (DOM object).

    If I understand it right, the "NOT_FOUND" error was raised because $ele is not a direct child of $doc.

                 My goal ... to kill off the slow brain cells that are holding me back from synergizing my knowledge of vertically integrated mobile platforms in local cloud-based content management system datafication.

      Update

      I tested the change above, and found that it does not correct the problem, you need to use the form I have below with undef as the second arg to insertAfter. It is possible that this is a result of different versions, so test for yourself.

      End update

      I was just going to post the same thing as above after a quick test script. Here is the output produced by making the change:

      <?xml version="1.0" encoding="utf-8"?> <University> <students> <student id="1000"/> <student id="1001"><student id="1003"/></student> <student id="1002"/> </students> </University>

      On a different note, you should always have use strict; and use warnings; as well as check for critical failures in your code, like this:

      #!/usr/bin/perl use strict; use warnings; use XML::LibXML; my $parser = XML::LibXML->new(); # this call should probably be wrapped in an eval (or Try::Tiny) or at + least # tested for a valid object being returned. my $doc = $parser->parse_file('student.xml'); my $query = '//student'; for my $ele ($doc->findnodes($query)){ my $attr_text=$ele->getAttribute('id'); if($attr_text eq '1001'){ my $new_ele=$doc->createElement('student'); $new_ele->setAttribute('id','1003'); $ele->insertAfter($new_ele,undef); last; } } # if you can't open the file you want to know why open(TESTFILE,">result.xml") or die "Can not open output: $!"; print TESTFILE $doc->toString; close(TESTFILE); exit; __END__
      On time, cheap, compliant with final specs. Pick two.
        Sorry - but your code is incorrect.

        The main problem is that the output XML has the 1003 student EMBEDDED INSIDE the 1001, which I do not think is the desired result.

        my code produces:

        <?xml version="1.0" encoding="utf-8"?> <University> <students> <student id="1000"/> <student id="1001"/><student id="1003"/> <student id="1002"/> </students> </University>
        which , I believe is what the OP wanted.

                     My goal ... to kill off the slow brain cells that are holding me back from synergizing my knowledge of vertically integrated mobile platforms in local cloud-based content management system datafication.

Re: NOT_FOUND_ERR in insertAfter()
by choroba (Abbot) on Sep 25, 2013 at 08:53 UTC
    NetWallah already told you what was the reason of the error. I would like to add a piece of advice:

    Do not go over the elements in a loop (unless you want to add a student to almost each of them). Use XPath to search for the desired target:

    #!/usr/bin/perl use warnings; use strict; use XML::LibXML; my $doc = 'XML::LibXML'->load_xml( string => << '__XML__'); <?xml version="1.0" encoding="utf-8" ?> <University> <students> <student id="1000"/> <student id="1001"/> <student id="1002"/> </students> </University> __XML__ my $query = '//student[@id="1001"]'; for my $ele ($doc->findnodes($query)){ my $new_ele = $doc->createElement('student'); $new_ele->setAttribute('id', '1003'); $ele->parentNode->insertAfter($new_ele, $ele) or die; last; # Not needed if identifiers are unique. The whole + looping is useless, then. } print $doc->toString;
    لսႽ ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1055603]
Approved by Athanasius
Front-paged by sparkyichi
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others musing on the Monastery: (8)
As of 2014-04-19 02:57 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    April first is:







    Results (475 votes), past polls