<?php
/**
* Форматирование HTML кода
*/
class alignedxhtml {
public $SPACER;
public $OFFSET;
public $SKIPTAGS;
function parse($xhtml) {
if (is_null($this->SPACER)) {
$this->SPACER = " ";
}
if (is_null($this->OFFSET)) {
$this->OFFSET = 0;
}
if (is_null($this->SKIPTAGS)) {
$this->SKIPTAGS = array('a', 'span', 'img', 'sup', 'sub');
}
/*
Теги <textarea>, <pre> и <script> - особенные, и с ними
придется попотеть.
Нужно защитить содержимое этих тегов от вмешательства
при выравнивании: убрать на время, во-первых, переводы строки,
во-вторых, HTML-теги, которые могут встретиться внутри
строковых переменных в скриптах
(точнее, не сами теги, а открывающие и закрывающие скобки).
*/
$xhtml = str_replace(array("\x01", "\x02", "\x03"), '', $xhtml);
$xhtml = preg_replace_callback(
'/
(<(textarea|script|pre)(?:[^>"\']*|"[^"]*"|\'[^\']*\')*>)
(.*?)
(<\/\2>)
/six',
// модификатор 's' не забываем: точка тут должна совпадать
// и с символом новой строки; модификатор 'x' позволяет добавлять в шаблон
// необрабатываемые пробелы и переводы строки, чтобы он лучше читался
create_function(
'$matches', '$tagbody = $matches[3];
$tagbody = str_replace("\n", "\x01", $tagbody);
$tagbody = str_replace("<", "\x02", $tagbody);
$tagbody = str_replace(">", "\x03", $tagbody);
return $matches[1] . $tagbody . $matches[4];'
), $xhtml);
// регулярное выражение для HTML-тега
// (модификатор s не нужен, т.к. точки в выражении нет)
$tagpattern = '/<(\/?)(\w+)(?:[^>"\']*|"[^"]*"|\'[^\']*\')*>/';
// убираем переводы строки внутри тегов (заменяем на пробелы)
$xhtml = preg_replace_callback(
$tagpattern, create_function(
'$matches', 'return str_replace("\n", " ", $matches[0]);'
), $xhtml);
// теперь обрабатыавем XHTML-код по одной строке
// (PHP это не умеет, поэтому пришлось вручную)
$start = 0;
$final_xhtml = '';
do {
$end = strpos($xhtml, "\n", $start);
$line = ($end !== FALSE) ? substr($xhtml, $start, $end - ($start - 1)) : substr($xhtml, $start);
$line = ltrim($line); // убираем ведущие пробелы, чтоб не мешали выравнивать
$final_xhtml .=
str_repeat($this->SPACER, $this->OFFSET) .
preg_replace_callback(
$tagpattern, array($this, 'alignXHTMLtags'), $line);
$start = $end + 1;
} while ($end !== FALSE);
// убираем пустые строки
$final_xhtml = preg_replace('/\n\s*(?=\n)/m', '', $final_xhtml);
// возвращаем обратно содержимое <textarea>, <pre> и <script>
$final_xhtml = str_replace("\x01", "\n", $final_xhtml);
$final_xhtml = str_replace("\x02", "<", $final_xhtml);
$final_xhtml = str_replace("\x03", ">", $final_xhtml);
return $final_xhtml;
}
function alignXHTMLtags($matches) {
$tag = $matches[0];
$tagname = $matches[2];
if (in_array($tagname, $this->SKIPTAGS))
return $tag;
$opening = FALSE;
if ($matches[1]) {
$this->OFFSET -= 1;
} // тег является закрывающим
elseif (substr($tag, -2, 1) == '/') {
;
} // тег является одиночным
else {
$opening = TRUE;
} // если тег не является ни одиночным, ни закрывающим, значит, он открывающий
if ($tagname == 'textarea' OR $tagname == 'pre' OR $tagname == 'script') { // эти теги вообще не трогаем, просто перенесем их
// полностью (со всем содержимым) на новую строку
if ($opening) {
$replacement = "\n" . $tag;
}
else
$replacement = $tag . "\n";
}
else {
$replacement = "\n"
. str_repeat($this->SPACER, $this->OFFSET) . $tag . "\n"
. str_repeat($this->SPACER, $this->OFFSET + 1);
}
if ($opening) {
$this->OFFSET += 1;
}
return $replacement;
}
}
?>