Пришла подобная задачка... Сегодня четверг - много печатать мне лень, поэтому сразу к делу.
Класс для постороения "матрицы":
<?php Class HTML_Table_Object { /* * Строки */ private $_trs; /* * Конструктор, на вход принимаем html таблички */ public function __construct($html = '') { $this->parse($html); } /* * Парсим табличку */ public function parse($html) { if(preg_match_all('~<tr[^>]*>.*?</tr>~is', $html, $trs)) { foreach($trs[0] as $i => $tr) { $this->_trs[] = new HTML_Table_Object_Tr($tr, $this, $i); } } foreach($this->_trs as $tr) { $tr->parse(); } } /* * Получить конкретную строку */ public function getTrAt($index = 0) { return $this->_trs[$index]; } /* * Схематичный вид полученной матрицы */ public function schematic() { $html = "<table border='1'>"; foreach($this->_trs as $tr) { $html .= $tr->schematic(); } return $html .= "</table>"; } /* * Пустая ли колонка */ public function isColumnEmpty($i) { foreach($this->_trs as $tr) { if(is_object($tr->getTdAt($i))) { if(!$tr->getTdAt($i)->isEmpty()) { return false; } } } return true; } /* * Удалить колонку */ public function deleteColumn($i) { foreach($this->_trs as $tr) { $tr->deleteTdAt($i); } } /* * Построить таблицу */ public function build() { foreach($this->_trs as $tr) { $tr->merge(); } $html = "<table border='1'>"; foreach($this->_trs as $tr) { $html .= $tr->build(); } return $html .= "</table>"; } } ?>
Класс "строка матрицы":
<?php Class HTML_Table_Object_Tr { /* * Ячейки */ private $_tds; /* * Исходный html */ private $_html = ''; /* * ссылка на таблицу */ private $_table; /* * порядковый номер строки в таблице */ private $_index = 0; /* * Конструктор, на вход принимает html trки, ссылку на таблицу и порядковый номер */ public function __construct($html = '', $table = null, $index = 0) { $this->_html = $html; $this->_table = $table; $this->_index = $index; } /* * Забрать ячейку */ public function getTdAt($i = 0) { return $this->_tds[$i]; } /* * Получить следующую tr */ public function getTable() { return $this->_table; } /* * Получить индекс */ public function getIndex() { return $this->_index; } /* * Ибираем алиасы */ public function merge() { foreach($this->_tds as $i => $td) { if($td instanceof HTML_Table_Object_Td_Alias) { // если у нас остался алиас - подменяем его на реальную ячейку if($td->getTd()->deleted) { $this->_tds[$i] = $td->getTd(); $this->_tds[$i]->deleted = false; continue; } if($td->getTd()->getTrIndex() == $this->getIndex()) { $td->getTd()->colspan++; } else { if($td->getTd()->getIndex() == $td->getIndex()) { $td->getTd()->rowspan++; } } unset($this->_tds[$i]); } } } /* * Разобрать строку */ public function parse() { if(preg_match_all('~<td[^>]*>.*?</td>~is', $this->_html, $tds)) { foreach($tds[0] as $i => $td) { $index = $this->getFirstEmptyIndexGE($i); // резервируем место (так как HTML_Table_Object_Td может добавить в эту строку алиасы на себя) $this->_tds[$index] = null; // добавляем на указанное место $this->_tds[$index] = new HTML_Table_Object_Td($td, $this, $index); } } ksort($this->_tds); } /* * Получить первый свободный индекс ячейки, больший или равный указанному */ public function getFirstEmptyIndexGE($i = 0) { if(!isset($this->_tds[$i])) { return $i; } else { while(true) { $i++; if(!isset($this->_tds[$i])) { return $i; } } } } /* * Добавить ячейку в строку */ public function pushTd($td = null) { $this->_tds[$td->getIndex()] = $td; } /* * Удалить ячейку */ public function deleteTdAt($i = null) { if($i !== null) { $this->_tds[$i]->deleted = true; unset($this->_tds[$i]); $this->_tds = array_values($this->_tds); } } /* * Количество ячеек в строке */ public function getTdsCount() { return count($this->_tds); } /* * Схематичный вид полученной матрицы */ public function schematic() { $html = "<tr>"; foreach($this->_tds as $td) { if(is_object($td)) { $html .= $td->schematic(); } } return $html .= "</tr>"; } /* * Построить строку */ public function build() { $html = "<tr>"; foreach($this->_tds as $td) { $html .= $td->build(); } return $html .= "</tr>"; } } ?>
Класс "ячейка матрицы":
<?php Class HTML_Table_Object_Td { /* * Порядковый номер ячейки */ private $_index; /* * Ячейка */ private $_tr; /* * Колспан */ public $colspan = 1; /* * Роуспан */ public $rowspan = 1; /* * Флаг о том, что ячейка была удалена */ public $deleted = false; /* * Контент ячейки */ private $_content = ''; /* * Конструктор, на вход принимает html tdшки, ссылка на tr и порядковый номер */ public function __construct($html = '', $tr = null, $index = 0) { $this->_tr = $tr; $this->_index = $index; $this->parse($html); } /* * Пустая ли ячейка */ public function isEmpty() { return $this->_content == ''; } /* * Получить инстанс таблицы */ public function getTable() { return $this->_tr->getTable(); } /* * Получить индекс */ public function getIndex() { return $this->_index; } /* * Получить индекс ячейки */ public function getTrIndex() { return $this->_tr->getIndex(); } /* * Разобрать данные ячейки */ public function parse($html = '') { if(preg_match('~<td([^>]*)>(.*?)</td>~is', $html, $matches)) { $attributes = $matches[1]; $this->_content = trim(str_replace(array(' '), array(''), $matches[2])); $colspan = 1; $rowspan = 1; if(preg_match_all('~(colspan|rowspan)=([0-9]+)~', str_replace(array("'", '"'), array('', ''), mb_strtolower($attributes, 'utf-8')), $matches)) { foreach($matches[1] as $i => $match) { if($match == 'colspan') { $colspan = $matches[2][$i]; } if($match == 'rowspan') { $rowspan = $matches[2][$i]; } } } for($i = 0; $i < $colspan; $i++) { for($j = 0; $j < $rowspan; $j++) { if(!($i ==0 && $j == 0)) { $tr = $this->getTable()->getTrAt($this->getTrIndex() + $j); $tdIndex = $tr->getFirstEmptyIndexGE($this->getIndex() + $i); $tr->pushTd(new HTML_Table_Object_Td_Alias($this, $tdIndex)); } } } } } /* * Схематичный вид полученной матрицы */ public function schematic() { return "<td>" . $this->getTrIndex() . "-" . $this->getIndex() . "</td>"; } /* * Построить строку */ public function build() { return "<td" . ($this->colspan > 1 ? (' colspan="' .$this->colspan. '"') : '') . "" . ($this->rowspan > 1 ? (' rowspan="' .$this->rowspan. '"') : '') . ">" . $this->_content . "</td>"; } } ?>
Класс "алиас на ячейку матрицы" (нужен для обработки colspan и rowspan):
<?php Class HTML_Table_Object_Td_Alias { /* * Ячейка, на которую ссылаемся */ private $_td; /* * Псевдоиндекс */ private $_index = 0; /* * Конструктор, на вход принимаем ячейку, на которую мы ссылаемся */ public function __construct($td = null, $index = 0) { $this->_td = $td; $this->_index = $index; } /* * Ячейка */ public function getTd() { return $this->_td; } /* * Псевдоиндекс */ public function getIndex() { return $this->_index; } /* * Алиас всегда считается пустым */ public function isEmpty() { return true; } /* * Схематичный вид полученной матрицы */ public function schematic() { return "<td>" . $this->_td->getTrIndex() . "-" . $this->_td->getIndex() . "+</td>"; } } ?>
Собственно как-то так... Кормим скрипту подобную табличку:
Cell | |||
Cell | |||
Cell | |||
Cell |
Серым цветом отмечена колонка, которую надо удалить.
<?php $table = new HTML_Table_Object($table); ?>
Выведем получившуюся матрицу:
<?php print $table->schematic(); ?>
0-0 | 0-0+ | 0-2 | 0-3 |
0-0+ | 0-0+ | 1-2 | 1-2+ |
2-0 | 2-1 | 2-2 | 2-3 |
3-0 | 3-1 | 3-2 | 3-3 |
Плюсами отмечены алиасы на ячейку (ведь ячейка с колспанами и роуспанами - все равно это ОДНА ячейка).
Ну и далее чистим табличку от пустых колонок:
<?php for($i=$table->getTrAt(0)->getTdsCount()-1; $i>=0; $i--) { if($table->isColumnEmpty($i)) { $table->deleteColumn($i); } } print $table->schematic(); print $table->build(); ?>
Результат:
0-0 | 0-2 | 0-3 |
0-0+ | 1-2 | 1-2+ |
2-0 | 2-2 | 2-3 |
3-0 | 3-2 | 3-3 |
Cell | ||
Cell | ||
Cell | ||
Cell |
В общем то ровно то, что я и хотел получить.
Скрипт не идеальный, но, вроде бы, работает. Найдете баги - пишите