Накидал на скорую руку:
function buildTableHeader($iniFileName)
{
$columns = parse_ini_file($iniFileName, true);
$root = new Column('root');
$maxDepth = 0;
foreach ($columns as $name => $cols) {
$columnRoot = new Column($name, $root);
foreach ($cols as $colData) {
$data = explode('|', $colData);
if (count($data) > $maxDepth) {
$maxDepth = count($data);
}
$current = $columnRoot;
foreach ($data as $title) {
if (!$current->hasChild($title)) {
$current = new Column($title, $current);
}
else {
$current = $current->getChild($title);
}
}
}
}
$result = array();
foreach ($root->getChildren() as $columnRoot) {
foreach ($columnRoot->getChildren() as $col) {
$col->walk($result, $maxDepth);
}
}
$str = '';
foreach ($result as $row) {
$str .= "<tr>\n";
foreach ($row as $col) {
$str .= "\t<th";
if ($col['colspan'] > 1) {
$str .= ' colspan="' . $col['colspan'] . '"';
}
if ($col['rowspan'] > 1) {
$str .= ' rowspan="' . $col['rowspan'] . '"';
}
$str .= '>' . $col['title'] . "</th>\n";
}
$str .= "</tr>\n";
}
return $str;
}
class Column
{
/**
* @param string $title
* @param Column $parent
*/
public function __construct($title, Column $parent = NULL)
{
$this->_title = $title;
$this->_parent = $parent;
$this->_children = array();
if ($this->_parent !== NULL) {
$this->_parent->_children[$title] = $this;
}
}
/**
* @return integer
*/
public function getTreeWidth()
{
$width = 0;
foreach ($this->_children as $child) {
$width += $child->getTreeWidth();
}
return $width == 0 ? 1 : $width;
}
/**
* @param string $name
* @return boolean
*/
public function hasChild($name)
{
return isset($this->_children[$name]);
}
/**
* @param string $name
* @return Column
*/
public function getChild($name)
{
return $this->_children[$name];
}
/**
* @return Column[]
*/
public function getChildren()
{
return $this->_children;
}
/**
* @param array $result
* @param integer $maxDepth
* @param integer $depth
*/
public function walk(&$result, $maxDepth, $depth = 0)
{
$result[$depth][] = array('title' => $this->_title, 'colspan' => $this->getTreeWidth(), 'rowspan' => 1);
if (!empty($this->_children)) {
foreach ($this->_children as $child) {
$child->walk($result, $maxDepth, $depth + 1);
}
}
else if ($maxDepth >= $depth) {
$result[$depth][count($result[$depth]) - 1]['rowspan'] = $maxDepth - $depth;
}
}
/**
* @var string
*/
private $_title;
/**
* @var Column[]
*/
private $_children;
/**
* @var Column
*/
private $_parent;
}
$tableHeader = buildTableHeader(__DIR__ . '/test.ini');
?><!doctype html>
<html>
<head>
<title>Test</title>
<style>
table {
border-collapse: collapse;
}
th, td {
border: solid black 1px;
padding: 3px 5px;
}
</style>
</head>
</html>
<table>
<thead>
<?php echo $tableHeader; ?>
</thead>
</table>
Для файла:
[columns1]
row1 = "test|type|kg"
row2 = "test|type|percent"
[columns2]
row1 = "test2|type|some1"
row2 = "test2|type|some2"
row3 = "test2|type|some2|p10"
row4 = "test2|type|some2|p100"
row5 = "test2|type|some3"
[columns3]
row3 = "test3|type"
Выдаёт
<!doctype html>
<html>
<head>
<title>Test</title>
<style>
table {
border-collapse: collapse;
}
th, td {
border: solid black 1px;
padding: 3px 5px;
}
</style>
</head>
</html>
<table>
<thead>
<tr>
<th colspan="2">test</th>
<th colspan="4">test2</th>
<th>test3</th>
</tr>
<tr>
<th colspan="2">type</th>
<th colspan="4">type</th>
<th rowspan="3">type</th>
</tr>
<tr>
<th rowspan="2">kg</th>
<th rowspan="2">percent</th>
<th rowspan="2">some1</th>
<th colspan="2">some2</th>
<th rowspan="2">some3</th>
</tr>
<tr>
<th>p10</th>
<th>p100</th>
</tr>
</thead>
</table>
Только в ini файле нужно имена параметров нужно задавать разными в одной секции
Work, buy, consume, die