#!/usr/bin/perl -w use XML::Twig; XML::Twig->new( twig_handlers => { _all_ => \&replace_text, }, keep_spaces => 1, # to keep the original indentation ) ->parse( \*DATA) ->flush; sub replace_text { my( $t, $elt)= @_; # need to go through all pcdata elements in case thedoc # includes mixed content (last foo element in the example) foreach my $pcdata ($t->descendants( '#PCDATA')) { $pcdata->set_pcdata( my_filter( $pcdata->pcdata) ); } $t->flush; } sub my_filter { $_[0]=~ s{foo}{bar}g; return $_[0]; } __DATA__ foo foo baz foo foo baz foo bar foo foo baz