#!/usr/bin/perl use strict; use warnings; use XML::Twig; my $t = XML::Twig->new( twig_handlers => { hl1 => \&fix_hl1, hl2 => \&fix_hl2, _all_ => \&fixup, }, keep_encoding => 1, keep_spaces => 1, ) ->parse( \*DATA); sub fixup { my( $t, $elt)= @_; foreach my $pcdata ($elt->children( '#PCDATA')) { $pcdata->set_text( conv_chars( $pcdata->text)); } $elt->flush unless( $_->in( 'hl1') || $_->in( 'hl2')); } sub conv_chars { my $t= shift; $t=~ s{—}{--}g; return $t; } sub fix_hl1 { $_->set_tag( 'new_hl1')->prefix( 'fixed hl1:'); } sub fix_hl2 { $_->set_tag( 'new_hl2')->prefix( 'fixed hl2:'); } __DATA__ ]> hl1 with a &foo; and an other &foo; and — and —

text, no foo

text, no foo but —

text, with &foo;

hl2 with a &foo; and an other &foo; and — and — hl2 no foo hl2 with a bold &foo;, and an other &foo;