#!/usr/bin/perl -w use strict; use XML::XPath; undef $/; my $XML=; my $xpath = XML::XPath->new('xml' => $XML); foreach my $node ($xpath->findnodes('/foo/bar/text')->get_nodelist) { my $data = your_munge_function($node->string_value); my $id = $node->getAttribute('id'); $xpath->setNodeText('/foo/bar/text[@id="' . $id . '"]', $data); } my $newXML = $xpath->findnodes_as_string('/'); # safe because XML::XPath entiti-zes > in attributes $newXML=~ s{(]*>)(.*?)()} {$1 . cdata_ize($2) . $3}eg; print $newXML; sub your_munge_function { return "munged $_[0]"; } sub cdata_ize { my $text= shift; $text=~ s{&}{&}g; $text=~ s{<}{<}g; return ""; } __DATA__ Foo bar baz]]>