use warnings; use strict; use XML::LibXML; my $doc = XML::LibXML->load_xml(string => <<'XML'); hello, foobar world! foo fooofoo XML my $re = qr/foo/; # don't include any capturing parens in this! my @nodes = $doc->documentElement; while (my $node = pop @nodes) { for my $c ($node->childNodes) { if ($c->nodeType==XML_ELEMENT_NODE) { push @nodes, $c } elsif ($c->nodeType==XML_TEXT_NODE || $c->nodeType==XML_CDATA_SECTION_NODE) { my @parts = split /($re)/, $c->data; next unless @parts>1; my $d = $doc->createDocumentFragment; for my $i (0..$#parts) { if ($i%2) { # regex match my $e = $doc->createElement('x'); $e->appendText($parts[$i]); $d->appendChild($e); } else { # text around match $d->appendText($parts[$i]); } } $node->replaceChild($d, $c); } } } print $doc->toString; __END__ hello, foobar world! foo fooofoo