Я, наконец, пошел по пути регулярных выражений, рассматривая только простые атрибуты для тега pre
(без '>' внутри атрибутов):
foreach(array('pre', 'code') as $sTag)
$s = preg_replace_callback("#\<($sTag)([^\>]*?)\>(.+?)\<\/$sTag\>#si",
function($matches)
{
$matches[3] = str_replace(array('&', '<', '>'), array('&', '<', '>'), $matches[3]);
return "<{$matches[1]} {$matches[2]}>".htmlentities($matches[3], ENT_COMPAT, "UTF-8")."</{$matches[1]}>";
},
$s);
Он также имеет дело с символами, уже преобразованными в html-сущности(мы не хотим иметь его дважды).
Не идеальное решение, но, учитывая данные, которые мне нужны для его применения, это сработает.