in reply to How can I replace a line (tag) in an XML file?

Using an XML parser, such as XML::Twig is a good approach:
use warnings; use strict; use XML::Twig; my $str = <<EOF; <students> <student> <name>John</name> <id>001</id> <gpa>A</gpa> </student> <student> <name>John</name> <id>002</id> <gpa>C</gpa> </student> </students> EOF my $t = XML::Twig->new( twig_handlers => { student => \&student, }, pretty_print => 'indented', ); $t->parse($str); $t->print($str); print "\n"; sub student { my ($t, $elt) = @_; if ($elt->field('id') eq '002') { $elt->first_child('gpa')->set_text('B'); } } __END__ <students> <student> <name>John</name> <id>001</id> <gpa>A</gpa> </student> <student> <name>John</name> <id>002</id> <gpa>B</gpa> </student> </students>
Note: I used XML::Tidy to indent your original XML code.

Update: made sub more succinct.

Replies are listed 'Best First'.
Re^2: How can I replace a line (tag) in an XML file?
by mirod (Canon) on Sep 29, 2011 at 07:48 UTC

    You can even put the test on the content of id in the handler condition, and not in the sub:

    twig_handlers => { 'student[string(id)="002"]' => sub { $_->first_child('gpa')->set_text('B'); } }

    Note that if the id is in a variable, then quote delimiter collisions between Perl and XPath makes it a little more annoying. Luckily Perl allows us to use whatever character we want with qq{}:

    twig_handlers => { qq{student[string(id)="$id"]} => sub { $_->first_child('gpa')->set_text('B'); } }
Re^2: How can I replace a line (tag) in an XML file?
by perlPractioner (Novice) on Sep 30, 2011 at 01:53 UTC

    Thanks for the timely response, I really appreciate it. I tested your code and it worked. However, I'd like to read the XML from a .xml file and replace the GPA tag (which you've already done). When I tried the following, I was able to read from the .xml file and replace the GPA tag, however the changes did not write back to the .xml file. I was only able to print the desired output but not able to write it back to the .xml file. This is what I have so far.

    use warnings; use strict; use XML::Twig; open File, 'test.xml'; sysread(FILE, my $str, -s FILE); my $t = XML::Twig->new( twig_handlers => { student => \&student, }, pretty_print => 'indented', ); $t->parse($str); $t->print($str); print "\n"; close FILE; sub student { my ($t, $elt) = @_; if ($elt->field('id') eq '002') { $elt->first_child('gpa')->set_text('B'); } }

    The print $str returns the desired output (changes the second instance of John's GPA from 'C' to 'B') but I'm not sure how to write this output back to the test.xml file. Any suggestions on this?

      You update the initial file the same way you would update a text file, or any other type of file: in this case once you've read the file close it, then open in for writing ans print the output to this filehandle.

      The way you use open, the fact that you use sysread are kind of unusual, so either you have a very personal style or you have little Perl experience and you are cargo-culting your way through the problem. You may want to read a little bit about Perl if you need to use it properly. Invest in "Learning Perl", or read the docs (at least the part on open and print, type perldoc -f open to get them