If you think this article useful, please make a reply ! Thanks.
Dokuwiki do not support
rowspan for tables, this is a big
PITY! I think most people have or will have been
troubled by this defict.
In this thread, I will introduce a way to modify the original dokuwiki code for version 2009-02-14.
The code have been tested for this version only(See later), if you are using different versions, please check it by yourself ( and reply to this post or email to me
ganxinjiang@gmail.com, thank you :-) ).
Of course, there are some modifications on the internet. But their methods introduce
compatability problems: You probably do not want to change the tables in existing articles! So,
compatability is in consideration when I made the modifications.
The
grammar for rowspan is defined as: if there is a grid in table which only contains special grammar string ( default string is ":::", you can change it! ) after using PHP
trim function, the grid is been merged with the higher level grid. Of course, the rowspan and colspan can be used together.
To all the dokuwiki source article, this is completely compatible! You need nothing to do with the existing ones.
NOTE: It is a must to abide the dokuwiki syntax when making tables! The result will probably be in mess otherwise.
All the changes on dokuwiki happens in the file
$dokuwikiroot/inc/parser/xhtml.php , and only
add code to the two functions, function
table_open and
table_close.
--------------Description in CHINESE---------
不支持表格行合并的Wiki是相当糟糕的,Dokuwiki竟然能没有这样的功能?下面,来看看我是怎么通过修改源代码来达到要求的。在看之前,一定要注意,不能更改其基本语法,否则以前做的表格可能都要重新做一遍了!下面的实现完全考虑了向后兼容,原来的那些表格依然可以正常显示(除非单元格中含有本代码中的指定语法,不过这可能性很小,而且,您还可以更改语法)。
首先是定义语法:本源代码实现的语法是开放的,你可以自己定义。基本思想是将某个单元格的字符串设置为特殊字符串,这个字符串就是所谓的语法(本源码的语法字符串是三个冒号“:::”,嘿嘿,相信您以前的表格中只含有这样字符串的单元格况不会有吧?)。也就是,如果一个单元格的内容是语法字符串,那么这个单元格的内容将被合并到上一行,以此类推。编写表格的注意事项和Dokuwiki的文档说明完全一样。比如,每行应该有相同数量的 | 和 ^ ;这里呢,由于考虑了行合并(rowspan),表格第一行的单元格不能有语法字符串的单元格(这也是非常合理的规定)。
--------------------------------------------
I am sorry that the comments is written in Chinese because of my poor English !!!
1) in funtion
table_open, the code after modifified as follows, only add 1 line.
打开$dokuwikiroot/inc/parser/xhtml.php文件,所有的修改都在这个文件中(修改时只增加不删除代码)。首先,修改table_open函数,增加1行,如下:
function table_open($maxcols = NULL, $numrows = NULL){
// initialize the row counter used for classes
$this->_counter['row_counter'] = 0;
$this->_counter['table_begin_pos'] = strlen($this->doc); // 增加这一行,记住当前表格的位置
$this->doc .= '<table class="inline">'.DOKU_LF;
}
2) in function
table_close, the code after modified as follows, add many lines to the end of original function, and the result is:
然后,修改table_close函数,如下:
function table_close(){
$this->doc .= '</table>'.DOKU_LF;
// 在这里增加很多行,直到本函数的末尾
$table = substr($this->doc, $this->_counter['table_begin_pos']); // 获取当前表格
preg_match('/(<table.*?>)(.*?)<\/table>/ims', $table, $matches, PREG_OFFSET_CAPTURE);
/* 解析旧表 */
$tbody_prefix = $matches[1][0]; //保存表头!
$nrow = preg_match_all('/(<tr.*?>)(.*?)<\/tr>/ims', $matches[2][0], $matches);//分解所有行
$tbody = array('rows_begin' => $matches[1], 'rows_content' => null); //初始化数据
foreach($matches[0] as $i_row => $row) { //解析每一行
preg_match_all('/(<t[d|h].*?>)(.*?)<\/(t[d|h])>/ims', $row, $match_cols); //分解所有列
$cols_attrib = $cols_content = $cols_tag = null;
foreach($match_cols[1] as $i_col => $col) { //解析每一列
preg_match_all('/\s(.*?)="(.*?)"/ims', $col, $match_attribs); //分解列属性
for ($i = 0, $col_attrib = null; $i < count($match_attribs[0]); $i++)//解析列属性
if ($match_attribs[1][$i] == 'colspan'){
$col_attrib[$match_attribs[1][$i]] = (int)$match_attribs[2][$i];
$col_padding = $col_attrib[$match_attribs[1][$i]];// 需填充的列数
}
else
$col_attrib[$match_attribs[1][$i]] = $match_attribs[2][$i];
if (is_null($col_attrib['colspan'])) // 增加colspan=1
$col_attrib['colspan'] = 1;
$col_attrib['rowspan'] = 1; // 原表格中rowspan总是1
$cols_attrib[] = $col_attrib;
$cols_content[] = trim($match_cols[2][$i_col]);
$cols_tag[] = $match_cols[3][$i_col];
while (--$col_padding > 0)
$cols_attrib[] = $cols_content[] = $cols_tag[] = null;
}
$tbody['rows_content']["row${i_row}"] = array(
'attrib' => $cols_attrib,
'content' => $cols_content,
'tag' => $cols_tag);
}
//var_dump($tbody);
/* 修改旧表格 */
foreach($tbody['rows_content'] as $row)
if(count($row['tag']) > $ncol)
$ncol = count($row['tag']);
for($r = $nrow - 1; $r > 0 ; $r--){ // from bottom to up
for ($c = 0; $c < $ncol; $c++){ // from left to right
// 如果这个单元格的内容是:::则进行rowspan
if ($tbody["rows_content"]["row".($r) ]["content"][$c] == ":::"){
$tbody["rows_content"]["row".($r-1)]["attrib"][$c]["rowspan"] =
$tbody["rows_content"]["row".($r) ]["attrib"][$c]["rowspan"] + 1;
// 并将当前单元格设置为null,在重建时忽略该单元格
$tbody["rows_content"]["row".$r]["tag"][$c] = null;
$tbody["rows_content"]["row".$r]["attrib"][$c] = null;
$tbody["rows_content"]["row".$r]["content"][$c] = null;
}
}
}
/* 重建新表格 */
$new_table = "$tbody_prefix\n";
for ($i_row = 0; $i_row < count($tbody["rows_begin"]); $i_row++) { // 构造每一行
$new_table .= $tbody["rows_begin"][$i_row]; // 行的起始标签及其属性
for ($i_col = 0, $cols = $tbody["rows_content"]["row${i_row}"];
$i_col < count($cols['attrib']); $i_col++){ // 构建每一列
if (is_null($cols['tag'][$i_col])) continue; // 忽略空白项
$new_table .= "\n\t<".$cols['tag'][$i_col]; // 列的起始标签开始
foreach($cols['attrib'][$i_col] as $attrib => $value) // 列的属性
$new_table .= " $attrib=\"$value\"";
$new_table .= ">"; // 列的起始标签结束
$new_table .= $cols['content'][$i_col]; // 增加列的内容
$new_table .= "</".$cols['tag'][$i_col].">"; // 列的结束标签
}
$new_table .= "\n</tr>\n"; // 行的结束标签
}
$new_table .= "</table>";
//var_dump($new_table);
/* 替换旧表 */
$this->doc = substr($this->doc, 0, $this->_counter['table_begin_pos']).$new_table;
}
Now lets test it(the first line is handled by plugin
tablewidth):
|< 100% - >|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 89 || ab ||
| 12 || 3 | 4 | 5 | 6 | 7 | ::: || ::: ||
| ::: || 3 | 4 5 6 7 |||| ::: || a | b |
| 1234 |||| 5 ^ 6789 |||| a | b |
| 1 | 2 | 3 | 4 | 5 | ::: |||| a | b |
| 1 | 2 | 3 | 4 | 5 | ::: |||| a | b |
| 1 | 2 | 3 | 45 || ::: |||| a | b |
| 123 ||| ::: || 6 | 7 | 8 | 9 | ab ||
| ::: ||| ::: || 6 | 7 | 8 | 9 | ::: ||
| ::: ||| 4 5 6 7 |||| 8 | 9 | ::: ||
result is :