#!/usr/bin/perl -w use strict; use XML::SAX::Writer; my $DEBUG=0; # set to 1 to debug my $w = XML::SAX::Writer->new; # see the man for XML::SAX::Writer to output to file $w->start_document(); # in your example you don't have a root element, so you need one my $root= 'root'; $w->start_element( { Name => $root, }); while( ) { # the split will return (char, tag, char, tag, char...) # the list always starts and ends with a char my @tokens= split( m{\[\[ # [[ ([^\]]*) # tag \]\] # ]] }x ); print join( ' - ', map { "'$_'" } @tokens), "\n" if( $DEBUG); while( @tokens) { my $chars= shift @tokens; $w->characters( { Data => $chars} ); my $tag= shift @tokens or last; if( $tag=~ m{^/(.*)$}) { $w->end_element( { Name => $1 }); } else { $w->start_element( { Name => $tag }); } } } $w->end_element( { Name => $root, }); $w->end_document; __DATA__ [[a]] some text here[[/a]] [[b]] some more text [[/b]] [[a]] some text again[[c]]more here..[[/c]] [[/a]] [[a]] some text again[[c]]more here..[[/c]][[/a]]