This seems to do what I want:
$pattern = '/ \< ([[:alnum:]]+) \> ( (?>[^<>]+) | (?R) )* \< \/ \1 \> /Xx';
while(preg_match($pattern, $string, $captured))
{
$string = preg_replace('/'.addcslashes($captured[0], '/').'/', '', $string, 1);
$results[][$captured[1]] = preg_replace(array("/...